From 7b1bdc21a4ba5eb5d36d32afeffde7055c26f88b Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Thu, 12 Aug 2021 16:37:53 +0300 Subject: [PATCH 001/174] Copy DerivativeStructure to multiplatform --- README.md | 2 +- docs/templates/README-TEMPLATE.md | 2 +- .../kscience/kmath/expressions/DSCompiler.kt | 1541 +++++++++++++++++ .../kmath/expressions/DerivativeStructure.kt | 186 ++ .../DerivativeStructureExpression.kt | 332 ++++ .../DerivativeStructureExpressionTest.kt | 59 + .../kscience/kmath/internal/InternalUtils.kt | 3 +- 7 files changed, 2122 insertions(+), 3 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt diff --git a/README.md b/README.md index 92260716e..aeedfefbb 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ module definitions below. The module stability could have the following levels: * **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. * **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked - with `@UnstableKmathAPI` or other stability warning annotations. + with `@UnstableKMathAPI` or other stability warning annotations. * **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index b0c418697..2e64a3e09 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -44,7 +44,7 @@ module definitions below. The module stability could have the following levels: * **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. * **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked - with `@UnstableKmathAPI` or other stability warning annotations. + with `@UnstableKMathAPI` or other stability warning annotations. * **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt new file mode 100644 index 000000000..bb88ce52c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt @@ -0,0 +1,1541 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.expressions + +import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.MutableBufferFactory +import kotlin.math.max +import kotlin.math.min + +internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: Int = size) { + for (i in fromIndex until toIndex) this[i] = element +} + +/** + * Class holding "compiled" computation rules for derivative structures. + * + * This class implements the computation rules described in Dan Kalman's paper + * [Doubly Recursive Multivariate Automatic Differentiation](http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf), + * Mathematics Magazine, vol. 75, no. 3, June 2002. However, to avoid performances bottlenecks, the recursive rules are + * "compiled" once in an unfolded form. This class does this recursion unrolling and stores the computation rules as + * simple loops with pre-computed indirection arrays. + * + * This class maps all derivative computation into single dimension arrays that hold the value and partial derivatives. + * The class does not hold these arrays, which remains under the responsibility of the caller. For each combination of + * number of free parameters and derivation order, only one compiler is necessary, and this compiler will be used to + * perform computations on all arrays provided to it, which can represent hundreds or thousands of different parameters + * kept together with all their partial derivatives. + * + * The arrays on which compilers operate contain only the partial derivatives together with the 0th + * derivative, i.e., the value. The partial derivatives are stored in a compiler-specific order, which can be retrieved + * using methods [getPartialDerivativeIndex] and [getPartialDerivativeOrders]. The value is guaranteed to be stored as + * the first element (i.e., the [getPartialDerivativeIndex] method returns 0 when called with 0 for all derivation + * orders and [getPartialDerivativeOrders] returns an array filled with 0 when called with 0 as the index). + * + * Note that the ordering changes with number of parameters and derivation order. For example given 2 parameters x and + * y, df/dy is stored at index 2 when derivation order is set to 1 (in this case the array has three elements: f, + * df/dx and df/dy). If derivation order is set to 2, then df/dy will be stored at index 3 (in this case the array has + * six elements: f, df/dx, df/dxdx, df/dy, df/dxdy and df/dydy). + * + * Given this structure, users can perform some simple operations like adding, subtracting or multiplying constants and + * negating the elements by themselves, knowing if they want to mutate their array or create a new array. These simple + * operations are not provided by the compiler. The compiler provides only the more complex operations between several + * arrays. + * + * Derived from + * [Commons Math's `DSCompiler`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DSCompiler.java). + * + * @property freeParameters Number of free parameters. + * @property order Derivation order. + * @see DerivativeStructure + */ +internal class DSCompiler> internal constructor( + val algebra: A, + val bufferFactory: MutableBufferFactory, + val freeParameters: Int, + val order: Int, + valueCompiler: DSCompiler?, + derivativeCompiler: DSCompiler?, +) { + /** + * Number of partial derivatives (including the single 0 order derivative element). + */ + val sizes: Array by lazy { + compileSizes( + freeParameters, + order, + valueCompiler, + ) + } + + /** + * Indirection array for partial derivatives. + */ + val derivativesIndirection: Array by lazy { + compileDerivativesIndirection( + freeParameters, order, + valueCompiler, derivativeCompiler, + ) + } + + /** + * Indirection array of the lower derivative elements. + */ + val lowerIndirection: IntArray by lazy { + compileLowerIndirection( + freeParameters, order, + valueCompiler, derivativeCompiler, + ) + } + + /** + * Indirection arrays for multiplication. + */ + val multIndirection: Array> by lazy { + compileMultiplicationIndirection( + freeParameters, order, + valueCompiler, derivativeCompiler, lowerIndirection, + ) + } + + /** + * Indirection arrays for function composition. + */ + val compositionIndirection: Array> by lazy { + compileCompositionIndirection( + freeParameters, order, + valueCompiler, derivativeCompiler, + sizes, derivativesIndirection, + ) + } + + /** + * Get the array size required for holding partial derivatives' data. + * + * This number includes the single 0 order derivative element, which is + * guaranteed to be stored in the first element of the array. + */ + val size: Int + get() = sizes[freeParameters][order] + + /** + * Get the index of a partial derivative in the array. + * + * If all orders are set to 0, then the 0th order derivative is returned, which is the value of the + * function. + * + * The indices of derivatives are between 0 and [size] − 1. Their specific order is fixed for a given compiler, but + * otherwise not publicly specified. There are however some simple cases which have guaranteed indices: + * + * * the index of 0th order derivative is always 0 + * * if there is only 1 [freeParameters], then the + * derivatives are sorted in increasing derivation order (i.e., f at index 0, df/dp + * at index 1, d2f/dp2 at index 2 … + * dkf/dpk at index k), + * * if the [order] is 1, then the derivatives + * are sorted in increasing free parameter order (i.e., f at index 0, df/dx1 + * at index 1, df/dx2 at index 2 … df/dxk at index k), + * * all other cases are not publicly specified. + * + * This method is the inverse of method [getPartialDerivativeOrders]. + * + * @param orders derivation orders with respect to each parameter. + * @return index of the partial derivative. + * @see getPartialDerivativeOrders + */ + fun getPartialDerivativeIndex(vararg orders: Int): Int { + // safety check + require(orders.size == freeParameters) { "dimension mismatch: ${orders.size} and $freeParameters" } + return getPartialDerivativeIndex(freeParameters, order, sizes, *orders) + } + + /** + * Get the derivation orders for a specific index in the array. + * + * This method is the inverse of [getPartialDerivativeIndex]. + * + * @param index of the partial derivative + * @return orders derivation orders with respect to each parameter + * @see getPartialDerivativeIndex + */ + fun getPartialDerivativeOrders(index: Int): IntArray = derivativesIndirection[index] +} + +/** + * Compute natural logarithm of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for logarithm the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.ln( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : ExponentialOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + function[0] = ln(operand[operandOffset]) + + if (order > 0) { + val inv = one / operand[operandOffset] + var xk = inv + for (i in 1..order) { + function[i] = xk + xk *= (-i * inv) + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute integer power of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param n power to apply. + * @param result array where result must be stored (for power the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.pow( + operand: Buffer, + operandOffset: Int, + n: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : PowerOperations = algebra { + if (n == 0) { + // special case, x^0 = 1 for all x + result[resultOffset] = one + result.fill(zero, resultOffset + 1, resultOffset + size) + return + } + + // create the power function value and derivatives + // [x^n, nx^(n-1), n(n-1)x^(n-2), ... ] + val function = bufferFactory(1 + order) { zero } + + if (n > 0) { + // strictly positive power + val maxOrder: Int = min(order, n) + var xk = operand[operandOffset] pow n - maxOrder + for (i in maxOrder downTo 1) { + function[i] = xk + xk *= operand[operandOffset] + } + function[0] = xk + } else { + // strictly negative power + val inv = one / operand[operandOffset] + var xk = inv pow -n + + for (i in 0..order) { + function[i] = xk + xk *= inv + } + } + + var coefficient = number(n) + + for (i in 1..order) { + function[i] = function[i] * coefficient + coefficient *= (n - i).toDouble() + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute exponential of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for exponential the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.exp( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Ring, A : ScaleOperations, A : ExponentialOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + function.fill(exp(operand[operandOffset])) + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute square root of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for nth root the result array *cannot* be the input + * array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.sqrt( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : PowerOperations = algebra { + // create the function value and derivatives + // [x^(1/n), (1/n)x^((1/n)-1), (1-n)/n^2x^((1/n)-2), ... ] + val function = bufferFactory(1 + order) { zero } + function[0] = sqrt(operand[operandOffset]) + var xk: T = 0.5 * one / function[0] + val xReciprocal = one / operand[operandOffset] + + for (i in 1..order) { + function[i] = xk + xk *= xReciprocal * (0.5 - i) + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute cosine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for cosine the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.cos( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) where A : Ring, A : TrigonometricOperations, A : ScaleOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + function[0] = cos(operand[operandOffset]) + + if (order > 0) { + function[1] = -sin(operand[operandOffset]) + for (i in 2..order) { + function[i] = -function[i - 2] + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute power of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param p power to apply. + * @param result array where result must be stored (for power the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.pow( + operand: Buffer, + operandOffset: Int, + p: Double, + result: MutableBuffer, + resultOffset: Int +) where A : Ring, A : NumericAlgebra, A : PowerOperations, A : ScaleOperations = algebra { + // create the function value and derivatives + // [x^p, px^(p-1), p(p-1)x^(p-2), ... ] + val function = bufferFactory(1 + order) { zero } + var xk = operand[operandOffset] pow p - order + + for (i in order downTo 1) { + function[i] = xk + xk *= operand[operandOffset] + } + + function[0] = xk + var coefficient = p + + for (i in 1..order) { + function[i] = function[i] * coefficient + coefficient *= p - i + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute tangent of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for tangent the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.tan( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Ring, A : TrigonometricOperations, A : ScaleOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val t = tan(operand[operandOffset]) + function[0] = t + + if (order > 0) { + + // the nth order derivative of tan has the form: + // dn(tan(x)/dxn = P_n(tan(x)) + // where P_n(t) is a degree n+1 polynomial with same parity as n+1 + // P_0(t) = t, P_1(t) = 1 + t^2, P_2(t) = 2 t (1 + t^2) ... + // the general recurrence relation for P_n is: + // P_n(x) = (1+t^2) P_(n-1)'(t) + // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array + val p = bufferFactory(order + 2) { zero } + p[1] = one + val t2 = t * t + for (n in 1..order) { + + // update and evaluate polynomial P_n(t) + var v = one + p[n + 1] = n * p[n] + var k = n + 1 + while (k >= 0) { + v = v * t2 + p[k] + if (k > 2) { + p[k - 2] = (k - 1) * p[k - 1] + (k - 3) * p[k - 3] + } else if (k == 2) { + p[0] = p[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= t + } + function[n] = v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute power of a derivative structure. + * + * @param x array holding the base. + * @param xOffset offset of the base in its array. + * @param y array holding the exponent. + * @param yOffset offset of the exponent in its array. + * @param result array where result must be stored (for power the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.pow( + x: Buffer, + xOffset: Int, + y: Buffer, + yOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) where A : Field, A : ExponentialOperations = algebra { + val logX = bufferFactory(size) { zero } + ln(x, xOffset, logX, 0) + val yLogX = bufferFactory(size) { zero } + multiply(logX, 0, y, yOffset, yLogX, 0) + exp(yLogX, 0, result, resultOffset) +} + +/** + * Compute sine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for sine the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.sin( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Ring, A : ScaleOperations, A : TrigonometricOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + function[0] = sin(operand[operandOffset]) + if (order > 0) { + function[1] = cos(operand[operandOffset]) + for (i in 2..order) { + function[i] = -function[i - 2] + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute arc cosine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for arc cosine the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.acos( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : TrigonometricOperations, A : PowerOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val x = operand[operandOffset] + function[0] = acos(x) + if (order > 0) { + // the nth order derivative of acos has the form: + // dn(acos(x)/dxn = P_n(x) / [1 - x^2]^((2n-1)/2) + // where P_n(x) is a degree n-1 polynomial with same parity as n-1 + // P_1(x) = -1, P_2(x) = -x, P_3(x) = -2x^2 - 1 ... + // the general recurrence relation for P_n is: + // P_n(x) = (1-x^2) P_(n-1)'(x) + (2n-3) x P_(n-1)(x) + // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array + val p = bufferFactory(order) { zero } + p[0] = -one + val x2 = x * x + val f = one / (one - x2) + var coeff = sqrt(f) + function[1] = coeff * p[0] + + for (n in 2..order) { + // update and evaluate polynomial P_n(x) + var v = zero + p[n - 1] = (n - 1) * p[n - 2] + var k = n - 1 + + while (k >= 0) { + v = v * x2 + p[k] + if (k > 2) { + p[k - 2] = (k - 1) * p[k - 1] + (2 * n - k) * p[k - 3] + } else if (k == 2) { + p[0] = p[1] + } + k -= 2 + } + + if (n and 0x1 == 0) { + v *= x + } + + coeff *= f + function[n] = coeff * v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute arc sine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for arc sine the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.asin( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : TrigonometricOperations, A : PowerOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val x = operand[operandOffset] + function[0] = asin(x) + if (order > 0) { + // the nth order derivative of asin has the form: + // dn(asin(x)/dxn = P_n(x) / [1 - x^2]^((2n-1)/2) + // where P_n(x) is a degree n-1 polynomial with same parity as n-1 + // P_1(x) = 1, P_2(x) = x, P_3(x) = 2x^2 + 1 ... + // the general recurrence relation for P_n is: + // P_n(x) = (1-x^2) P_(n-1)'(x) + (2n-3) x P_(n-1)(x) + // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array + val p = bufferFactory(order) { zero } + p[0] = one + val x2 = x * x + val f = one / (one - x2) + var coeff = sqrt(f) + function[1] = coeff * p[0] + for (n in 2..order) { + + // update and evaluate polynomial P_n(x) + var v = zero + p[n - 1] = (n - 1) * p[n - 2] + var k = n - 1 + while (k >= 0) { + v = v * x2 + p[k] + if (k > 2) { + p[k - 2] = (k - 1) * p[k - 1] + (2 * n - k) * p[k - 3] + } else if (k == 2) { + p[0] = p[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= x + } + coeff *= f + function[n] = coeff * v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute arc tangent of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for arc tangent the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.atan( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : TrigonometricOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val x = operand[operandOffset] + function[0] = atan(x) + + if (order > 0) { + // the nth order derivative of atan has the form: + // dn(atan(x)/dxn = Q_n(x) / (1 + x^2)^n + // where Q_n(x) is a degree n-1 polynomial with same parity as n-1 + // Q_1(x) = 1, Q_2(x) = -2x, Q_3(x) = 6x^2 - 2 ... + // the general recurrence relation for Q_n is: + // Q_n(x) = (1+x^2) Q_(n-1)'(x) - 2(n-1) x Q_(n-1)(x) + // as per polynomial parity, we can store coefficients of both Q_(n-1) and Q_n in the same array + val q = bufferFactory(order) { zero } + q[0] = one + val x2 = x * x + val f = one / (one + x2) + var coeff = f + function[1] = coeff * q[0] + for (n in 2..order) { + + // update and evaluate polynomial Q_n(x) + var v = zero + q[n - 1] = -n * q[n - 2] + var k = n - 1 + while (k >= 0) { + v = v * x2 + q[k] + if (k > 2) { + q[k - 2] = (k - 1) * q[k - 1] + (k - 1 - 2 * n) * q[k - 3] + } else if (k == 2) { + q[0] = q[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= x + } + coeff *= f + function[n] = coeff * v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute hyperbolic cosine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for hyperbolic cosine the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.cosh( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Ring, A : ScaleOperations, A : ExponentialOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + function[0] = cosh(operand[operandOffset]) + + if (order > 0) { + function[1] = sinh(operand[operandOffset]) + for (i in 2..order) { + function[i] = function[i - 2] + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute hyperbolic tangent of a derivative structure. + * + * @param operand array holding the operand + * @param operandOffset offset of the operand in its array + * @param result array where result must be stored (for hyperbolic tangent the result array *cannot* be the input + * array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.tanh( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : ExponentialOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val t = tanh(operand[operandOffset]) + function[0] = t + if (order > 0) { + + // the nth order derivative of tanh has the form: + // dn(tanh(x)/dxn = P_n(tanh(x)) + // where P_n(t) is a degree n+1 polynomial with same parity as n+1 + // P_0(t) = t, P_1(t) = 1 - t^2, P_2(t) = -2 t (1 - t^2) ... + // the general recurrence relation for P_n is: + // P_n(x) = (1-t^2) P_(n-1)'(t) + // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array + val p = bufferFactory(order + 2) { zero } + p[1] = one + val t2 = t * t + for (n in 1..order) { + + // update and evaluate polynomial P_n(t) + var v = zero + p[n + 1] = -n * p[n] + var k = n + 1 + while (k >= 0) { + v = v * t2 + p[k] + if (k > 2) { + p[k - 2] = (k - 1) * p[k - 1] - (k - 3) * p[k - 3] + } else if (k == 2) { + p[0] = p[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= t + } + function[n] = v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute inverse hyperbolic cosine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for inverse hyperbolic cosine the result array *cannot* be the input + * array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.acosh( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : ExponentialOperations, A : PowerOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val x = operand[operandOffset] + function[0] = acosh(x) + + if (order > 0) { + // the nth order derivative of acosh has the form: + // dn(acosh(x)/dxn = P_n(x) / [x^2 - 1]^((2n-1)/2) + // where P_n(x) is a degree n-1 polynomial with same parity as n-1 + // P_1(x) = 1, P_2(x) = -x, P_3(x) = 2x^2 + 1 ... + // the general recurrence relation for P_n is: + // P_n(x) = (x^2-1) P_(n-1)'(x) - (2n-3) x P_(n-1)(x) + // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array + val p = bufferFactory(order) { zero } + p[0] = one + val x2 = x * x + val f = one / (x2 - one) + var coeff = sqrt(f) + function[1] = coeff * p[0] + for (n in 2..order) { + + // update and evaluate polynomial P_n(x) + var v = zero + p[n - 1] = (1 - n) * p[n - 2] + var k = n - 1 + while (k >= 0) { + v = v * x2 + p[k] + if (k > 2) { + p[k - 2] = (1 - k) * p[k - 1] + (k - 2 * n) * p[k - 3] + } else if (k == 2) { + p[0] = -p[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= x + } + + coeff *= f + function[n] = coeff * v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Compute composition of a derivative structure by a function. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param f array of value and derivatives of the function at the current point (i.e. at `operand[operandOffset]`). + * @param result array where result must be stored (for composition the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.compose( + operand: Buffer, + operandOffset: Int, + f: Buffer, + result: MutableBuffer, + resultOffset: Int, +) where A : Ring, A : ScaleOperations = algebra { + for (i in compositionIndirection.indices) { + val mappingI = compositionIndirection[i] + var r = zero + for (j in mappingI.indices) { + val mappingIJ = mappingI[j] + var product = mappingIJ[0] * f[mappingIJ[1]] + for (k in 2 until mappingIJ.size) { + product *= operand[operandOffset + mappingIJ[k]] + } + r += product + } + result[resultOffset + i] = r + } +} + +/** + * Compute hyperbolic sine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for hyperbolic sine the result array *cannot* be the input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.sinh( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : ExponentialOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + function[0] = sinh(operand[operandOffset]) + + if (order > 0) { + function[1] = cosh(operand[operandOffset]) + for (i in 2..order) { + function[i] = function[i - 2] + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Perform division of two derivative structures. + * + * @param lhs array holding left-hand side of division. + * @param lhsOffset offset of the left-hand side in its array. + * @param rhs array right-hand side of division. + * @param rhsOffset offset of the right-hand side in its array. + * @param result array where result must be stored (for division the result array *cannot* be one of the input arrays). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.divide( + lhs: Buffer, + lhsOffset: Int, + rhs: Buffer, + rhsOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) where A : Field, A : PowerOperations, A : ScaleOperations = algebra { + val reciprocal = bufferFactory(size) { zero } + pow(rhs, lhsOffset, -1, reciprocal, 0) + multiply(lhs, lhsOffset, reciprocal, rhsOffset, result, resultOffset) +} + +/** + * Perform multiplication of two derivative structures. + * + * @param lhs array holding left-hand side of multiplication. + * @param lhsOffset offset of the left-hand side in its array. + * @param rhs array right-hand side of multiplication. + * @param rhsOffset offset of the right-hand side in its array. + * @param result array where result must be stored (for multiplication the result array *cannot* be one of the input + * arrays). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.multiply( + lhs: Buffer, + lhsOffset: Int, + rhs: Buffer, + rhsOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) where A : Ring, A : ScaleOperations = algebra { + for (i in multIndirection.indices) { + val mappingI = multIndirection[i] + var r = zero + + for (j in mappingI.indices) { + r += mappingI[j][0] * lhs[lhsOffset + mappingI[j][1]] * rhs[rhsOffset + mappingI[j][2]] + } + + result[resultOffset + i] = r + } +} + +/** + * Perform subtraction of two derivative structures. + * + * @param lhs array holding left-hand side of subtraction. + * @param lhsOffset offset of the left-hand side in its array. + * @param rhs array right-hand side of subtraction. + * @param rhsOffset offset of the right-hand side in its array. + * @param result array where result must be stored (it may be one of the input arrays). + * @param resultOffset offset of the result in its array. + */ +internal fun > DSCompiler.subtract( + lhs: Buffer, + lhsOffset: Int, + rhs: Buffer, + rhsOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) = algebra { + for (i in 0 until size) { + result[resultOffset + i] = lhs[lhsOffset + i] - rhs[rhsOffset + i] + } +} + +/** + * Compute inverse hyperbolic sine of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for inverse hyperbolic sine the result array *cannot* be the input + * array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.asinh( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int +) where A : Field, A : ExponentialOperations, A : PowerOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val x = operand[operandOffset] + function[0] = asinh(x) + if (order > 0) { + // the nth order derivative of asinh has the form: + // dn(asinh(x)/dxn = P_n(x) / [x^2 + 1]^((2n-1)/2) + // where P_n(x) is a degree n-1 polynomial with same parity as n-1 + // P_1(x) = 1, P_2(x) = -x, P_3(x) = 2x^2 - 1 ... + // the general recurrence relation for P_n is: + // P_n(x) = (x^2+1) P_(n-1)'(x) - (2n-3) x P_(n-1)(x) + // as per polynomial parity, we can store coefficients of both P_(n-1) and P_n in the same array + val p = bufferFactory(order) { zero } + p[0] = one + val x2 = x * x + val f = one / (one + x2) + var coeff = sqrt(f) + function[1] = coeff * p[0] + for (n in 2..order) { + + // update and evaluate polynomial P_n(x) + var v = zero + p[n - 1] = (1 - n) * p[n - 2] + var k = n - 1 + while (k >= 0) { + v = v * x2 + p[k] + if (k > 2) { + p[k - 2] = (k - 1) * p[k - 1] + (k - 2 * n) * p[k - 3] + } else if (k == 2) { + p[0] = p[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= x + } + coeff *= f + function[n] = coeff * v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Perform addition of two derivative structures. + * + * @param lhs array holding left-hand side of addition. + * @param lhsOffset offset of the left-hand side in its array. + * @param rhs array right-hand side of addition. + * @param rhsOffset offset of the right-hand side in its array. + * @param result array where result must be stored (it may be one of the input arrays). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.add( + lhs: Buffer, + lhsOffset: Int, + rhs: Buffer, + rhsOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) where A : Group = algebra { + for (i in 0 until size) { + result[resultOffset + i] = lhs[lhsOffset + i] + rhs[rhsOffset + i] + } +} + +/** + * Check rules set compatibility. + * + * @param compiler other compiler to check against instance. + */ +internal fun > DSCompiler.checkCompatibility(compiler: DSCompiler) { + require(freeParameters == compiler.freeParameters) { + "dimension mismatch: $freeParameters and ${compiler.freeParameters}" + } + require(order == compiler.order) { + "dimension mismatch: $order and ${compiler.order}" + } +} + +/** + * Compute inverse hyperbolic tangent of a derivative structure. + * + * @param operand array holding the operand. + * @param operandOffset offset of the operand in its array. + * @param result array where result must be stored (for inverse hyperbolic tangent the result array *cannot* be the + * input array). + * @param resultOffset offset of the result in its array. + */ +internal fun DSCompiler.atanh( + operand: Buffer, + operandOffset: Int, + result: MutableBuffer, + resultOffset: Int, +) where A : Field, A : ExponentialOperations = algebra { + // create the function value and derivatives + val function = bufferFactory(1 + order) { zero } + val x = operand[operandOffset] + function[0] = atanh(x) + + if (order > 0) { + // the nth order derivative of atanh has the form: + // dn(atanh(x)/dxn = Q_n(x) / (1 - x^2)^n + // where Q_n(x) is a degree n-1 polynomial with same parity as n-1 + // Q_1(x) = 1, Q_2(x) = 2x, Q_3(x) = 6x^2 + 2 ... + // the general recurrence relation for Q_n is: + // Q_n(x) = (1-x^2) Q_(n-1)'(x) + 2(n-1) x Q_(n-1)(x) + // as per polynomial parity, we can store coefficients of both Q_(n-1) and Q_n in the same array + val q = bufferFactory(order) { zero } + q[0] = one + val x2 = x * x + val f = one / (one - x2) + var coeff = f + function[1] = coeff * q[0] + for (n in 2..order) { + + // update and evaluate polynomial Q_n(x) + var v = zero + q[n - 1] = n * q[n - 2] + var k = n - 1 + while (k >= 0) { + v = v * x2 + q[k] + if (k > 2) { + q[k - 2] = (k - 1) * q[k - 1] + (2 * n - k + 1) * q[k - 3] + } else if (k == 2) { + q[0] = q[1] + } + k -= 2 + } + if (n and 0x1 == 0) { + v *= x + } + coeff *= f + function[n] = coeff * v + } + } + + // apply function composition + compose(operand, operandOffset, function, result, resultOffset) +} + +/** + * Get the compiler for number of free parameters and order. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @return cached rules set. + */ +internal fun > getCompiler( + algebra: A, + bufferFactory: MutableBufferFactory, + parameters: Int, + order: Int +): DSCompiler { + // get the cached compilers + val cache: Array?>>? = null + + // we need to create more compilers + val maxParameters: Int = max(parameters, cache?.size ?: 0) + val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) + val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } + + if (cache != null) { + // preserve the already created compilers + for (i in cache.indices) { + cache[i].copyInto(newCache[i], endIndex = cache[i].size) + } + } + + // create the array in increasing diagonal order + + // create the array in increasing diagonal order + for (diag in 0..parameters + order) { + for (o in max(0, diag - parameters)..min(order, diag)) { + val p: Int = diag - o + if (newCache[p][o] == null) { + val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! + val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! + + newCache[p][o] = DSCompiler( + algebra, + bufferFactory, + p, + o, + valueCompiler, + derivativeCompiler, + ) + } + } + } + + return newCache[parameters][order]!! +} + +/** + * Compile the sizes array. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param valueCompiler compiler for the value part. + * @return sizes array. + */ +private fun > compileSizes( + parameters: Int, order: Int, + valueCompiler: DSCompiler?, +): Array { + val sizes = Array(parameters + 1) { + IntArray(order + 1) + } + + if (parameters == 0) { + sizes[0].fill(1) + } else { + checkNotNull(valueCompiler) + valueCompiler.sizes.copyInto(sizes, endIndex = parameters) + sizes[parameters][0] = 1 + for (i in 0 until order) { + sizes[parameters][i + 1] = sizes[parameters][i] + sizes[parameters - 1][i + 1] + } + } + return sizes +} + +/** + * Compile the derivatives' indirection array. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param valueCompiler compiler for the value part. + * @param derivativeCompiler compiler for the derivative part. + * @return derivatives indirection array. + */ +private fun > compileDerivativesIndirection( + parameters: Int, + order: Int, + valueCompiler: DSCompiler?, + derivativeCompiler: DSCompiler?, +): Array { + if (parameters == 0 || order == 0) { + return Array(1) { IntArray(parameters) } + } + + val vSize: Int = valueCompiler!!.derivativesIndirection.size + val dSize: Int = derivativeCompiler!!.derivativesIndirection.size + val derivativesIndirection = Array(vSize + dSize) { IntArray(parameters) } + + // set up the indices for the value part + for (i in 0 until vSize) { + // copy the first indices, the last one remaining set to 0 + valueCompiler.derivativesIndirection[i].copyInto(derivativesIndirection[i], endIndex = parameters - 1) + } + + // set up the indices for the derivative part + for (i in 0 until dSize) { + // copy the indices + derivativeCompiler.derivativesIndirection[i].copyInto(derivativesIndirection[vSize], 0, 0, parameters) + + // increment the derivation order for the last parameter + derivativesIndirection[vSize + i][parameters - 1]++ + } + + return derivativesIndirection +} + +/** + * Compile the lower derivatives' indirection array. + * + * This indirection array contains the indices of all elements except derivatives for last derivation order. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param valueCompiler compiler for the value part. + * @param derivativeCompiler compiler for the derivative part. + * @return lower derivatives' indirection array. + */ +private fun > compileLowerIndirection( + parameters: Int, + order: Int, + valueCompiler: DSCompiler?, + derivativeCompiler: DSCompiler?, +): IntArray { + if (parameters == 0 || order <= 1) return intArrayOf(0) + checkNotNull(valueCompiler) + checkNotNull(derivativeCompiler) + + // this is an implementation of definition 6 in Dan Kalman's paper. + val vSize: Int = valueCompiler.lowerIndirection.size + val dSize: Int = derivativeCompiler.lowerIndirection.size + val lowerIndirection = IntArray(vSize + dSize) + valueCompiler.lowerIndirection.copyInto(lowerIndirection, endIndex = vSize) + for (i in 0 until dSize) { + lowerIndirection[vSize + i] = valueCompiler.size + derivativeCompiler.lowerIndirection[i] + } + return lowerIndirection +} + +/** + * Compile the multiplication indirection array. + * + * This indirection array contains the indices of all pairs of elements involved when computing a multiplication. This + * allows a straightforward loop-based multiplication (see [multiply]). + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param valueCompiler compiler for the value part. + * @param derivativeCompiler compiler for the derivative part. + * @param lowerIndirection lower derivatives' indirection array. + * @return multiplication indirection array. + */ +@Suppress("UNCHECKED_CAST") +private fun > compileMultiplicationIndirection( + parameters: Int, + order: Int, + valueCompiler: DSCompiler?, + derivativeCompiler: DSCompiler?, + lowerIndirection: IntArray, +): Array> { + if (parameters == 0 || order == 0) return arrayOf(arrayOf(intArrayOf(1, 0, 0))) + + // this is an implementation of definition 3 in Dan Kalman's paper. + val vSize = valueCompiler!!.multIndirection.size + val dSize = derivativeCompiler!!.multIndirection.size + val multIndirection: Array?> = arrayOfNulls(vSize + dSize) + valueCompiler.multIndirection.copyInto(multIndirection, endIndex = vSize) + + for (i in 0 until dSize) { + val dRow = derivativeCompiler.multIndirection[i] + val row: List = buildList(dRow.size * 2) { + for (j in dRow.indices) { + add(intArrayOf(dRow[j][0], lowerIndirection[dRow[j][1]], vSize + dRow[j][2])) + add(intArrayOf(dRow[j][0], vSize + dRow[j][1], lowerIndirection[dRow[j][2]])) + } + } + + // combine terms with similar derivation orders + val combined: List = buildList(row.size) { + for (j in row.indices) { + val termJ = row[j] + if (termJ[0] > 0) { + for (k in j + 1 until row.size) { + val termK = row[k] + + if (termJ[1] == termK[1] && termJ[2] == termK[2]) { + // combine termJ and termK + termJ[0] += termK[0] + // make sure we will skip termK later on in the outer loop + termK[0] = 0 + } + } + + add(termJ) + } + } + } + + multIndirection[vSize + i] = combined.toTypedArray() + } + + return multIndirection as Array> +} + +/** + * Compile the indirection array of function composition. + * + * This indirection array contains the indices of all sets of elements involved when computing a composition. This + * allows a straightforward loop-based composition (see [compose]). + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param valueCompiler compiler for the value part. + * @param derivativeCompiler compiler for the derivative part. + * @param sizes sizes array. + * @param derivativesIndirection derivatives indirection array. + * @return multiplication indirection array. + */ +@Suppress("UNCHECKED_CAST") +private fun > compileCompositionIndirection( + parameters: Int, + order: Int, + valueCompiler: DSCompiler?, + derivativeCompiler: DSCompiler?, + sizes: Array, + derivativesIndirection: Array, +): Array> { + if (parameters == 0 || order == 0) { + return arrayOf(arrayOf(intArrayOf(1, 0))) + } + + val vSize = valueCompiler!!.compositionIndirection.size + val dSize = derivativeCompiler!!.compositionIndirection.size + val compIndirection: Array?> = arrayOfNulls(vSize + dSize) + + // the composition rules from the value part can be reused as is + valueCompiler.compositionIndirection.copyInto(compIndirection, endIndex = vSize) + + // the composition rules for the derivative part are deduced by differentiation the rules from the + // underlying compiler once with respect to the parameter this compiler handles and the underlying one + // did not handle + + // the composition rules for the derivative part are deduced by differentiation the rules from the + // underlying compiler once with respect to the parameter this compiler handles and the underlying one did + // not handle + for (i in 0 until dSize) { + val row: List = buildList { + for (term in derivativeCompiler.compositionIndirection[i]) { + + // handle term p * f_k(g(x)) * g_l1(x) * g_l2(x) * ... * g_lp(x) + + // derive the first factor in the term: f_k with respect to new parameter + val derivedTermF = IntArray(term.size + 1) + derivedTermF[0] = term[0] // p + derivedTermF[1] = term[1] + 1 // f_(k+1) + val orders = IntArray(parameters) + orders[parameters - 1] = 1 + derivedTermF[term.size] = getPartialDerivativeIndex( + parameters, + order, + sizes, + *orders + ) // g_1 + + for (j in 2 until term.size) { + // convert the indices as the mapping for the current order is different from the mapping with one + // less order + derivedTermF[j] = convertIndex( + term[j], parameters, + derivativeCompiler.derivativesIndirection, + parameters, order, sizes + ) + } + + derivedTermF.sort(2, derivedTermF.size) + add(derivedTermF) + + // derive the various g_l + for (l in 2 until term.size) { + val derivedTermG = IntArray(term.size) + derivedTermG[0] = term[0] + derivedTermG[1] = term[1] + + for (j in 2 until term.size) { + // convert the indices as the mapping for the current order + // is different from the mapping with one less order + derivedTermG[j] = convertIndex( + term[j], + parameters, + derivativeCompiler.derivativesIndirection, + parameters, + order, + sizes, + ) + + if (j == l) { + // derive this term + derivativesIndirection[derivedTermG[j]].copyInto(orders, endIndex = parameters) + orders[parameters - 1]++ + + derivedTermG[j] = getPartialDerivativeIndex( + parameters, + order, + sizes, + *orders, + ) + } + } + + derivedTermG.sort(2, derivedTermG.size) + add(derivedTermG) + } + } + } + + // combine terms with similar derivation orders + val combined: List = buildList(row.size) { + for (j in row.indices) { + val termJ = row[j] + + if (termJ[0] > 0) { + (j + 1 until row.size).map { k -> row[k] }.forEach { termK -> + var equals = termJ.size == termK.size + var l = 1 + + while (equals && l < termJ.size) { + equals = equals and (termJ[l] == termK[l]) + ++l + } + + if (equals) { + // combine termJ and termK + termJ[0] += termK[0] + // make sure we will skip termK later on in the outer loop + termK[0] = 0 + } + } + + add(termJ) + } + } + } + + compIndirection[vSize + i] = combined.toTypedArray() + } + + return compIndirection as Array> +} + +/** + * Get the index of a partial derivative in an array. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param sizes sizes array. + * @param orders derivation orders with respect to each parameter (the length of this array must match the number of + * parameters). + * @return index of the partial derivative. + */ +private fun getPartialDerivativeIndex( + parameters: Int, + order: Int, + sizes: Array, + vararg orders: Int, +): Int { + + // the value is obtained by diving into the recursive Dan Kalman's structure + // this is theorem 2 of his paper, with recursion replaced by iteration + var index = 0 + var m = order + var ordersSum = 0 + + for (i in parameters - 1 downTo 0) { + // derivative order for current free parameter + var derivativeOrder = orders[i] + + // safety check + ordersSum += derivativeOrder + require(ordersSum <= order) { "number is too large: $ordersSum > $order" } + + while (derivativeOrder-- > 0) { + // as long as we differentiate according to current free parameter, + // we have to skip the value part and dive into the derivative part, + // so we add the size of the value part to the base index + index += sizes[i][m--] + } + } + + return index +} + +/** + * Convert an index from one (parameters, order) structure to another. + * + * @param index index of a partial derivative in source derivative structure. + * @param srcP number of free parameters in source derivative structure. + * @param srcDerivativesIndirection derivatives indirection array for the source derivative structure. + * @param destP number of free parameters in destination derivative structure. + * @param destO derivation order in destination derivative structure. + * @param destSizes sizes array for the destination derivative structure. + * @return index of the partial derivative with the *same* characteristics in destination derivative structure. + */ +private fun convertIndex( + index: Int, + srcP: Int, + srcDerivativesIndirection: Array, + destP: Int, + destO: Int, + destSizes: Array, +): Int { + val orders = IntArray(destP) + srcDerivativesIndirection[index].copyInto(orders, endIndex = min(srcP, destP)) + return getPartialDerivativeIndex(destP, destO, destSizes, *orders) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt new file mode 100644 index 000000000..a1a6354f0 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt @@ -0,0 +1,186 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.expressions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.NumericAlgebra +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.structures.MutableBuffer + +/** + * Class representing both the value and the differentials of a function. + * + * This class is the workhorse of the differentiation package. + * + * This class is an implementation of the extension to Rall's numbers described in Dan Kalman's paper [Doubly Recursive + * Multivariate Automatic Differentiation](http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf), + * Mathematics Magazine, vol. 75, no. 3, June 2002. Rall's numbers are an extension to the real numbers used + * throughout mathematical expressions; they hold the derivative together with the value of a function. Dan Kalman's + * derivative structures hold all partial derivatives up to any specified order, with respect to any number of free + * parameters. Rall's numbers therefore can be seen as derivative structures for order one derivative and one free + * parameter, and real numbers can be seen as derivative structures with zero order derivative and no free parameters. + * + * Derived from + * [Commons Math's `DerivativeStructure`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DerivativeStructure.java). + */ +@UnstableKMathAPI +public open class DerivativeStructure internal constructor( + internal val derivativeAlgebra: DerivativeStructureRing, + internal val compiler: DSCompiler, +) where A : Ring, A : NumericAlgebra, A : ScaleOperations { + /** + * Combined array holding all values. + */ + internal var data: MutableBuffer = + derivativeAlgebra.bufferFactory(compiler.size) { derivativeAlgebra.algebra.zero } + + /** + * Build an instance with all values and derivatives set to 0. + * + * @param parameters number of free parameters. + * @param order derivation order. + */ + public constructor ( + derivativeAlgebra: DerivativeStructureRing, + parameters: Int, + order: Int, + ) : this( + derivativeAlgebra, + getCompiler(derivativeAlgebra.algebra, derivativeAlgebra.bufferFactory, parameters, order), + ) + + /** + * Build an instance representing a constant value. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param value value of the constant. + * @see DerivativeStructure + */ + public constructor ( + derivativeAlgebra: DerivativeStructureRing, + parameters: Int, + order: Int, + value: T, + ) : this( + derivativeAlgebra, + parameters, + order, + ) { + data[0] = value + } + + /** + * Build an instance representing a variable. + * + * Instances built using this constructor are considered to be the free variables with respect to which + * differentials are computed. As such, their differential with respect to themselves is +1. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param index index of the variable (from 0 to `parameters - 1`). + * @param value value of the variable. + */ + public constructor ( + derivativeAlgebra: DerivativeStructureRing, + parameters: Int, + order: Int, + index: Int, + value: T, + ) : this(derivativeAlgebra, parameters, order, value) { + require(index < parameters) { "number is too large: $index >= $parameters" } + + if (order > 0) { + // the derivative of the variable with respect to itself is 1. + data[getCompiler(derivativeAlgebra.algebra, derivativeAlgebra.bufferFactory, index, order).size] = + derivativeAlgebra.algebra.one + } + } + + /** + * Build an instance from all its derivatives. + * + * @param parameters number of free parameters. + * @param order derivation order. + * @param derivatives derivatives sorted according to [DSCompiler.getPartialDerivativeIndex]. + */ + public constructor ( + derivativeAlgebra: DerivativeStructureRing, + parameters: Int, + order: Int, + vararg derivatives: T, + ) : this( + derivativeAlgebra, + parameters, + order, + ) { + require(derivatives.size == data.size) { "dimension mismatch: ${derivatives.size} and ${data.size}" } + data = derivativeAlgebra.bufferFactory(data.size) { derivatives[it] } + } + + /** + * Copy constructor. + * + * @param ds instance to copy. + */ + internal constructor(ds: DerivativeStructure) : this(ds.derivativeAlgebra, ds.compiler) { + this.data = ds.data.copy() + } + + /** + * The number of free parameters. + */ + public val freeParameters: Int + get() = compiler.freeParameters + + /** + * The derivation order. + */ + public val order: Int + get() = compiler.order + + /** + * The value part of the derivative structure. + * + * @see getPartialDerivative + */ + public val value: T + get() = data[0] + + /** + * Get a partial derivative. + * + * @param orders derivation orders with respect to each variable (if all orders are 0, the value is returned). + * @return partial derivative. + * @see value + */ + public fun getPartialDerivative(vararg orders: Int): T = data[compiler.getPartialDerivativeIndex(*orders)] + + + /** + * Test for the equality of two derivative structures. + * + * Derivative structures are considered equal if they have the same number + * of free parameters, the same derivation order, and the same derivatives. + * + * @return `true` if two derivative structures are equal. + */ + public override fun equals(other: Any?): Boolean { + if (this === other) return true + + if (other is DerivativeStructure<*, *>) { + return ((freeParameters == other.freeParameters) && + (order == other.order) && + data == other.data) + } + + return false + } + + public override fun hashCode(): Int = + 227 + 229 * freeParameters + 233 * order + 239 * data.hashCode() +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt new file mode 100644 index 000000000..f91fb55e8 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt @@ -0,0 +1,332 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.expressions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.MutableBufferFactory +import space.kscience.kmath.structures.indices + +/** + * A class implementing both [DerivativeStructure] and [Symbol]. + */ +@UnstableKMathAPI +public class DerivativeStructureSymbol( + derivativeAlgebra: DerivativeStructureRing, + size: Int, + order: Int, + index: Int, + symbol: Symbol, + value: T, +) : Symbol by symbol, DerivativeStructure( + derivativeAlgebra, + size, + order, + index, + value +) where A : Ring, A : NumericAlgebra, A : ScaleOperations { + override fun toString(): String = symbol.toString() + override fun equals(other: Any?): Boolean = (other as? Symbol) == symbol + override fun hashCode(): Int = symbol.hashCode() +} + +/** + * A ring over [DerivativeStructure]. + * + * @property order The derivation order. + * @param bindings The map of bindings values. All bindings are considered free parameters. + */ +@UnstableKMathAPI +public open class DerivativeStructureRing( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val order: Int, + bindings: Map, +) : Ring>, ScaleOperations>, + NumericAlgebra>, + ExpressionAlgebra>, + NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { + public val numberOfVariables: Int = bindings.size + + override val zero: DerivativeStructure by lazy { + DerivativeStructure( + this, + numberOfVariables, + order, + ) + } + + override val one: DerivativeStructure by lazy { + DerivativeStructure( + this, + numberOfVariables, + order, + algebra.one, + ) + } + + override fun number(value: Number): DerivativeStructure = const(algebra.number(value)) + + private val variables: Map> = + bindings.entries.mapIndexed { index, (key, value) -> + key to DerivativeStructureSymbol( + this, + numberOfVariables, + order, + index, + key, + value, + ) + }.toMap() + + public override fun const(value: T): DerivativeStructure = + DerivativeStructure(this, numberOfVariables, order, value) + + override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[StringSymbol(value)] + + override fun bindSymbol(value: String): DerivativeStructureSymbol = + bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") + + public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] + + public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = + bindSymbolOrNull(symbol.identity) ?: error("Symbol '${symbol}' is not supported in $this") + + public fun DerivativeStructure.derivative(symbols: List): T { + require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } + val ordersCount = symbols.groupBy { it }.mapValues { it.value.size } + return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) + } + + public fun DerivativeStructure.derivative(vararg symbols: Symbol): T = derivative(symbols.toList()) + + override fun DerivativeStructure.unaryMinus(): DerivativeStructure { + val ds = DerivativeStructure(this@DerivativeStructureRing, compiler) + for (i in ds.data.indices) { + ds.data[i] = algebra { -data[i] } + } + return ds + } + + override fun add(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure { + left.compiler.checkCompatibility(right.compiler) + val ds = DerivativeStructure(left) + left.compiler.add(left.data, 0, right.data, 0, ds.data, 0) + return ds + } + + override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure { + val ds = DerivativeStructure(a) + for (i in ds.data.indices) { + ds.data[i] = algebra { ds.data[i].times(value) } + } + return ds + } + + override fun multiply( + left: DerivativeStructure, + right: DerivativeStructure + ): DerivativeStructure { + left.compiler.checkCompatibility(right.compiler) + val result = DerivativeStructure(this, left.compiler) + left.compiler.multiply(left.data, 0, right.data, 0, result.data, 0) + return result + } + + override fun DerivativeStructure.minus(arg: DerivativeStructure): DerivativeStructure { + compiler.checkCompatibility(arg.compiler) + val ds = DerivativeStructure(this) + compiler.subtract(data, 0, arg.data, 0, ds.data, 0) + return ds + } + + override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure { + val ds = DerivativeStructure(this) + ds.data[0] = algebra { ds.data[0] + number(other) } + return ds + } + + override operator fun DerivativeStructure.minus(other: Number): DerivativeStructure = + this + -other.toDouble() + + override operator fun Number.plus(other: DerivativeStructure): DerivativeStructure = other + this + override operator fun Number.minus(other: DerivativeStructure): DerivativeStructure = other - this +} + +@UnstableKMathAPI +public class DerivativeStructureRingExpression( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val function: DerivativeStructureRing.() -> DerivativeStructure, +) : DifferentiableExpression where A : Ring, A : ScaleOperations, A : NumericAlgebra { + override operator fun invoke(arguments: Map): T = + DerivativeStructureRing(algebra, bufferFactory, 0, arguments).function().value + + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + with( + DerivativeStructureRing( + algebra, + bufferFactory, + symbols.size, + arguments + ) + ) { function().derivative(symbols) } + } +} + +/** + * A field over commons-math [DerivativeStructure]. + * + * @property order The derivation order. + * @param bindings The map of bindings values. All bindings are considered free parameters. + */ +@UnstableKMathAPI +public class DerivativeStructureField>( + algebra: A, + bufferFactory: MutableBufferFactory, + order: Int, + bindings: Map, +) : DerivativeStructureRing(algebra, bufferFactory, order, bindings), ExtendedField> { + override fun number(value: Number): DerivativeStructure = const(algebra.number(value)) + + override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure { + left.compiler.checkCompatibility(right.compiler) + val result = DerivativeStructure(this, left.compiler) + left.compiler.divide(left.data, 0, right.data, 0, result.data, 0) + return result + } + + override fun sin(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.sin(arg.data, 0, result.data, 0) + return result + } + + override fun cos(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.cos(arg.data, 0, result.data, 0) + return result + } + + override fun tan(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.tan(arg.data, 0, result.data, 0) + return result + } + + override fun asin(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.asin(arg.data, 0, result.data, 0) + return result + } + + override fun acos(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.acos(arg.data, 0, result.data, 0) + return result + } + + override fun atan(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.atan(arg.data, 0, result.data, 0) + return result + } + + override fun sinh(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.sinh(arg.data, 0, result.data, 0) + return result + } + + override fun cosh(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.cosh(arg.data, 0, result.data, 0) + return result + } + + override fun tanh(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.tanh(arg.data, 0, result.data, 0) + return result + } + + override fun asinh(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.asinh(arg.data, 0, result.data, 0) + return result + } + + override fun acosh(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.acosh(arg.data, 0, result.data, 0) + return result + } + + override fun atanh(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.atanh(arg.data, 0, result.data, 0) + return result + } + + override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { + is Int -> { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.pow(arg.data, 0, pow, result.data, 0) + result + } + else -> { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.pow(arg.data, 0, pow.toDouble(), result.data, 0) + result + } + } + + override fun sqrt(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.sqrt(arg.data, 0, result.data, 0) + return result + } + + public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure { + arg.compiler.checkCompatibility(pow.compiler) + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.pow(arg.data, 0, pow.data, 0, result.data, 0) + return result + } + + override fun exp(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.exp(arg.data, 0, result.data, 0) + return result + } + + override fun ln(arg: DerivativeStructure): DerivativeStructure { + val result = DerivativeStructure(this, arg.compiler) + arg.compiler.ln(arg.data, 0, result.data, 0) + return result + } +} + +@UnstableKMathAPI +public class DerivativeStructureFieldExpression>( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val function: DerivativeStructureField.() -> DerivativeStructure, +) : DifferentiableExpression { + override operator fun invoke(arguments: Map): T = + DerivativeStructureField(algebra, bufferFactory, 0, arguments).function().value + + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + with( + DerivativeStructureField( + algebra, + bufferFactory, + symbols.size, + arguments, + ) + ) { function().derivative(symbols) } + } +} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt new file mode 100644 index 000000000..429fe310b --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt @@ -0,0 +1,59 @@ +/* + * 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 file. + */ + +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.expressions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.structures.DoubleBuffer +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFails + +internal inline fun diff( + order: Int, + vararg parameters: Pair, + block: DerivativeStructureField.() -> Unit, +) { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + DerivativeStructureField(DoubleField, ::DoubleBuffer, order, mapOf(*parameters)).block() +} + +internal class AutoDiffTest { + private val x by symbol + private val y by symbol + + @Test + fun derivativeStructureFieldTest() { + diff(2, x to 1.0, y to 1.0) { + val x = bindSymbol(x)//by binding() + val y = bindSymbol("y") + val z = x * (-sin(x * y) + y) + 2.0 + println(z.derivative(x)) + println(z.derivative(y, x)) + assertEquals(z.derivative(x, y), z.derivative(y, x)) + // check improper order cause failure + assertFails { z.derivative(x, x, y) } + } + } + + @Test + fun autoDifTest() { + val f = DerivativeStructureFieldExpression(DoubleField, ::DoubleBuffer) { + val x by binding + val y by binding + x.pow(2) + 2 * x * y + y.pow(2) + 1 + } + + assertEquals(10.0, f(x to 1.0, y to 2.0)) + assertEquals(6.0, f.derivative(x)(x to 1.0, y to 2.0)) + assertEquals(2.0, f.derivative(x, x)(x to 1.234, y to -2.0)) + assertEquals(2.0, f.derivative(x, y)(x to 1.0, y to 2.0)) + } +} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt index 3997a77b3..71fd15fe6 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt @@ -48,7 +48,8 @@ internal object InternalUtils { cache.copyInto( logFactorials, BEGIN_LOG_FACTORIALS, - BEGIN_LOG_FACTORIALS, endCopy + BEGIN_LOG_FACTORIALS, + endCopy, ) } else // All values to be computed From 2483c56f1c95180e168bd564be6131122a6c8cfe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 3 Mar 2022 20:45:35 +0300 Subject: [PATCH 002/174] Restructured Polynomial --- .../kmath/functions/AbstractPolynomial.kt | 354 +++++++++++++++ .../kscience/kmath/functions/Piecewise.kt | 8 +- .../kscience/kmath/functions/Polynomial.kt | 425 ++++++++++++++---- .../kmath/functions/polynomialUtil.kt | 139 ++++++ .../kmath/integration/SplineIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 4 +- .../kmath/functions/PolynomialTest.kt | 11 +- kotlin-js-store/yarn.lock | 56 +-- 8 files changed, 846 insertions(+), 154 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt 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 new file mode 100644 index 000000000..f6a617656 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -0,0 +1,354 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of polynomials. + */ +public interface AbstractPolynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractPolynomialSpace> : Ring

{ + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * 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) + /** + * Returns difference between the constant 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) + /** + * Returns product of the constant 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) + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * 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) + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * 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) + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P = optimizedMultiply(other, this) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public fun P.asConstantOrNull(): C? + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + // endregion + + // region Legacy of Ring interface + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right + // endregion + + public companion object { + // TODO: All of this should be moved to algebraic structures' place for utilities + // TODO: Move receiver to context receiver + /** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ + internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + + // 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. + * @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: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 16af7f555..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -117,16 +117,16 @@ public fun > PiecewisePolynomial( * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ -public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = - findPiece(arg)?.value(ring, arg) +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) /** * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } /** * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { value(ring, it) ?: defaultValue } + { substitute(ring, it) ?: defaultValue } 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 a36d36f52..30280a396 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 @@ -5,128 +5,371 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract +import kotlin.jvm.JvmName import kotlin.math.max -import kotlin.math.pow +import kotlin.math.min /** * Polynomial coefficients model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) { +public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" + +// public companion object { +// /** +// * Default name of variables used in string representations. +// * +// * @see Polynomial.toString +// */ +// public var defaultVariableName: String = "x" +// +// /** +// * Represents result of division with remainder. +// */ +// public data class DividingResult( +// val quotient: Polynomial, +// val reminder: Polynomial +// ) +// } } /** - * Returns a [Polynomial] instance with given [coefficients]. + * Represents internal [Polynomial] errors. + */ +internal class PolynomialError(message: String): Error(message) + +// region Constructors and converters + +/** + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T): Polynomial = Polynomial(coefficients.toList()) +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Evaluates the value of the given double polynomial for given double argument. + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ -public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexed { index, acc, c -> - acc + c * arg.pow(index) -} +@Suppress("FunctionName") +public fun Polynomial(vararg coefficients: T, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) + +// endregion /** - * Evaluates the value of the given polynomial for given argument. - * https://en.wikipedia.org/wiki/Horner%27s_method - */ -public fun > Polynomial.value(ring: C, arg: T): T = ring { - if (coefficients.isEmpty()) return@ring zero - var result: T = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - -/** - * Create a polynomial witch represents differentiated version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.differentiate( - algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) -} - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.integrate( - algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } - } - Polynomial(integratedCoefficients) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > Polynomial.integrate( - algebra: Field, - range: ClosedRange, -): T = algebra { - val integral = integrate(algebra) - integral.value(algebra, range.endInclusive) - integral.value(algebra, range.start) -} - -/** - * Space of polynomials. + * Space of polynomials constructed over ring. * - * @param T the type of operated polynomials. - * @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T]. - * @param ring the [C] instance. + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. */ -public class PolynomialSpace( - private val ring: C, -) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - override val zero: Polynomial = Polynomial(emptyList()) +@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +public open class PolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace>{ + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion - override fun Polynomial.unaryMinus(): Polynomial = ring { + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun Polynomial.plus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + other + else this[0] = this[0]!! + other + } + ) + public override operator fun Polynomial.minus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - other + else this[0] = this[0]!! - other + } + ) + public override operator fun Polynomial.times(other: Int): Polynomial = + if (other == 0) zero + else Polynomial( + coefficients + .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + this@plus + else this[0] = this[0]!! + this@plus + } + ) + public override operator fun Int.minus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - this@minus + else this[0] = this[0]!! - this@minus + } + ) + public override operator fun Int.times(other: Polynomial): Polynomial = + if (this == 0) zero + else Polynomial( + other.coefficients + .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + public override operator fun C.plus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@plus)) + else Polynomial( + toMutableList() + .apply { + this[0] += this@plus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.minus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(-this@minus)) + else Polynomial( + toMutableList() + .apply { + this[0] -= this@minus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.times(other: Polynomial): Polynomial = + Polynomial( + other.coefficients +// .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Polynomial-constant relation + public override operator fun Polynomial.plus(other: C): Polynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] += other + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.minus(other: C): Polynomial = + with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] -= other + } + ) + } +// if (degree == -1) UnivariatePolynomial(-other) else UnivariatePolynomial( +// listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.times(other: C): Polynomial = + Polynomial( + coefficients +// .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Polynomial-polynomial relation + public override operator fun Polynomial.unaryMinus(): Polynomial = Polynomial(coefficients.map { -it }) - } - - override fun add(left: Polynomial, right: Polynomial): Polynomial { - val dim = max(left.coefficients.size, right.coefficients.size) - - return ring { - Polynomial(List(dim) { index -> - left.coefficients.getOrElse(index) { zero } + right.coefficients.getOrElse(index) { zero } - }) + public override operator fun Polynomial.plus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.minus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> -other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return when { + thisDegree == -1 -> this + otherDegree == -1 -> other + else -> + Polynomial( + (0..(thisDegree + otherDegree)) + .map { d -> + (max(0, d - otherDegree)..(min(thisDegree, d))) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } } - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + public override fun Polynomial.isNotZero(): Boolean = coefficients.any { it.isNotZero() } + 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? + public override fun Polynomial.isNotOne(): Boolean = !isOne() + 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? + public override fun Polynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: Polynomial = Polynomial(emptyList()) + override val one: Polynomial = Polynomial(listOf(ring.one)) + + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override fun Polynomial.equals(other: Polynomial): Boolean = + when { + this === other -> true + else -> { + if (this.degree == other.degree) + (0..degree).all { coefficients[it] == other.coefficients[it] } + else false + } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } + + public override fun Polynomial.asConstantOrNull(): C? = + with(coefficients) { + when { + isEmpty() -> ring.zero + degree > 0 -> null + else -> first() + } + } + public override fun Polynomial.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: Polynomial): Polynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } /** * Evaluates the polynomial for the given value [arg]. */ - public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) - - public fun Polynomial.asFunction(): (T) -> T = asFunction(ring) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + // endregion } -public inline fun C.polynomial(block: PolynomialSpace.() -> R): R where C : Ring, C : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalablePolynomialSpace( + ring: A, +) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..1a3eb7874 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -0,0 +1,139 @@ +/* + * 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.jvm.JvmName +import kotlin.math.pow + + +// region Utilities + +/** + * Removes zeros on the end of the coefficient list of polynomial. + */ +//context(PolynomialSpace) +//fun > Polynomial.removeZeros() : Polynomial = +// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero + +/** + * Crates a [PolynomialSpace] over received ring. + */ +public fun > A.polynomial(): PolynomialSpace = + PolynomialSpace(this) + +/** + * Crates a [PolynomialSpace]'s scope over received ring. + */ +public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return PolynomialSpace(this).block() +} + +/** + * Crates a [ScalablePolynomialSpace] over received scalable ring. + */ +public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = + ScalablePolynomialSpace(this) + +/** + * Crates a [ScalablePolynomialSpace]'s scope over received scalable ring. + */ +public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalablePolynomialSpace(this).block() +} + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun Polynomial.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 Polynomial.substitute(ring: Ring, 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 +} + +// 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] + } + return result +} + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + algebra: A, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun Polynomial.antiderivative( + algebra: A, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + val integratedCoefficients = buildList(coefficients.size + 1) { + add(zero) + coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } + } + Polynomial(integratedCoefficients) +} + +/** + * Compute a definite integral of a given polynomial in a [range] + */ +@UnstableKMathAPI +public fun > Polynomial.integrate( + algebra: Field, + range: ClosedRange, +): C = algebra { + val integral = antiderivative(algebra) + integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 15d548641..2e6873ece 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials @@ -23,7 +24,7 @@ import space.kscience.kmath.structures.MutableBufferFactory @OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) /** * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index b13adefa5..bbd76c87e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -9,7 +9,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.value +import space.kscience.kmath.functions.substitute import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer @@ -33,7 +33,7 @@ public interface PolynomialInterpolator> : Interpolator): PiecewisePolynomial override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 05c16d17e..e0f0e32a4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -5,13 +5,22 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun simple_polynomial_test() { + Double.algebra.scalablePolynomial { + val x = Polynomial(listOf(0.0, 1.0)) + val polynomial = x * x - 2 * x + 1 + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + } @Test fun testIntegration() { val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.value(1.0), 0.001) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) } } \ No newline at end of file diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index e21abe604..9fc75720e 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -274,11 +274,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -astring@1.7.5: - version "1.7.5" - resolved "https://registry.yarnpkg.com/astring/-/astring-1.7.5.tgz#a7d47fceaf32b052d33a3d07c511efeec67447ca" - integrity sha512-lobf6RWXb8c4uZ7Mdq0U12efYmpD1UFnyOWVJPTa3ukqZrMopav+2hdNu0hgBF0JIBFK9QgrBDfwYvh3DFJDAA== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -294,24 +289,11 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== -benchmark@*: - version "2.1.4" - resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" - integrity sha1-CfPeMckWQl1JjMLuVloOvzwqVik= - dependencies: - lodash "^4.17.4" - platform "^1.3.3" - binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -binaryen@101.0.0: - version "101.0.0" - resolved "https://registry.yarnpkg.com/binaryen/-/binaryen-101.0.0.tgz#42a9e4cc7a22e2c1d75a31d28005a9b518b2c555" - integrity sha512-FRmVxvrR8jtcf0qcukNAPZDM3dZ2sc9GmA/hKxBI7k3fFzREKh1cAs+ruQi+ITTKz7u/AuFMuVnbJwTh0ef/HQ== - body-parser@^1.19.0: version "1.19.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" @@ -599,14 +581,6 @@ dom-serialize@^2.2.1: extend "^3.0.0" void-elements "^2.0.0" -dukat@0.5.8-rc.4: - version "0.5.8-rc.4" - resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" - integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== - dependencies: - google-protobuf "3.12.2" - typescript "3.9.5" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -881,11 +855,6 @@ glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -google-protobuf@3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" - integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== - graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" @@ -1065,11 +1034,6 @@ jest-worker@^27.4.1: merge-stream "^2.0.0" supports-color "^8.0.0" -js-base64@3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.6.1.tgz#555aae398b74694b4037af1f8a5a6209d170efbe" - integrity sha512-Frdq2+tRRGLQUIQOgsIGSCd1VePCS2fsddTG5dTCqR0JHgltXWfsxnY0gIXPoMeRmdom6Oyq+UMOFg5suduOjQ== - js-yaml@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -1179,7 +1143,7 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1437,11 +1401,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -platform@^1.3.3: - version "1.3.6" - resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" - integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== - postcss-modules-extract-imports@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" @@ -1696,14 +1655,6 @@ source-map-loader@3.0.0: iconv-lite "^0.6.2" source-map-js "^0.6.2" -source-map-support@0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -1838,11 +1789,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== - ua-parser-js@^0.7.28: version "0.7.31" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" From ab9dcd83b90a468a325948a1c32257ae0a5d5875 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 10 Mar 2022 01:44:14 +0300 Subject: [PATCH 003/174] Added abstract rational functions --- .../kmath/functions/AbstractPolynomial.kt | 16 +- .../functions/AbstractRationalFunction.kt | 507 ++++++++++++++++++ 2 files changed, 515 insertions(+), 8 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt 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 f6a617656..237a72bcc 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 @@ -70,19 +70,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Polynomial-integer relation /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as polynomial. * * 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) /** - * Returns difference between the constant and the integer represented as polynomial. + * 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) /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -91,19 +91,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Integer-polynomial relation /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) /** - * Returns difference between the integer represented as polynomial and the constant. + * 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) /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -254,11 +254,11 @@ public interface AbstractPolynomialSpace> : Ring

/** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: P + public override val zero: P /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: P + public override val one: P /** * Checks equality of the polynomials. 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 new file mode 100644 index 000000000..5cb570c9f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -0,0 +1,507 @@ +/* + * 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.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of rational function. + */ +public interface AbstractRationalFunction> + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P + /** + * Returns difference between the constant 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 + /** + * Returns product of the constant 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 + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P + // endregion + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * 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) + /** + * 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) + /** + * 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) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * 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) + /** + * 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) + /** + * 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) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zeroPolynomial + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zeroPolynomial + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == onePolynomial + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != onePolynomial + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -onePolynomial + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -onePolynomial + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public val zeroPolynomial: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public val onePolynomial: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun C.plus(other: R): R + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public operator fun C.minus(other: R): R + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public operator fun C.times(other: R): R + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun R.plus(other: C): R + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public operator fun R.minus(other: C): R + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public operator fun R.times(other: C): R + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun P.plus(other: R): R + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public operator fun P.minus(other: R): R + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.times(other: R): R + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun R.plus(other: P): R + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public operator fun R.minus(other: P): R + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public operator fun R.times(other: P): R + // endregion + + // region Rational-rational relation + /** + * Returns the same rational function. + */ + public override operator fun R.unaryPlus(): R = this + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R + + /** + * Check if the instant is zero rational function. + */ + public fun R.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero rational function. + */ + public fun R.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit rational function. + */ + public fun R.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit rational function. + */ + public fun R.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit rational function. + */ + public fun R.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit rational function. + */ + public fun R.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun R.equals(other: R): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun P.asConstantOrNull(): C? + + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isConstant(): Boolean + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNonZeroConstant(): Boolean + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun R.asConstantOrNull(): C? + + public fun R.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // TODO: Перенести в реализацию +// fun R.substitute(argument: C): C +// fun R.substitute(argument: P): R +// fun R.substitute(argument: R): R +// +// fun R.asFunction(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnConstants(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun P.asFunctionOnPolynomials(): (P) -> R = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnRationalFunctions(): (R) -> R = /*this::substitute*/ { this.substitute(it) } +// +// operator fun R.invoke(argument: C): C = this.substitute(argument) +// operator fun R.invoke(argument: P): R = this.substitute(argument) +// operator fun R.invoke(argument: R): R = this.substitute(argument) + // endregion + + // region Legacy + override fun add(left: R, right: R): R = left + right + override fun multiply(left: R, right: R): R = left * right + // endregion +} \ No newline at end of file From ffea8cc2234d869745fb0b99a8baedbf9cb51118 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:25:25 +0300 Subject: [PATCH 004/174] Regenerated READMEs --- README.md | 4 ++-- kmath-ast/README.md | 47 +++++++++++++++++++++++++++++--------- kmath-complex/README.md | 6 ++--- kmath-core/README.md | 6 ++--- kmath-ejml/README.md | 6 ++--- kmath-for-real/README.md | 6 ++--- kmath-functions/README.md | 6 ++--- kmath-jafama/README.md | 6 ++--- kmath-kotlingrad/README.md | 6 ++--- kmath-nd4j/README.md | 6 ++--- kmath-tensors/README.md | 6 ++--- 11 files changed, 65 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 99dd6d00f..76b8ce2f7 100644 --- a/README.md +++ b/README.md @@ -308,8 +308,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-17") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-19") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-19") for jvm-specific version } ``` diff --git a/kmath-ast/README.md b/kmath-ast/README.md index bedf17486..9411befe3 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-19`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-17' + implementation 'space.kscience:kmath-ast:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-17") + implementation("space.kscience:kmath-ast:0.3.0-dev-19") } ``` @@ -66,20 +66,19 @@ For example, the following code: ```kotlin import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.operations.DoubleField -"x+2".parseMath().compileToExpression(ComplexField) +"x^3-x+3".parseMath().compileToExpression(DoubleField) ``` … leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.Map; -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.complex.Complex; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; +import java.util.*; +import kotlin.jvm.functions.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.complex.*; +import space.kscience.kmath.expressions.*; public final class CompiledExpression_45045_0 implements Expression { private final Object[] constants; @@ -91,6 +90,32 @@ public final class CompiledExpression_45045_0 implements Expression { } ``` +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: + +```java +import java.util.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_-386104628_0 implements DoubleExpression { + private final SymbolIndexer indexer; + + public SymbolIndexer getIndexer() { + return this.indexer; + } + + public double invoke(double[] arguments) { + double var2 = arguments[0]; + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } + + public final Double invoke(Map arguments) { + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } +} +``` + Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. #### Limitations diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 92f2435ba..cfaf43aa1 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-17' + implementation 'space.kscience:kmath-complex:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-17") + implementation("space.kscience:kmath-complex:0.3.0-dev-19") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index e765ad50c..4e980baf5 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-19`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-17' + implementation 'space.kscience:kmath-core:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-17") + implementation("space.kscience:kmath-core:0.3.0-dev-19") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index fcd092bf1..24b36aa0d 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-17' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-17") + implementation("space.kscience:kmath-ejml:0.3.0-dev-19") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 938327612..f6b02e6ad 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-17' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-17") + implementation("space.kscience:kmath-for-real:0.3.0-dev-19") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3d4beee47..a7f4f9b6f 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-19`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-17' + implementation 'space.kscience:kmath-functions:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-17") + implementation("space.kscience:kmath-functions:0.3.0-dev-19") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 760244751..3e0d9c418 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-19`. **Gradle:** ```gradle @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-17' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-17") + implementation("space.kscience:kmath-jafama:0.3.0-dev-19") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 588ccb9b4..422ce4fb0 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-19") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 7ca9cd4fd..23d529e72 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-17") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-19") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 42ce91336..93f78e895 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-17' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-17") + implementation("space.kscience:kmath-tensors:0.3.0-dev-19") } ``` From 843d63c76a46a55c683f4a8276663f5fecc6d6f5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:27:00 +0300 Subject: [PATCH 005/174] Added support for all polynomials. But standard utilities still are not fully implemented. --- .../kmath/functions/AbstractPolynomial.kt | 47 +- .../functions/AbstractRationalFunction.kt | 2 - .../kmath/functions/LabeledPolynomial.kt | 927 ++++++++++++++++++ .../kmath/functions/NumberedPolynomial.kt | 689 +++++++++++++ .../kscience/kmath/functions/Polynomial.kt | 151 ++- .../kscience/kmath/functions/Variable.kt | 38 + .../kscience/kmath/functions/algebraicStub.kt | 51 + .../kmath/functions/labeledPolynomialUtil.kt | 490 +++++++++ .../kmath/functions/numberedPolynomialUtil.kt | 605 ++++++++++++ .../kmath/functions/polynomialUtil.kt | 6 +- 10 files changed, 2911 insertions(+), 95 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt 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 237a72bcc..b7b7116f0 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 @@ -17,6 +17,9 @@ public interface AbstractPolynomial /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractPolynomialSpace> : Ring

{ @@ -307,48 +310,4 @@ public interface AbstractPolynomialSpace> : Ring

override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right // endregion - - public companion object { - // TODO: All of this should be moved to algebraic structures' place for utilities - // TODO: Move receiver to context receiver - /** - * Multiplication of element and integer. - * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the difference. - */ - internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = - when { - other == 0 -> zero - other == 1 -> arg - other == -1 -> -arg - other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) - other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) - other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - - // 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. - * @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: Int): C = - when { - multiplier == 0 -> base - multiplier == 1 -> base + arg - multiplier == -1 -> base - arg - multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) - multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - } } \ No newline at end of file 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 5cb570c9f..34050aa0f 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 @@ -5,8 +5,6 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.js.JsName import kotlin.jvm.JvmName diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..48f6f57fa --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,927 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomials with labeled variables. + * + * @param C Ring in which the polynomial is considered. + */ +public class LabeledPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every non-zero monomial + * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and + * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. + * For example polynomial + * ``` + * 5 a^2 c^3 - 6 b + 0 b c + * ``` + * has coefficients represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Variable] objects. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [LabeledPolynomial] errors. + */ +internal class LabeledPolynomialError: Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [LabeledPolynomialError] with the given [message]. + */ +internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +// endregion + +// region Constructors and converters + +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +// +//fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +// +//context(A) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to ring.one)) +// +//context(A) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) LabeledPolynomial(emptyMap()) +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) zero +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class LabeledPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Variable-integer relation + public operator fun Variable.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * other, + )) + // endregion + + // region Integer-variable relation + public operator fun Int.plus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to ring.one * this@plus, + )) + public operator fun Int.minus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to ring.one * this@minus, + )) + public operator fun Int.times(other: Variable): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one * this@times, + )) + // endregion + + // region Polynomial-integer relation + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-variable relation + public operator fun C.plus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to this@plus, + )) + public operator fun C.minus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to this@minus, + )) + public operator fun C.times(other: Variable): LabeledPolynomial = + if (isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to this@times, + )) + // endregion + + // region Variable-constant relation + public operator fun Variable.plus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to other, + )) + public operator fun Variable.minus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to other, + )) + public operator fun Variable.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(this@times to 1U) to other, + )) + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Variable-variable relation + public operator fun Variable.plus(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * 2 + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to ring.one, + )) + public operator fun Variable.minus(other: Variable): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to -ring.one, + )) + public operator fun Variable.times(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 2U) to ring.one + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U, other to 1U) to ring.one, + )) + // endregion + + // region Variable-polynomial relation + public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = mapOf(this@minus to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-variable relation + public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.times(other: Variable): LabeledPolynomial = + LabeledPolynomial( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> LabeledPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.zero)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.one)) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun LabeledPolynomial.equals(other: LabeledPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.countOfVariables: Int get() = variables.size + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun LabeledPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyMap()) { ring.zero } + else null + } + +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("substitutePolynomial") +// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } +// +// @Suppress("NOTHING_TO_INLINE") +// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("invokePolynomial") +// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..f1ad9a74f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,689 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Polynomial model without fixation on specific context they are applied to. + * + * @param C the type of constants. + */ +public class NumberedPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as + * pair "key-value" in the map, where value is coefficients `a` and + * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring + * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * listOf(0, 1, 1) to 0, + * ) + * ``` + * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not + * contain any zeros on end, but can contain zeros on start or anywhere in middle. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [Polynomial] errors. + */ +internal class NumberedPolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toMap(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) +// +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toList(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) + +public fun > C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class NumberedPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) -other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to this@minus)) + else NumberedPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + if (other.isZero()) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> + NumberedPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } + public override fun NumberedPolynomial.isNotZero(): Boolean = coefficients.values.any { it.isNotZero() } + public override fun NumberedPolynomial.isOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotOne()) return@with false + else foundAbsoluteTermAndItIsOne = true + } + } + foundAbsoluteTermAndItIsOne + } + public override fun NumberedPolynomial.isNotOne(): Boolean = !isOne() + public override fun NumberedPolynomial.isMinusOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsMinusOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotMinusOne()) return@with false + else foundAbsoluteTermAndItIsMinusOne = true + } + } + foundAbsoluteTermAndItIsMinusOne + } + public override fun NumberedPolynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) + override val one: NumberedPolynomial = + NumberedPolynomial( + mapOf( + listOf() to ring.one // 1 * x_1^0 * x_2^0 * ... + ) + ) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun NumberedPolynomial.equals(other: NumberedPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0 else degs.size } ?: 0 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And size of the list is [countOfVariables]. + */ + public val NumberedPolynomial.degrees: List + get() = + buildList(countOfVariables) { + repeat(countOfVariables) { add(0U) } + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun NumberedPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyList()) { ring.zero } + else null + } + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } + + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file 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 30280a396..99d6b0659 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 @@ -5,43 +5,38 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min /** - * Polynomial coefficients model without fixation on specific context they are applied to. + * Polynomial model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" - -// public companion object { -// /** -// * Default name of variables used in string representations. -// * -// * @see Polynomial.toString -// */ -// public var defaultVariableName: String = "x" -// -// /** -// * Represents result of division with remainder. -// */ -// public data class DividingResult( -// val quotient: Polynomial, -// val reminder: Polynomial -// ) -// } } +// region Internal utilities + /** * Represents internal [Polynomial] errors. */ -internal class PolynomialError(message: String): Error(message) +internal class PolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun polynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +// endregion // region Constructors and converters @@ -66,16 +61,16 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) // endregion /** - * Space of polynomials constructed over ring. + * Space of univariate polynomials constructed over ring. * * @param C the type of constants. Polynomials have them as a coefficients in their terms. * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public val ring: A, -) : AbstractPolynomialSpace>{ +) : AbstractPolynomialSpace> { // region Constant-integer relation @JvmName("constantIntPlus") public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } @@ -102,8 +97,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + other - else this[0] = this[0]!! + other + val result = getOrElse(0) { ring.zero } + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.minus(other: Int): Polynomial = @@ -113,8 +114,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - other - else this[0] = this[0]!! - other + val result = getOrElse(0) { ring.zero } - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.times(other: Int): Polynomial = @@ -134,8 +141,14 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + this@plus - else this[0] = this[0]!! + this@plus + val result = this@plus + getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.minus(other: Polynomial): Polynomial = @@ -145,8 +158,16 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - this@minus - else this[0] = this[0]!! - this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = this@minus - getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.times(other: Polynomial): Polynomial = @@ -183,12 +204,20 @@ public open class PolynomialSpace>( // region Constant-polynomial relation public override operator fun C.plus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(this@plus)) else Polynomial( toMutableList() .apply { - this[0] += this@plus + val result = if (size == 0) this@plus else this@plus + get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -196,12 +225,22 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.minus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(-this@minus)) else Polynomial( toMutableList() .apply { - this[0] -= this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = if (size == 0) this@minus else this@minus - get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -209,9 +248,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.times(other: Polynomial): Polynomial = - Polynomial( + if (this.isZero()) other + else Polynomial( other.coefficients -// .subList(0, other.degree + 1) + .subList(0, other.degree + 1) .map { it * this } ) // endregion @@ -224,7 +264,14 @@ public open class PolynomialSpace>( else Polynomial( toMutableList() .apply { - this[0] += other + val result = if (size == 0) other else get(0) + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -232,12 +279,20 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.minus(other: C): Polynomial = - with(coefficients) { + if (other.isZero()) this + else with(coefficients) { if (isEmpty()) Polynomial(listOf(other)) else Polynomial( toMutableList() .apply { - this[0] -= other + val result = if (size == 0) other else get(0) - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -245,9 +300,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.times(other: C): Polynomial = - Polynomial( + if (other.isZero()) this + else Polynomial( coefficients -// .subList(0, degree + 1) + .subList(0, degree + 1) .map { it * other } ) // endregion @@ -283,8 +339,8 @@ public open class PolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return when { - thisDegree == -1 -> this - otherDegree == -1 -> other + thisDegree == -1 -> zero + otherDegree == -1 -> zero else -> Polynomial( (0..(thisDegree + otherDegree)) @@ -293,6 +349,7 @@ public open class PolynomialSpace>( .map { coefficients[it] * other.coefficients[d - it] } .reduce { acc, rational -> acc + rational } } + .run { subList(0, indexOfLast { it.isNotZero() } + 1) } ) } } @@ -321,8 +378,8 @@ public open class PolynomialSpace>( } // endregion - // Not sure is it necessary... // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } public override fun Polynomial.asConstantOrNull(): C? = @@ -354,8 +411,8 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) - // endregion + // endregion } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt new file mode 100644 index 000000000..410604fd3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt @@ -0,0 +1,38 @@ +package space.kscience.kmath.functions + +import kotlin.reflect.KProperty + + +/** + * Represents class of labeled variables like usual + * `x`, `y`, `z`, `a`, `b`, `n`, `m`, etc. + * + * Variables does not contain any information about field (or ring, ets.) they are considered in + * and therefore about coefficient. + * + * @property name Is the label or name of variable. For `x` it is `"x"`, for `n` – `"n"`, etc. + */ +public data class Variable (val name: String) : Comparable { + /** + * Represents the variable as a string. + * + * @return Only name of the variable. + */ + override fun toString(): String = name + /** + * Compares two variables. + * Comparison is realised by comparison of variables' names. + * + * Used in [LabeledPolynomial] and [LabeledRationalFunction] to sort monomials in + * [LabeledPolynomial.toString] and [LabeledRationalFunction.toString] in lexicographic order. + * + * @see Comparable.compareTo + * @sample LabeledPolynomial.monomialComparator + * @return Only name of the variable. + */ + override fun compareTo(other: Variable): Int = name.compareTo(other.name) + + public companion object { + public operator fun getValue(thisRef: Any?, property: KProperty<*>) : Variable = Variable(property.name) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt new file mode 100644 index 000000000..9e5043b8c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Group + + +// TODO: All of this should be moved to algebraic structures' place for utilities +// TODO: Move receiver to context receiver +/** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ +internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + +// 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. + * @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: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 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 new file mode 100644 index 000000000..62ac31b64 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -0,0 +1,490 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.* + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(LabeledPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(LabeledPolynomialSpace) +//fun > power(arg: C, pow: UInt): C = ring { power(arg, pow) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Variables +// +//context(LabeledPolynomialSpace) +//fun > power(arg: Variable, pow: UInt): LabeledPolynomial = +// if (pow == 0U) one +// else LabeledPolynomial(mapOf( +// mapOf(arg to pow) to ring.one +// )) +// +//// endregion + +//// region Polynomials +// +//context(LabeledPolynomialSpace) +//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(LabeledPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = +// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(namer: (Variable) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = +// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Variable) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +//// region Polynomial substitution and functional representation +// +//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// LabeledPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.filterKeys { it !in args } +// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> +// multiplyWithPower(acc, args[variable]!!, deg) +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = +// ring.labeledPolynomial { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.entries +// .asSequence() +// .filter { it.key in arg } +// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> +// multiplyWithPower(acc, arg[index]!!, deg) +// } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//// endregion + +//// region Algebraic derivative and antiderivative +//// TODO +//// endregion \ No newline at end of file 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 new file mode 100644 index 000000000..d4053442d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -0,0 +1,605 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.* +import kotlin.jvm.JvmName + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(NumberedPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//public fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Polynomials +// +//context(NumberedPolynomialSpace) +//public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: NumberedPolynomial, arg: NumberedPolynomial, pow: UInt): NumberedPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(NumberedPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +//// region Polynomial substitution and functional representation +// +//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// NumberedPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() +// val newC = degs.foldIndexed(c) { index, acc, deg -> +// if (index in args) multiplyWithPower(acc, args[index]!!, deg) +// else acc +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = +// ring.numberedPolynomialSpace { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.foldIndexed( +// NumberedPolynomial( +// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c +// ) +// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + val acc = LinkedHashMap, Double>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitutor.pow(deg.toInt()) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +/** + * 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 NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + val acc = LinkedHashMap, C>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed +// as soon as possible on it +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { + val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() + else acc[newDegs] = acc[newDegs]!! + c + } +}*/ + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Ring, A : NumericAlgebra = derivativeBy(algebra, variables.toIntArray()) + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Field, A : NumericAlgebra = antiderivativeBy(algebra, variables.toIntArray()) + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 1a3eb7874..4d99b3a45 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 @@ -121,7 +121,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) + one)) } + coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } } Polynomial(integratedCoefficients) } @@ -136,4 +136,6 @@ public fun > Polynomial.integrate( ): C = algebra { val integral = antiderivative(algebra) integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file +} + +// endregion \ No newline at end of file From 191dd02e478787df7a50efb7b9568701ad243d01 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 3 Mar 2022 20:45:35 +0300 Subject: [PATCH 006/174] Restructured Polynomial --- .../kmath/functions/AbstractPolynomial.kt | 354 +++++++++++++++ .../kscience/kmath/functions/Piecewise.kt | 8 +- .../kscience/kmath/functions/Polynomial.kt | 425 ++++++++++++++---- .../kmath/functions/polynomialUtil.kt | 139 ++++++ .../kmath/integration/SplineIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 4 +- .../kmath/functions/PolynomialTest.kt | 11 +- 7 files changed, 845 insertions(+), 99 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt 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 new file mode 100644 index 000000000..f6a617656 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt @@ -0,0 +1,354 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of polynomials. + */ +public interface AbstractPolynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractPolynomialSpace> : Ring

{ + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * 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) + /** + * Returns difference between the constant 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) + /** + * Returns product of the constant 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) + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * 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) + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * 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) + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P = optimizedMultiply(other, this) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public fun P.asConstantOrNull(): C? + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + // endregion + + // region Legacy of Ring interface + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right + // endregion + + public companion object { + // TODO: All of this should be moved to algebraic structures' place for utilities + // TODO: Move receiver to context receiver + /** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ + internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + + // 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. + * @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: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 16af7f555..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -117,16 +117,16 @@ public fun > PiecewisePolynomial( * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ -public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = - findPiece(arg)?.value(ring, arg) +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) /** * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } /** * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { value(ring, it) ?: defaultValue } + { substitute(ring, it) ?: defaultValue } 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 a36d36f52..30280a396 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 @@ -5,128 +5,371 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract +import kotlin.jvm.JvmName import kotlin.math.max -import kotlin.math.pow +import kotlin.math.min /** * Polynomial coefficients model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) { +public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" + +// public companion object { +// /** +// * Default name of variables used in string representations. +// * +// * @see Polynomial.toString +// */ +// public var defaultVariableName: String = "x" +// +// /** +// * Represents result of division with remainder. +// */ +// public data class DividingResult( +// val quotient: Polynomial, +// val reminder: Polynomial +// ) +// } } /** - * Returns a [Polynomial] instance with given [coefficients]. + * Represents internal [Polynomial] errors. + */ +internal class PolynomialError(message: String): Error(message) + +// region Constructors and converters + +/** + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ @Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T): Polynomial = Polynomial(coefficients.toList()) +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Evaluates the value of the given double polynomial for given double argument. + * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. */ -public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexed { index, acc, c -> - acc + c * arg.pow(index) -} +@Suppress("FunctionName") +public fun Polynomial(vararg coefficients: T, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) + +// endregion /** - * Evaluates the value of the given polynomial for given argument. - * https://en.wikipedia.org/wiki/Horner%27s_method - */ -public fun > Polynomial.value(ring: C, arg: T): T = ring { - if (coefficients.isEmpty()) return@ring zero - var result: T = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - -/** - * Create a polynomial witch represents differentiated version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.differentiate( - algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) -} - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.integrate( - algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } - } - Polynomial(integratedCoefficients) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > Polynomial.integrate( - algebra: Field, - range: ClosedRange, -): T = algebra { - val integral = integrate(algebra) - integral.value(algebra, range.endInclusive) - integral.value(algebra, range.start) -} - -/** - * Space of polynomials. + * Space of polynomials constructed over ring. * - * @param T the type of operated polynomials. - * @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T]. - * @param ring the [C] instance. + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. */ -public class PolynomialSpace( - private val ring: C, -) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - override val zero: Polynomial = Polynomial(emptyList()) +@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +public open class PolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace>{ + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion - override fun Polynomial.unaryMinus(): Polynomial = ring { + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun Polynomial.plus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + other + else this[0] = this[0]!! + other + } + ) + public override operator fun Polynomial.minus(other: Int): Polynomial = + if (other == 0) this + else + Polynomial( + coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - other + else this[0] = this[0]!! - other + } + ) + public override operator fun Polynomial.times(other: Int): Polynomial = + if (other == 0) zero + else Polynomial( + coefficients + .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero + this@plus + else this[0] = this[0]!! + this@plus + } + ) + public override operator fun Int.minus(other: Polynomial): Polynomial = + if (this == 0) other + else + Polynomial( + other.coefficients + .toMutableList() + .apply { + if (isEmpty()) this[0] = ring.zero - this@minus + else this[0] = this[0]!! - this@minus + } + ) + public override operator fun Int.times(other: Polynomial): Polynomial = + if (this == 0) zero + else Polynomial( + other.coefficients + .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + public override operator fun C.plus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@plus)) + else Polynomial( + toMutableList() + .apply { + this[0] += this@plus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.minus(other: Polynomial): Polynomial = + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(-this@minus)) + else Polynomial( + toMutableList() + .apply { + this[0] -= this@minus + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun C.times(other: Polynomial): Polynomial = + Polynomial( + other.coefficients +// .subList(0, other.degree + 1) + .map { it * this } + ) + // endregion + + // region Polynomial-constant relation + public override operator fun Polynomial.plus(other: C): Polynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] += other + } + ) + } +// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( +// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.minus(other: C): Polynomial = + with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + this[0] -= other + } + ) + } +// if (degree == -1) UnivariatePolynomial(-other) else UnivariatePolynomial( +// listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) +// ) + public override operator fun Polynomial.times(other: C): Polynomial = + Polynomial( + coefficients +// .subList(0, degree + 1) + .map { it * other } + ) + // endregion + + // region Polynomial-polynomial relation + public override operator fun Polynomial.unaryMinus(): Polynomial = Polynomial(coefficients.map { -it }) - } - - override fun add(left: Polynomial, right: Polynomial): Polynomial { - val dim = max(left.coefficients.size, right.coefficients.size) - - return ring { - Polynomial(List(dim) { index -> - left.coefficients.getOrElse(index) { zero } + right.coefficients.getOrElse(index) { zero } - }) + public override operator fun Polynomial.plus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.minus(other: Polynomial): Polynomial = + Polynomial( + (0..max(degree, other.degree)) + .map { + when { + it > degree -> -other.coefficients[it] + it > other.degree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + .ifEmpty { listOf(ring.zero) } + ) + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return when { + thisDegree == -1 -> this + otherDegree == -1 -> other + else -> + Polynomial( + (0..(thisDegree + otherDegree)) + .map { d -> + (max(0, d - otherDegree)..(min(thisDegree, d))) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } } - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + public override fun Polynomial.isNotZero(): Boolean = coefficients.any { it.isNotZero() } + 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? + public override fun Polynomial.isNotOne(): Boolean = !isOne() + 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? + public override fun Polynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: Polynomial = Polynomial(emptyList()) + override val one: Polynomial = Polynomial(listOf(ring.one)) + + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override fun Polynomial.equals(other: Polynomial): Boolean = + when { + this === other -> true + else -> { + if (this.degree == other.degree) + (0..degree).all { coefficients[it] == other.coefficients[it] } + else false + } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } + + public override fun Polynomial.asConstantOrNull(): C? = + with(coefficients) { + when { + isEmpty() -> ring.zero + degree > 0 -> null + else -> first() + } + } + public override fun Polynomial.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.substitute(argument: Polynomial): Polynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } /** * Evaluates the polynomial for the given value [arg]. */ - public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) - - public fun Polynomial.asFunction(): (T) -> T = asFunction(ring) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + // endregion } -public inline fun C.polynomial(block: PolynomialSpace.() -> R): R where C : Ring, C : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalablePolynomialSpace( + ring: A, +) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } + } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..1a3eb7874 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -0,0 +1,139 @@ +/* + * 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.jvm.JvmName +import kotlin.math.pow + + +// region Utilities + +/** + * Removes zeros on the end of the coefficient list of polynomial. + */ +//context(PolynomialSpace) +//fun > Polynomial.removeZeros() : Polynomial = +// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero + +/** + * Crates a [PolynomialSpace] over received ring. + */ +public fun > A.polynomial(): PolynomialSpace = + PolynomialSpace(this) + +/** + * Crates a [PolynomialSpace]'s scope over received ring. + */ +public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return PolynomialSpace(this).block() +} + +/** + * Crates a [ScalablePolynomialSpace] over received scalable ring. + */ +public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = + ScalablePolynomialSpace(this) + +/** + * Crates a [ScalablePolynomialSpace]'s scope over received scalable ring. + */ +public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalablePolynomialSpace(this).block() +} + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun Polynomial.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 Polynomial.substitute(ring: Ring, 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 +} + +// 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] + } + return result +} + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + algebra: A, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun Polynomial.antiderivative( + algebra: A, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + val integratedCoefficients = buildList(coefficients.size + 1) { + add(zero) + coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } + } + Polynomial(integratedCoefficients) +} + +/** + * Compute a definite integral of a given polynomial in a [range] + */ +@UnstableKMathAPI +public fun > Polynomial.integrate( + algebra: Field, + range: ClosedRange, +): C = algebra { + val integral = antiderivative(algebra) + integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index eb88d9ae0..0fcd4c6e5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials @@ -23,7 +24,7 @@ import space.kscience.kmath.structures.MutableBufferFactory @OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) /** * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 2266092a3..62819be0c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -10,7 +10,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.value +import space.kscience.kmath.functions.substitute import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer @@ -34,7 +34,7 @@ public interface PolynomialInterpolator> : Interpolator): PiecewisePolynomial override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 05c16d17e..e0f0e32a4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -5,13 +5,22 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun simple_polynomial_test() { + Double.algebra.scalablePolynomial { + val x = Polynomial(listOf(0.0, 1.0)) + val polynomial = x * x - 2 * x + 1 + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + } @Test fun testIntegration() { val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.value(1.0), 0.001) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) } } \ No newline at end of file From cab59581071d25e2a569ad3bb13eb799e42e046f Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 10 Mar 2022 01:44:14 +0300 Subject: [PATCH 007/174] Added abstract rational functions --- .../kmath/functions/AbstractPolynomial.kt | 16 +- .../functions/AbstractRationalFunction.kt | 507 ++++++++++++++++++ 2 files changed, 515 insertions(+), 8 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt 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 f6a617656..237a72bcc 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 @@ -70,19 +70,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Polynomial-integer relation /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the polynomial and the integer represented as polynomial. * * 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) /** - * Returns difference between the constant and the integer represented as polynomial. + * 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) /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the polynomial and the integer represented as polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -91,19 +91,19 @@ public interface AbstractPolynomialSpace> : Ring

// region Integer-polynomial relation /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P = optimizedAddMultiplied(other, one, this) /** - * Returns difference between the integer represented as polynomial and the constant. + * 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) /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -254,11 +254,11 @@ public interface AbstractPolynomialSpace> : Ring

/** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: P + public override val zero: P /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: P + public override val one: P /** * Checks equality of the polynomials. 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 new file mode 100644 index 000000000..5cb570c9f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt @@ -0,0 +1,507 @@ +/* + * 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.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied +import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of rational function. + */ +public interface AbstractRationalFunction> + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public operator fun C.plus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntMinus") + public operator fun C.minus(other: Int): C + /** + * 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]. + */ + @JvmName("constantIntTimes") + public operator fun C.times(other: Int): C + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public operator fun Int.plus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantMinus") + public operator fun Int.minus(other: C): C + /** + * 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]. + */ + @JvmName("intConstantTimes") + public operator fun Int.times(other: C): C + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P + /** + * Returns difference between the constant 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 + /** + * Returns product of the constant 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 + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P + // endregion + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * 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) + /** + * 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) + /** + * 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) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * 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) + /** + * 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) + /** + * 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) + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public operator fun C.times(other: C): C + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public fun C.isZero(): Boolean + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public fun C.isNotZero(): Boolean + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public fun C.isOne(): Boolean + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public fun C.isNotOne(): Boolean + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public fun C.isMinusOne(): Boolean + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public fun C.isNotMinusOne(): Boolean + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public operator fun P.minus(other: P): P + /** + * Returns product of the polynomials. + */ + public operator fun P.times(other: P): P + + /** + * Check if the instant is zero polynomial. + */ + public fun P.isZero(): Boolean = this == zeroPolynomial + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = this != zeroPolynomial + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this == onePolynomial + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = this != onePolynomial + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this == -onePolynomial + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = this != -onePolynomial + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public val zeroPolynomial: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public val onePolynomial: P + + /** + * Checks equality of the polynomials. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun P.equals(other: P): Boolean + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun C.plus(other: R): R + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public operator fun C.minus(other: R): R + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public operator fun C.times(other: R): R + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun R.plus(other: C): R + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public operator fun R.minus(other: C): R + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public operator fun R.times(other: C): R + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun P.plus(other: R): R + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public operator fun P.minus(other: R): R + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.times(other: R): R + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun R.plus(other: P): R + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public operator fun R.minus(other: P): R + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public operator fun R.times(other: P): R + // endregion + + // region Rational-rational relation + /** + * Returns the same rational function. + */ + public override operator fun R.unaryPlus(): R = this + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R + + /** + * Check if the instant is zero rational function. + */ + public fun R.isZero(): Boolean = this == zero + /** + * Check if the instant is NOT zero rational function. + */ + public fun R.isNotZero(): Boolean = this != zero + /** + * Check if the instant is unit rational function. + */ + public fun R.isOne(): Boolean = this == one + /** + * Check if the instant is NOT unit rational function. + */ + public fun R.isNotOne(): Boolean = this != one + /** + * Check if the instant is minus unit rational function. + */ + public fun R.isMinusOne(): Boolean = this == -one + /** + * Check if the instant is NOT minus unit rational function. + */ + public fun R.isNotMinusOne(): Boolean = this != -one + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public fun R.equals(other: R): Boolean + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun P.asConstantOrNull(): C? + + public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isConstant(): Boolean + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNonZeroConstant(): Boolean + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun R.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + + public fun R.asConstantOrNull(): C? + + public fun R.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + + // TODO: Перенести в реализацию +// fun R.substitute(argument: C): C +// fun R.substitute(argument: P): R +// fun R.substitute(argument: R): R +// +// fun R.asFunction(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnConstants(): (C) -> C = /*this::substitute*/ { this.substitute(it) } +// fun P.asFunctionOnPolynomials(): (P) -> R = /*this::substitute*/ { this.substitute(it) } +// fun R.asFunctionOnRationalFunctions(): (R) -> R = /*this::substitute*/ { this.substitute(it) } +// +// operator fun R.invoke(argument: C): C = this.substitute(argument) +// operator fun R.invoke(argument: P): R = this.substitute(argument) +// operator fun R.invoke(argument: R): R = this.substitute(argument) + // endregion + + // region Legacy + override fun add(left: R, right: R): R = left + right + override fun multiply(left: R, right: R): R = left * right + // endregion +} \ No newline at end of file From 571c6342ddcead43bbcd99b1583e86366212f802 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:25:25 +0300 Subject: [PATCH 008/174] Regenerated READMEs --- README.md | 4 ++-- kmath-ast/README.md | 47 +++++++++++++++++++++++++++++--------- kmath-complex/README.md | 6 ++--- kmath-core/README.md | 6 ++--- kmath-ejml/README.md | 6 ++--- kmath-for-real/README.md | 6 ++--- kmath-functions/README.md | 6 ++--- kmath-jafama/README.md | 6 ++--- kmath-kotlingrad/README.md | 6 ++--- kmath-nd4j/README.md | 6 ++--- kmath-tensors/README.md | 6 ++--- 11 files changed, 65 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 99dd6d00f..76b8ce2f7 100644 --- a/README.md +++ b/README.md @@ -308,8 +308,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-17") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-17") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-19") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-19") for jvm-specific version } ``` diff --git a/kmath-ast/README.md b/kmath-ast/README.md index bedf17486..9411befe3 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-19`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-17' + implementation 'space.kscience:kmath-ast:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-17") + implementation("space.kscience:kmath-ast:0.3.0-dev-19") } ``` @@ -66,20 +66,19 @@ For example, the following code: ```kotlin import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.complex.ComplexField +import space.kscience.kmath.operations.DoubleField -"x+2".parseMath().compileToExpression(ComplexField) +"x^3-x+3".parseMath().compileToExpression(DoubleField) ``` … leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.Map; -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.complex.Complex; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; +import java.util.*; +import kotlin.jvm.functions.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.complex.*; +import space.kscience.kmath.expressions.*; public final class CompiledExpression_45045_0 implements Expression { private final Object[] constants; @@ -91,6 +90,32 @@ public final class CompiledExpression_45045_0 implements Expression { } ``` +For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: + +```java +import java.util.*; +import space.kscience.kmath.asm.internal.*; +import space.kscience.kmath.expressions.*; + +public final class CompiledExpression_-386104628_0 implements DoubleExpression { + private final SymbolIndexer indexer; + + public SymbolIndexer getIndexer() { + return this.indexer; + } + + public double invoke(double[] arguments) { + double var2 = arguments[0]; + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } + + public final Double invoke(Map arguments) { + double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); + return Math.pow(var2, 3.0D) - var2 + 3.0D; + } +} +``` + Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. #### Limitations diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 92f2435ba..cfaf43aa1 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-17' + implementation 'space.kscience:kmath-complex:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-17") + implementation("space.kscience:kmath-complex:0.3.0-dev-19") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index e765ad50c..4e980baf5 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-19`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-17' + implementation 'space.kscience:kmath-core:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-17") + implementation("space.kscience:kmath-core:0.3.0-dev-19") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index fcd092bf1..24b36aa0d 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-17' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-17") + implementation("space.kscience:kmath-ejml:0.3.0-dev-19") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 938327612..f6b02e6ad 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-17' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-17") + implementation("space.kscience:kmath-for-real:0.3.0-dev-19") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3d4beee47..a7f4f9b6f 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-19`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-17' + implementation 'space.kscience:kmath-functions:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-17") + implementation("space.kscience:kmath-functions:0.3.0-dev-19") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index 760244751..3e0d9c418 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-19`. **Gradle:** ```gradle @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-17' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-17") + implementation("space.kscience:kmath-jafama:0.3.0-dev-19") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 588ccb9b4..422ce4fb0 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-19`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-17' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-17") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-19") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 7ca9cd4fd..23d529e72 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-17' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-17") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-19") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 42ce91336..93f78e895 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-17`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-19`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-17' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-19' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-17") + implementation("space.kscience:kmath-tensors:0.3.0-dev-19") } ``` From 93de1d53116b29391797f68972c0f6bf144857d6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:27:00 +0300 Subject: [PATCH 009/174] Added support for all polynomials. But standard utilities still are not fully implemented. --- .../kmath/functions/AbstractPolynomial.kt | 47 +- .../functions/AbstractRationalFunction.kt | 2 - .../kmath/functions/LabeledPolynomial.kt | 927 ++++++++++++++++++ .../kmath/functions/NumberedPolynomial.kt | 689 +++++++++++++ .../kscience/kmath/functions/Polynomial.kt | 151 ++- .../kscience/kmath/functions/Variable.kt | 38 + .../kscience/kmath/functions/algebraicStub.kt | 51 + .../kmath/functions/labeledPolynomialUtil.kt | 490 +++++++++ .../kmath/functions/numberedPolynomialUtil.kt | 605 ++++++++++++ .../kmath/functions/polynomialUtil.kt | 6 +- 10 files changed, 2911 insertions(+), 95 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt 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 237a72bcc..b7b7116f0 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 @@ -17,6 +17,9 @@ public interface AbstractPolynomial /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractPolynomialSpace> : Ring

{ @@ -307,48 +310,4 @@ public interface AbstractPolynomialSpace> : Ring

override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right // endregion - - public companion object { - // TODO: All of this should be moved to algebraic structures' place for utilities - // TODO: Move receiver to context receiver - /** - * Multiplication of element and integer. - * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the difference. - */ - internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = - when { - other == 0 -> zero - other == 1 -> arg - other == -1 -> -arg - other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) - other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) - other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - - // 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. - * @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: Int): C = - when { - multiplier == 0 -> base - multiplier == 1 -> base + arg - multiplier == -1 -> base - arg - multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) - multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } - } } \ No newline at end of file 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 5cb570c9f..34050aa0f 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 @@ -5,8 +5,6 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.js.JsName import kotlin.jvm.JvmName diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..48f6f57fa --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,927 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomials with labeled variables. + * + * @param C Ring in which the polynomial is considered. + */ +public class LabeledPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every non-zero monomial + * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and + * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. + * For example polynomial + * ``` + * 5 a^2 c^3 - 6 b + 0 b c + * ``` + * has coefficients represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Variable] objects. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [LabeledPolynomial] errors. + */ +internal class LabeledPolynomialError: Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [LabeledPolynomialError] with the given [message]. + */ +internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +// endregion + +// region Constructors and converters + +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// +// // Map for cleaned coefficients. +// val fixedCoefs = mutableMapOf, C>() +// +// // Cleaning the degrees, summing monomials of the same degrees. +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// // Removing zero monomials. +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received +// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. +// * +// * @param pairs Collection of pairs that represents monomials. +// * +// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +// +//fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +// +//context(A) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to ring.one)) +// +//context(A) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) LabeledPolynomial(emptyMap()) +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) +// +//context(LabeledPolynomialSpace) +//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = +// if(c.isZero()) zero +// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class LabeledPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Variable-integer relation + public operator fun Variable.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to ring.one * other, + )) + public operator fun Variable.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * other, + )) + // endregion + + // region Integer-variable relation + public operator fun Int.plus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to ring.one * this@plus, + )) + public operator fun Int.minus(other: Variable): LabeledPolynomial = + if (this == 0) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to ring.one * this@minus, + )) + public operator fun Int.times(other: Variable): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one * this@times, + )) + // endregion + + // region Polynomial-integer relation + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else + LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else + LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-variable relation + public operator fun C.plus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to ring.one, + emptyMap() to this@plus, + )) + public operator fun C.minus(other: Variable): LabeledPolynomial = + if (isZero()) LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to -ring.one, + emptyMap() to this@minus, + )) + public operator fun C.times(other: Variable): LabeledPolynomial = + if (isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(other to 1U) to this@times, + )) + // endregion + + // region Variable-constant relation + public operator fun Variable.plus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@plus to 1U) to ring.one, + emptyMap() to other, + )) + public operator fun Variable.minus(other: C): LabeledPolynomial = + if (other.isZero()) LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + )) + else LabeledPolynomial(mapOf( + mapOf(this@minus to 1U) to -ring.one, + emptyMap() to other, + )) + public operator fun Variable.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial(mapOf( + mapOf(this@times to 1U) to other, + )) + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + if (this.isZero()) zero + else LabeledPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + if (other.isZero()) zero + else LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Variable-variable relation + public operator fun Variable.plus(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one * 2 + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to ring.one, + )) + public operator fun Variable.minus(other: Variable): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomial(mapOf( + mapOf(this to 1U) to ring.one, + mapOf(other to 1U) to -ring.one, + )) + public operator fun Variable.times(other: Variable): LabeledPolynomial = + if (this == other) LabeledPolynomial(mapOf( + mapOf(this to 2U) to ring.one + )) + else LabeledPolynomial(mapOf( + mapOf(this to 1U, other to 1U) to ring.one, + )) + // endregion + + // region Variable-polynomial relation + public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = mapOf(this@minus to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun Variable.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-variable relation + public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + else LabeledPolynomial( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + val result = ring.one - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + public operator fun LabeledPolynomial.times(other: Variable): LabeledPolynomial = + LabeledPolynomial( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> LabeledPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.zero)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.one)) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun LabeledPolynomial.equals(other: LabeledPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.countOfVariables: Int get() = variables.size + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun LabeledPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun LabeledPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyMap()) { ring.zero } + else null + } + +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("substitutePolynomial") +// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// @Suppress("NOTHING_TO_INLINE") +// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } +// +// @Suppress("NOTHING_TO_INLINE") +// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// @Suppress("NOTHING_TO_INLINE") +// @JvmName("invokePolynomial") +// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..f1ad9a74f --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,689 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Polynomial model without fixation on specific context they are applied to. + * + * @param C the type of constants. + */ +public class NumberedPolynomial +internal constructor( + /** + * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as + * pair "key-value" in the map, where value is coefficients `a` and + * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring + * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, + * listOf(0, 1) to (-6), + * listOf(0, 1, 1) to 0, + * ) + * ``` + * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not + * contain any zeros on end, but can contain zeros on start or anywhere in middle. + */ + public val coefficients: Map, C> +) : AbstractPolynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +// region Internal utilities + +/** + * Represents internal [Polynomial] errors. + */ +internal class NumberedPolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +/** + * Returns the same degrees description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toMap(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(A) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) +// +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(coefs) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in coefs) { +// val key = entry.key.cleanUp() +// val value = entry.value +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) +// +// val fixedCoefs = mutableMapOf, C>() +// +// for (entry in pairs) { +// val key = entry.first.cleanUp() +// val value = entry.second +// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value +// } +// +// return NumberedPolynomial( +// fixedCoefs +// .filter { it.value.isNotZero() } +// ) +//} +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//@Suppress("FunctionName") +//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = +// NumberedPolynomial(pairs.toList(), toCheckInput) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param coefs Coefficients of the instants. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) +///** +// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received +// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. +// * +// * @param pairs Collection of pairs that represent monomials. +// * +// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) + +public fun > C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +// endregion + +/** + * Space of polynomials. + * + * @param C the type of operated polynomials. + * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. + * @param ring the [A] instance. + */ +@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") +public class NumberedPolynomialSpace>( + public val ring: A, +) : AbstractPolynomialSpace> { + // region Constant-integer relation + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Polynomial-integer relation + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomial( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Integer-polynomial relation + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomial( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Constant-constant relation + @JvmName("constantUnaryMinus") + override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + @JvmName("constantPlus") + override operator fun C.plus(other: C): C = ring { this@plus + other } + @JvmName("constantMinus") + override operator fun C.minus(other: C): C = ring { this@minus - other } + @JvmName("constantTimes") + override operator fun C.times(other: C): C = ring { this@times * other } + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this != zero } + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this != one } + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this != -one } + // endregion + + // region Constant-polynomial relation + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = this@plus + getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) -other + else with(other.coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to this@minus)) + else NumberedPolynomial( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + val result = this@minus - getOrElse(degs) { ring.zero } + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + if (this.isZero()) zero + else NumberedPolynomial( + other.coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> this@times * c } + } + ) + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } + other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns difference of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + else NumberedPolynomial( + toMutableMap() + .apply { + val degs = emptyList() + + val result = getOrElse(degs) { ring.zero } - other + + if (result.isZero()) remove(degs) + else this[degs] = result + } + ) + } + /** + * Returns product of the polynomials. [other] is interpreted as [NumberedPolynomial]. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + if (other.isZero()) zero + else NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + mapValues { (_, c) -> c * other } + } + ) + // endregion + + // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomial( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomial( + coefficients + .applyAndRemoveZeros { + other.coefficients + .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + when { + isZero() -> zero + other.isZero() -> zero + else -> + NumberedPolynomial( + buildCoefficients { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + } + + public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } + public override fun NumberedPolynomial.isNotZero(): Boolean = coefficients.values.any { it.isNotZero() } + public override fun NumberedPolynomial.isOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotOne()) return@with false + else foundAbsoluteTermAndItIsOne = true + } + } + foundAbsoluteTermAndItIsOne + } + public override fun NumberedPolynomial.isNotOne(): Boolean = !isOne() + public override fun NumberedPolynomial.isMinusOne(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsMinusOne = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isNotMinusOne()) return@with false + else foundAbsoluteTermAndItIsMinusOne = true + } + } + foundAbsoluteTermAndItIsMinusOne + } + public override fun NumberedPolynomial.isNotMinusOne(): Boolean = !isMinusOne() + + override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) + override val one: NumberedPolynomial = + NumberedPolynomial( + mapOf( + listOf() to ring.one // 1 * x_1^0 * x_2^0 * ... + ) + ) + + // TODO: Docs + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + override fun NumberedPolynomial.equals(other: NumberedPolynomial): Boolean = + when { + this === other -> true + else -> coefficients.size == other.coefficients.size && + coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } + } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0 else degs.size } ?: 0 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And size of the list is [countOfVariables]. + */ + public val NumberedPolynomial.degrees: List + get() = + buildList(countOfVariables) { + repeat(countOfVariables) { add(0U) } + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isConstant(): Boolean = + coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + override fun NumberedPolynomial.isNonZeroConstant(): Boolean = + with(coefficients) { + var foundAbsoluteTermAndItIsNotZero = false + for ((degs, c) in this) { + if (degs.isNotEmpty()) if (c.isNotZero()) return@with false + else { + if (c.isZero()) return@with false + else foundAbsoluteTermAndItIsNotZero = true + } + } + foundAbsoluteTermAndItIsNotZero + } + + override fun NumberedPolynomial.asConstantOrNull(): C? = + with(coefficients) { + if(isConstant()) getOrElse(emptyList()) { ring.zero } + else null + } + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } + + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) + // endregion + + // region Legacy + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun add(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left + right + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun multiply(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left * right + // endregion + + // region Utilities + // TODO: Move to region internal utilities with context receiver + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + return this + } + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + toMutableMap().applyAndRemoveZeros(block) + @OptIn(ExperimentalTypeInference::class) + internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } + // endregion +} \ No newline at end of file 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 30280a396..99d6b0659 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 @@ -5,43 +5,38 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedAddMultiplied -import space.kscience.kmath.functions.AbstractPolynomialSpace.Companion.optimizedMultiply import space.kscience.kmath.operations.* import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min /** - * Polynomial coefficients model without fixation on specific context they are applied to. + * Polynomial model without fixation on specific context they are applied to. * * @param coefficients constant is the leftmost coefficient. */ public class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" - -// public companion object { -// /** -// * Default name of variables used in string representations. -// * -// * @see Polynomial.toString -// */ -// public var defaultVariableName: String = "x" -// -// /** -// * Represents result of division with remainder. -// */ -// public data class DividingResult( -// val quotient: Polynomial, -// val reminder: Polynomial -// ) -// } } +// region Internal utilities + /** * Represents internal [Polynomial] errors. */ -internal class PolynomialError(message: String): Error(message) +internal class PolynomialError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [PolynomialError] with the given [message]. + */ +internal fun polynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) + +// endregion // region Constructors and converters @@ -66,16 +61,16 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) // endregion /** - * Space of polynomials constructed over ring. + * Space of univariate polynomials constructed over ring. * * @param C the type of constants. Polynomials have them as a coefficients in their terms. * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // KT-31420 +@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public val ring: A, -) : AbstractPolynomialSpace>{ +) : AbstractPolynomialSpace> { // region Constant-integer relation @JvmName("constantIntPlus") public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } @@ -102,8 +97,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + other - else this[0] = this[0]!! + other + val result = getOrElse(0) { ring.zero } + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.minus(other: Int): Polynomial = @@ -113,8 +114,14 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - other - else this[0] = this[0]!! - other + val result = getOrElse(0) { ring.zero } - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Polynomial.times(other: Int): Polynomial = @@ -134,8 +141,14 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero + this@plus - else this[0] = this[0]!! + this@plus + val result = this@plus + getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.minus(other: Polynomial): Polynomial = @@ -145,8 +158,16 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - if (isEmpty()) this[0] = ring.zero - this@minus - else this[0] = this[0]!! - this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = this@minus - getOrElse(0) { ring.zero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) public override operator fun Int.times(other: Polynomial): Polynomial = @@ -183,12 +204,20 @@ public open class PolynomialSpace>( // region Constant-polynomial relation public override operator fun C.plus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(this@plus)) else Polynomial( toMutableList() .apply { - this[0] += this@plus + val result = if (size == 0) this@plus else this@plus + get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -196,12 +225,22 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.minus(other: Polynomial): Polynomial = - with(other.coefficients) { + if (this.isZero()) other + else with(other.coefficients) { if (isEmpty()) Polynomial(listOf(-this@minus)) else Polynomial( toMutableList() .apply { - this[0] -= this@minus + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = if (size == 0) this@minus else this@minus - get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -209,9 +248,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun C.times(other: Polynomial): Polynomial = - Polynomial( + if (this.isZero()) other + else Polynomial( other.coefficients -// .subList(0, other.degree + 1) + .subList(0, other.degree + 1) .map { it * this } ) // endregion @@ -224,7 +264,14 @@ public open class PolynomialSpace>( else Polynomial( toMutableList() .apply { - this[0] += other + val result = if (size == 0) other else get(0) + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -232,12 +279,20 @@ public open class PolynomialSpace>( // listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.minus(other: C): Polynomial = - with(coefficients) { + if (other.isZero()) this + else with(coefficients) { if (isEmpty()) Polynomial(listOf(other)) else Polynomial( toMutableList() .apply { - this[0] -= other + val result = if (size == 0) other else get(0) - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } } ) } @@ -245,9 +300,10 @@ public open class PolynomialSpace>( // listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) // ) public override operator fun Polynomial.times(other: C): Polynomial = - Polynomial( + if (other.isZero()) this + else Polynomial( coefficients -// .subList(0, degree + 1) + .subList(0, degree + 1) .map { it * other } ) // endregion @@ -283,8 +339,8 @@ public open class PolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return when { - thisDegree == -1 -> this - otherDegree == -1 -> other + thisDegree == -1 -> zero + otherDegree == -1 -> zero else -> Polynomial( (0..(thisDegree + otherDegree)) @@ -293,6 +349,7 @@ public open class PolynomialSpace>( .map { coefficients[it] * other.coefficients[d - it] } .reduce { acc, rational -> acc + rational } } + .run { subList(0, indexOfLast { it.isNotZero() } + 1) } ) } } @@ -321,8 +378,8 @@ public open class PolynomialSpace>( } // endregion - // Not sure is it necessary... // region Polynomial properties + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } public override fun Polynomial.asConstantOrNull(): C? = @@ -354,8 +411,8 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) - // endregion + // endregion } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt new file mode 100644 index 000000000..410604fd3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt @@ -0,0 +1,38 @@ +package space.kscience.kmath.functions + +import kotlin.reflect.KProperty + + +/** + * Represents class of labeled variables like usual + * `x`, `y`, `z`, `a`, `b`, `n`, `m`, etc. + * + * Variables does not contain any information about field (or ring, ets.) they are considered in + * and therefore about coefficient. + * + * @property name Is the label or name of variable. For `x` it is `"x"`, for `n` – `"n"`, etc. + */ +public data class Variable (val name: String) : Comparable { + /** + * Represents the variable as a string. + * + * @return Only name of the variable. + */ + override fun toString(): String = name + /** + * Compares two variables. + * Comparison is realised by comparison of variables' names. + * + * Used in [LabeledPolynomial] and [LabeledRationalFunction] to sort monomials in + * [LabeledPolynomial.toString] and [LabeledRationalFunction.toString] in lexicographic order. + * + * @see Comparable.compareTo + * @sample LabeledPolynomial.monomialComparator + * @return Only name of the variable. + */ + override fun compareTo(other: Variable): Int = name.compareTo(other.name) + + public companion object { + public operator fun getValue(thisRef: Any?, property: KProperty<*>) : Variable = Variable(property.name) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt new file mode 100644 index 000000000..9e5043b8c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Group + + +// TODO: All of this should be moved to algebraic structures' place for utilities +// TODO: Move receiver to context receiver +/** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + */ +internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = + when { + other == 0 -> zero + other == 1 -> arg + other == -1 -> -arg + other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) + other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) + other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + } + +// 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. + * @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: Int): C = + when { + multiplier == 0 -> base + multiplier == 1 -> base + arg + multiplier == -1 -> base - arg + multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) + multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) + else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 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 new file mode 100644 index 000000000..62ac31b64 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt @@ -0,0 +1,490 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.* + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(LabeledPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(LabeledPolynomialSpace) +//fun > power(arg: C, pow: UInt): C = ring { power(arg, pow) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Variables +// +//context(LabeledPolynomialSpace) +//fun > power(arg: Variable, pow: UInt): LabeledPolynomial = +// if (pow == 0U) one +// else LabeledPolynomial(mapOf( +// mapOf(arg to pow) to ring.one +// )) +// +//// endregion + +//// region Polynomials +// +//context(LabeledPolynomialSpace) +//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } +// +//context(LabeledPolynomialSpace) +//fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(LabeledPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.represent(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = +// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representWithBrackets(namer: (Variable) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// val variableName = names.getOrDefault(variable, variable.toString()) +// when (deg) { +// 1U -> variableName +// else -> "$variableName^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversed(namer: (Variable) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .toSortedMap() +// .filter { it.value > 0U } +// .map { (variable, deg) -> +// when (deg) { +// 1U -> namer(variable) +// else -> "${namer(variable)}^$deg" +// } +// } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with +// * brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = +// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(LabeledPolynomialSpace) +//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Variable) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +//// region Polynomial substitution and functional representation +// +//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// LabeledPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.filterKeys { it !in args } +// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> +// multiplyWithPower(acc, args[variable]!!, deg) +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = +// ring.labeledPolynomial { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.entries +// .asSequence() +// .filter { it.key in arg } +// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> +// multiplyWithPower(acc, arg[index]!!, deg) +// } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = +// { substitute(ring, it) } +// +//// endregion + +//// region Algebraic derivative and antiderivative +//// TODO +//// endregion \ No newline at end of file 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 new file mode 100644 index 000000000..d4053442d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt @@ -0,0 +1,605 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.* +import kotlin.jvm.JvmName + + +// TODO: Docs + +// region Sort of legacy + +//// region Constants +// +//// TODO: Reuse underlying ring extensions +// +//context(NumberedPolynomialSpace) +//@Suppress("NOTHING_TO_INLINE") +//public fun > numberConstant(value: Int): C = ring { number(value) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } +// +//// endregion + +//// region Polynomials +// +//context(NumberedPolynomialSpace) +//public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } +// +//context(NumberedPolynomialSpace) +//public fun > multiplyWithPower(base: NumberedPolynomial, arg: NumberedPolynomial, pow: UInt): NumberedPolynomial = +// when { +// arg.isZero() && pow > 0U -> base +// arg.isOne() -> base +// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base +// else -> multiplyWithPowerInternalLogic(base, arg, pow) +// } +// +//// Trivial but slow as duck +//context(NumberedPolynomialSpace) +//internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = +// when { +// exponent == 0U -> base +// exponent == 1U -> base * arg +// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) +// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) +// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") +// } +// +//// endregion + +// endregion + +// region Utilities + +// TODO: Docs +@OptIn(ExperimentalContracts::class) +public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +// endregion + +//// region String representations +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = +// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> "${withVariableName}_${index+1}" +// else -> "${withVariableName}_${index+1}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer]. +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = +// coefficients.entries +// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } +// .asSequence() +// .map { (degs, t) -> +// if (degs.isEmpty()) "$t" +// else { +// when { +// t.isOne() -> "" +// t.isMinusOne() -> "-" +// else -> "$t " +// } + +// degs +// .mapIndexed { index, deg -> +// when (deg) { +// 0U -> "" +// 1U -> namer(index) +// else -> "${namer(index)}^$deg" +// } +// } +// .filter { it.isNotEmpty() } +// .joinToString(separator = " ") { it } +// } +// } +// .joinToString(separator = " + ") { it } +// .ifEmpty { "0" } +// +///** +// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` +// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = +// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } +// +///** +// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed +// * (i.e. when there are at least two addends in the representation). +// * Consider that monomials are sorted in **reversed** lexicographic order. +// */ +//context(NumberedPolynomialSpace) +//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = +// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } +// +//// endregion + +//// region Polynomial substitution and functional representation +// +//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { +// if (coefficients.isEmpty()) return this@substitute +// NumberedPolynomial( +// buildMap { +// coefficients.forEach { (degs, c) -> +// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() +// val newC = degs.foldIndexed(c) { index, acc, deg -> +// if (index in args) multiplyWithPower(acc, args[index]!!, deg) +// else acc +// } +// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC +// } +// } +// ) +//} +// +//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as +//// possible on it +//@JvmName("substitutePolynomial") +//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = +// ring.numberedPolynomialSpace { +// if (coefficients.isEmpty()) return zero +// coefficients +// .asSequence() +// .map { (degs, c) -> +// degs.foldIndexed( +// NumberedPolynomial( +// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c +// ) +// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } +// } +// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. +// } +// +//// TODO: Substitute rational function +// +//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = +// { substitute(ring, it) } +// +//// endregion + +// region Operator extensions + +//// region Field case +// +//operator fun > Polynomial.div(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(quotientCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(quotientCoefficients, toCheckInput = false) +//} +// +//operator fun > Polynomial.div(other: T): Polynomial = +// if (other.isZero()) throw ArithmeticException("/ by zero") +// else +// Polynomial( +// coefficients +// .mapValues { it.value / other }, +// toCheckInput = false +// ) +// +//operator fun > Polynomial.rem(other: Polynomial): Polynomial { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return this +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial(thisCoefficients, toCheckInput = false) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial(thisCoefficients, toCheckInput = false) +//} +// +//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { +// if (other.isZero()) throw ArithmeticException("/ by zero") +// if (isZero()) return Polynomial.Companion.DividingResult(this, this) +// +// fun Map, T>.leadingTerm() = +// this +// .asSequence() +// .map { Pair(it.key, it.value) } +// .reduce { (accDegs, accC), (listDegs, listC) -> +// for (i in 0..accDegs.lastIndex) { +// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC +// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC +// } +// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC +// } +// +// var thisCoefficients = coefficients.toMutableMap() +// val otherCoefficients = other.coefficients +// val quotientCoefficients = HashMap, T>() +// +// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() +// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() +// +// while ( +// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && +// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } +// ) { +// val multiplierDegs = +// thisLeadingTermDegs +// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } +// .cleanUp() +// val multiplierC = thisLeadingTermC / otherLeadingTermC +// +// quotientCoefficients[multiplierDegs] = multiplierC +// +// for ((degs, t) in otherCoefficients) { +// val productDegs = +// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) +// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } +// .cleanUp() +// val productC = t * multiplierC +// thisCoefficients[productDegs] = +// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC +// } +// +// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() +// +// if (thisCoefficients.isEmpty()) +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +// +// val t = thisCoefficients.leadingTerm() +// thisLeadingTermDegs = t.first +// thisLeadingTermC = t.second +// } +// +// return Polynomial.Companion.DividingResult( +// Polynomial(quotientCoefficients, toCheckInput = false), +// Polynomial(thisCoefficients, toCheckInput = false) +// ) +//} +// +//// endregion + +// endregion + +// region Polynomial substitution and functional representation + +// TODO: May be apply Horner's method too? +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + val acc = LinkedHashMap, Double>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitutor.pow(deg.toInt()) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +/** + * 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 NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + val acc = LinkedHashMap, C>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c + else acc[newDegs] = acc[newDegs]!! + c + } + return NumberedPolynomial(acc) +} + +// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed +// as soon as possible on it +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { + val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitutor) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitutor, deg) + } + if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() + else acc[newDegs] = acc[newDegs]!! + c + } +}*/ + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent the polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } + +// endregion + +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Ring, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun NumberedPolynomial.derivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Ring, A : NumericAlgebra = derivativeBy(algebra, variables.toIntArray()) + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variable: Int, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: IntArray, +): Polynomial where A : Field, A : NumericAlgebra = algebra { + TODO() +} + +/** + * Create a polynomial witch represents indefinite integral version of this polynomial + */ +@UnstableKMathAPI +public fun NumberedPolynomial.antiderivativeBy( + algebra: A, + variables: Collection, +): Polynomial where A : Field, A : NumericAlgebra = antiderivativeBy(algebra, variables.toIntArray()) + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 1a3eb7874..4d99b3a45 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 @@ -121,7 +121,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) + one)) } + coefficients.forEachIndexed{ index, t -> add(t / number(index + 1)) } } Polynomial(integratedCoefficients) } @@ -136,4 +136,6 @@ public fun > Polynomial.integrate( ): C = algebra { val integral = antiderivative(algebra) integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file +} + +// endregion \ No newline at end of file From 033edd3febfc36983a1fd6319941ba453531b6f5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 13 Mar 2022 03:55:51 +0300 Subject: [PATCH 010/174] Removed kotlin-js-store --- kotlin-js-store/yarn.lock | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 kotlin-js-store/yarn.lock diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock deleted file mode 100644 index e69de29bb..000000000 From de53d032afbe7da603b7bc7cc919718c0c193811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:14:24 +0300 Subject: [PATCH 011/174] 1. Prototyped Rational Functions 2. Added abstract interfaces for removing boilerplates 3. Changed or added default values in interfaces 4. Renamed non-operator `equals` to `equalsTo`, and made it infix --- .../kmath/functions/AbstractPolynomial.kt | 128 ++++- .../functions/AbstractRationalFunction.kt | 500 ++++++++++++++++-- .../kmath/functions/LabeledPolynomial.kt | 24 +- .../kmath/functions/NumberedPolynomial.kt | 74 +-- .../kscience/kmath/functions/Polynomial.kt | 51 +- .../kmath/functions/RationalFunction.kt | 355 +++++++++++++ .../kmath/functions/rationalFunctionUtil.kt | 34 ++ 7 files changed, 998 insertions(+), 168 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt 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 b7b7116f0..69c45798a 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 @@ -154,7 +154,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is NOT zero constant. */ @JvmName("constantIsNotZero") - public fun C.isNotZero(): Boolean + public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ @@ -164,7 +164,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is NOT unit constant. */ @JvmName("constantIsNotOne") - public fun C.isNotOne(): Boolean + public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ @@ -174,7 +174,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") - public fun C.isNotMinusOne(): Boolean + public fun C.isNotMinusOne(): Boolean = !isMinusOne() // endregion // region Constant-polynomial relation @@ -232,27 +232,27 @@ public interface AbstractPolynomialSpace> : Ring

/** * Check if the instant is zero polynomial. */ - public fun P.isZero(): Boolean = this == zero + public fun P.isZero(): Boolean = this equalsTo zero /** * Check if the instant is NOT zero polynomial. */ - public fun P.isNotZero(): Boolean = this != zero + public fun P.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit polynomial. */ - public fun P.isOne(): Boolean = this == one + public fun P.isOne(): Boolean = this equalsTo one /** * Check if the instant is NOT unit polynomial. */ - public fun P.isNotOne(): Boolean = this != one + public fun P.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit polynomial. */ - public fun P.isMinusOne(): Boolean = this == -one + public fun P.isMinusOne(): Boolean = this equalsTo -one /** * Check if the instant is NOT minus unit polynomial. */ - public fun P.isNotMinusOne(): Boolean = this != -one + public fun P.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero polynomial (zero of the polynomial ring). @@ -266,8 +266,11 @@ public interface AbstractPolynomialSpace> : Ring

/** * Checks equality of the polynomials. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public fun P.equals(other: P): Boolean + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) // endregion // Not sure is it necessary... @@ -310,4 +313,107 @@ public interface AbstractPolynomialSpace> : Ring

override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right // endregion +} + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { + + public val ring: A + + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(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]. + */ + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(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]. + */ + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(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]. + */ + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-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]. + */ + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Constant-constant relation + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this == zero } + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this == one } + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this == -one } + // endregion } \ No newline at end of file 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 34050aa0f..9725ea078 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 @@ -13,7 +13,12 @@ import kotlin.jvm.JvmName /** * Abstraction of rational function. */ -public interface AbstractRationalFunction> +public interface AbstractRationalFunction> { + public val numerator: P + public val denominator: P + public operator fun component1(): P = numerator + public operator fun component2(): P = denominator +} @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { @@ -190,7 +195,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is NOT zero constant. */ @JvmName("constantIsNotZero") - public fun C.isNotZero(): Boolean + public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ @@ -200,7 +205,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is NOT unit constant. */ @JvmName("constantIsNotOne") - public fun C.isNotOne(): Boolean + public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ @@ -210,7 +215,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") - public fun C.isNotMinusOne(): Boolean + public fun C.isNotMinusOne(): Boolean = !isMinusOne() // endregion // region Constant-polynomial relation @@ -268,42 +273,45 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero polynomial. */ - public fun P.isZero(): Boolean = this == zeroPolynomial + public fun P.isZero(): Boolean = this equalsTo polynomialZero /** * Check if the instant is NOT zero polynomial. */ - public fun P.isNotZero(): Boolean = this != zeroPolynomial + public fun P.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit polynomial. */ - public fun P.isOne(): Boolean = this == onePolynomial + public fun P.isOne(): Boolean = this equalsTo polynomialOne /** * Check if the instant is NOT unit polynomial. */ - public fun P.isNotOne(): Boolean = this != onePolynomial + public fun P.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit polynomial. */ - public fun P.isMinusOne(): Boolean = this == -onePolynomial + public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne /** * Check if the instant is NOT minus unit polynomial. */ - public fun P.isNotMinusOne(): Boolean = this != -onePolynomial + public fun P.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero polynomial (zero of the polynomial ring). */ - public val zeroPolynomial: P + public val polynomialZero: P /** * Instance of unit polynomial (unit of the polynomial ring). */ - public val onePolynomial: P + public val polynomialOne: P /** * Checks equality of the polynomials. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public fun P.equals(other: P): Boolean + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) // endregion // region Constant-rational relation @@ -391,27 +399,27 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero rational function. */ - public fun R.isZero(): Boolean = this == zero + public fun R.isZero(): Boolean = this equalsTo zero /** * Check if the instant is NOT zero rational function. */ - public fun R.isNotZero(): Boolean = this != zero + public fun R.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit rational function. */ - public fun R.isOne(): Boolean = this == one + public fun R.isOne(): Boolean = this equalsTo one /** * Check if the instant is NOT unit rational function. */ - public fun R.isNotOne(): Boolean = this != one + public fun R.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit rational function. */ - public fun R.isMinusOne(): Boolean = this == -one + public fun R.isMinusOne(): Boolean = this equalsTo -one /** * Check if the instant is NOT minus unit rational function. */ - public fun R.isNotMinusOne(): Boolean = this != -one + public fun R.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero rational function (zero of the rational functions ring). @@ -425,8 +433,11 @@ public interface AbstractRationalFunctionalSpace, R: /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public fun R.equals(other: R): Boolean + public infix fun R.equalsTo(other: R): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) // endregion // Not sure is it necessary... @@ -453,35 +464,31 @@ public interface AbstractRationalFunctionalSpace, R: * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. */ public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ public fun P.asConstantOrNull(): C? - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") // endregion // Not sure is it necessary... - // region Polynomial properties + // region Rational properties /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. */ - public fun R.isConstant(): Boolean + public val R.numeratorDegree: Int get() = numerator.degree /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. */ - public fun R.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun R.isNonZeroConstant(): Boolean - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun R.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - - public fun R.asConstantOrNull(): C? - - public fun R.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + public val R.denominatorDegree: Int get() = denominator.degree // TODO: Перенести в реализацию // fun R.substitute(argument: C): C @@ -501,5 +508,416 @@ public interface AbstractRationalFunctionalSpace, R: // region Legacy override fun add(left: R, right: R): R = left + right override fun multiply(left: R, right: R): R = left * right + // endregion +} + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { + + public val ring: A + + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(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]. + */ + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(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]. + */ + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(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]. + */ + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-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]. + */ + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = ring { this@isZero.isZero() } + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = ring { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = ring { this@isOne.isOne() } + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = ring { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = ring { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = ring { this@isNotMinusOne.isNotMinusOne() } + // endregion +} + +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface AbstractRationalFunctionalSpaceOverPolynomialSpace, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { + + public val polynomialRing: AbstractPolynomialSpace + + // region Constant-integer relation + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + @JvmName("constantIntPlus") + public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + 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]. + */ + @JvmName("constantIntMinus") + public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - 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]. + */ + @JvmName("constantIntTimes") + public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } + // endregion + + // region Integer-constant relation + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + @JvmName("intConstantPlus") + public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } + /** + * 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]. + */ + @JvmName("intConstantMinus") + public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } + /** + * 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]. + */ + @JvmName("intConstantTimes") + public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } + // endregion + + // region Polynomial-integer relation + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } + // endregion + + // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } + // endregion + + // region Constant-constant relation + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + @JsName("constantTimes") + public override operator fun C.times(other: C): C = polynomialRing { this@times * other } + + /** + * Check if the instant is zero constant. + */ + @JvmName("constantIsZero") + public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero constant. + */ + @JvmName("constantIsNotZero") + public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit constant. + */ + @JvmName("constantIsOne") + public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit constant. + */ + @JvmName("constantIsNotOne") + public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit constant. + */ + @JvmName("constantIsMinusOne") + public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit constant. + */ + @JvmName("constantIsNotMinusOne") + public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + // endregion + + // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.times(other: P): P = polynomialRing { this@times * other } + // endregion + + // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.times(other: C): P = polynomialRing { this@times * other } + // endregion + + // region Polynomial-polynomial relation + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P = polynomialRing { this@times * other } + + /** + * Check if the instant is zero polynomial. + */ + public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero polynomial. + */ + public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit polynomial. + */ + public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit polynomial. + */ + public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit polynomial. + */ + public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit polynomial. + */ + public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public override val polynomialZero: P get() = polynomialRing.zero + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public override val polynomialOne: P get() = polynomialRing.one + + /** + * Checks equality of the polynomials. + */ + public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } + /** + * Checks NOT equality of the polynomials. + */ + public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } + // endregion + + // Not sure is it necessary... + // region Polynomial properties + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val P.degree: Int get() = polynomialRing { this@degree.degree } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } + // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 48f6f57fa..cbd713d27 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -13,7 +13,7 @@ import kotlin.math.max * * @param C Ring in which the polynomial is considered. */ -public class LabeledPolynomial +public data class LabeledPolynomial internal constructor( /** * Map that collects coefficients of the polynomial. Every non-zero monomial @@ -788,7 +788,7 @@ public class LabeledPolynomialSpace>( isZero() -> zero other.isZero() -> zero else -> LabeledPolynomial( - buildCoefficients { + buildCoefficients(coefficients.size * other.coefficients.size) { for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { val degs = degs1.toMutableMap() degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } @@ -804,7 +804,7 @@ public class LabeledPolynomialSpace>( // TODO: Docs @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - override fun LabeledPolynomial.equals(other: LabeledPolynomial): Boolean = + override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = when { this === other -> true else -> coefficients.size == other.coefficients.size && @@ -896,15 +896,9 @@ public class LabeledPolynomialSpace>( // public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) // endregion - // region Legacy - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun add(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left + right - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun multiply(left: LabeledPolynomial, right: LabeledPolynomial): LabeledPolynomial = left * right - // endregion - // region Utilities // TODO: Move to region internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) @@ -916,12 +910,20 @@ public class LabeledPolynomialSpace>( internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = toMutableMap().applyAndRemoveZeros(block) @OptIn(ExperimentalTypeInference::class) - internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap { builderAction() for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap(capacity) { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index f1ad9a74f..f11338161 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -13,7 +13,7 @@ import kotlin.math.max * * @param C the type of constants. */ -public class NumberedPolynomial +public data class NumberedPolynomial internal constructor( /** * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as @@ -259,27 +259,9 @@ public fun > C.asNumberedPolynomial() : NumberedPolynomial = Nu * @param ring the [A] instance. */ @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") -public class NumberedPolynomialSpace>( - public val ring: A, -) : AbstractPolynomialSpace> { - // region Constant-integer relation - @JvmName("constantIntPlus") - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } - @JvmName("constantIntMinus") - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } - @JvmName("constantIntTimes") - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } - // endregion - - // region Integer-constant relation - @JvmName("intConstantPlus") - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } - @JvmName("intConstantMinus") - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } - @JvmName("intConstantTimes") - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } - // endregion - +public open class NumberedPolynomialSpace>( + public final override val ring: A, +) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = if (other == 0) this @@ -362,29 +344,6 @@ public class NumberedPolynomialSpace>( ) // endregion - // region Constant-constant relation - @JvmName("constantUnaryMinus") - override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - @JvmName("constantPlus") - override operator fun C.plus(other: C): C = ring { this@plus + other } - @JvmName("constantMinus") - override operator fun C.minus(other: C): C = ring { this@minus - other } - @JvmName("constantTimes") - override operator fun C.times(other: C): C = ring { this@times * other } - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } - @JvmName("constantIsNotZero") - public override fun C.isNotZero(): Boolean = ring { this != zero } - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - @JvmName("constantIsNotOne") - public override fun C.isNotOne(): Boolean = ring { this != one } - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } - @JvmName("constantIsNotMinusOne") - public override fun C.isNotMinusOne(): Boolean = ring { this != -one } - // endregion - // region Constant-polynomial relation override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) other @@ -521,7 +480,7 @@ public class NumberedPolynomialSpace>( other.isZero() -> zero else -> NumberedPolynomial( - buildCoefficients { + buildCoefficients(coefficients.size * other.coefficients.size) { for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { val degs = (0..max(degs1.lastIndex, degs2.lastIndex)) @@ -534,7 +493,6 @@ public class NumberedPolynomialSpace>( } public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } - public override fun NumberedPolynomial.isNotZero(): Boolean = coefficients.values.any { it.isNotZero() } public override fun NumberedPolynomial.isOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsOne = false @@ -547,7 +505,6 @@ public class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsOne } - public override fun NumberedPolynomial.isNotOne(): Boolean = !isOne() public override fun NumberedPolynomial.isMinusOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsMinusOne = false @@ -560,7 +517,6 @@ public class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsMinusOne } - public override fun NumberedPolynomial.isNotMinusOne(): Boolean = !isMinusOne() override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) override val one: NumberedPolynomial = @@ -572,7 +528,7 @@ public class NumberedPolynomialSpace>( // TODO: Docs @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - override fun NumberedPolynomial.equals(other: NumberedPolynomial): Boolean = + override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = when { this === other -> true else -> coefficients.size == other.coefficients.size && @@ -658,15 +614,9 @@ public class NumberedPolynomialSpace>( public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) // endregion - // region Legacy - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun add(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left + right - @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") - override inline fun multiply(left: NumberedPolynomial, right: NumberedPolynomial): NumberedPolynomial = left * right - // endregion - // region Utilities // TODO: Move to region internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) @@ -678,12 +628,20 @@ public class NumberedPolynomialSpace>( internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = toMutableMap().applyAndRemoveZeros(block) @OptIn(ExperimentalTypeInference::class) - internal fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap { builderAction() for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildMap(capacity) { + builderAction() + for ((degs, c) in this) if (c.isZero()) this.remove(degs) + } + } // endregion } \ No newline at end of file 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 99d6b0659..2c764f4f5 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 @@ -15,7 +15,7 @@ import kotlin.math.min * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) : AbstractPolynomial { +public data class Polynomial(public val coefficients: List) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" } @@ -69,25 +69,8 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) */ @Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( - public val ring: A, -) : AbstractPolynomialSpace> { - // region Constant-integer relation - @JvmName("constantIntPlus") - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } - @JvmName("constantIntMinus") - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } - @JvmName("constantIntTimes") - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } - // endregion - - // region Integer-constant relation - @JvmName("intConstantPlus") - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } - @JvmName("intConstantMinus") - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } - @JvmName("intConstantTimes") - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } - // endregion + public final override val ring: A, +) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation public override operator fun Polynomial.plus(other: Int): Polynomial = @@ -179,29 +162,6 @@ public open class PolynomialSpace>( ) // endregion - // region Constant-constant relation - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = ring { this@times * other } - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } - @JvmName("constantIsNotZero") - public override fun C.isNotZero(): Boolean = ring { this != zero } - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - @JvmName("constantIsNotOne") - public override fun C.isNotOne(): Boolean = ring { this != one } - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } - @JvmName("constantIsNotMinusOne") - public override fun C.isNotMinusOne(): Boolean = ring { this != -one } - // endregion - // region Constant-polynomial relation public override operator fun C.plus(other: Polynomial): Polynomial = if (this.isZero()) other @@ -355,19 +315,16 @@ public open class PolynomialSpace>( } public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } - public override fun Polynomial.isNotZero(): Boolean = coefficients.any { it.isNotZero() } 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? - public override fun Polynomial.isNotOne(): Boolean = !isOne() 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? - public override fun Polynomial.isNotMinusOne(): Boolean = !isMinusOne() override val zero: Polynomial = Polynomial(emptyList()) override val one: Polynomial = Polynomial(listOf(ring.one)) @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") - public override fun Polynomial.equals(other: Polynomial): Boolean = + public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true else -> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt new file mode 100644 index 000000000..778ffb895 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -0,0 +1,355 @@ +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + + +public data class RationalFunction internal constructor ( + public override val numerator: Polynomial, + public override val denominator: Polynomial +) : AbstractRationalFunction> { + override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// region Internal utilities + +/** + * Represents internal [RationalFunction] errors. + */ +internal class RationalFunctionError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [RationalFunction] with the given [message]. + */ +internal fun rationalFunctionError(message: Any): Nothing = throw RationalFunctionError(message.toString()) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +// endregion + +public class RationalFunctionSpace> ( + public val ring: A, +) : AbstractRationalFunctionalSpaceOverPolynomialSpace, RationalFunction, A> { + + override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun RationalFunction.plus(other: Int): RationalFunction = + RationalFunction( + numerator + denominator * other, + denominator + ) + /** + * 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 override operator fun RationalFunction.minus(other: Int): RationalFunction = + RationalFunction( + numerator - denominator * other, + denominator + ) + /** + * 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 override operator fun RationalFunction.times(other: Int): RationalFunction = + RationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: RationalFunction): RationalFunction = TODO() + /** + * 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 override operator fun Int.minus(other: RationalFunction): RationalFunction = TODO() + /** + * 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 override operator fun Int.times(other: RationalFunction): RationalFunction = TODO() + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: RationalFunction): RationalFunction = TODO() + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun RationalFunction.plus(other: C): RationalFunction = + RationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun RationalFunction.minus(other: C): RationalFunction = + RationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun RationalFunction.times(other: C): RationalFunction = + RationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = TODO() + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = TODO() + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun RationalFunction.plus(other: Polynomial): RationalFunction = + RationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun RationalFunction.minus(other: Polynomial): RationalFunction = + RationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun RationalFunction.times(other: Polynomial): RationalFunction = + RationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Rational-rational relation + /** + * Returns negation of the rational function. + */ + public override operator fun RationalFunction.unaryMinus(): RationalFunction = RationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun RationalFunction.plus(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun RationalFunction.minus(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun RationalFunction.times(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Check if the instant is zero rational function. + */ + public override fun RationalFunction.isZero(): Boolean = numerator.isZero() + /** + * Check if the instant is unit rational function. + */ + public override fun RationalFunction.isOne(): Boolean = numerator.equalsTo(denominator) + /** + * Check if the instant is minus unit rational function. + */ + public override fun RationalFunction.isMinusOne(): Boolean = (numerator + denominator).isZero() + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: RationalFunction = RationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: RationalFunction = RationalFunction(polynomialOne, polynomialOne) + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override infix fun RationalFunction.equalsTo(other: RationalFunction): Boolean = + when { + this === other -> true + numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false + else -> numerator * other.denominator equalsTo other.numerator * denominator + } + // endregion + + // region REST TODO: Разобрать + + public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = + RationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun RationalFunction.div(other: Polynomial): RationalFunction = + RationalFunction( + numerator, + denominator * other + ) + + public operator fun RationalFunction.div(other: C): RationalFunction = + RationalFunction( + numerator, + denominator * other + ) + + public operator fun RationalFunction.div(other: Int): RationalFunction = + RationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = +// RationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// operator fun invoke(arg: RationalFunction): RationalFunction { +// val num = numerator invokeRFTakeNumerator arg +// val den = denominator invokeRFTakeNumerator arg +// val degreeDif = numeratorDegree - denominatorDegree +// return if (degreeDif > 0) +// RationalFunction( +// num, +// multiplyByPower(den, arg.denominator, degreeDif) +// ) +// else +// RationalFunction( +// multiplyByPower(num, arg.denominator, -degreeDif), +// den +// ) +// } +// +// override fun toString(): String = toString(UnivariatePolynomial.variableName) +// +// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(withVariableName) +// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" +// } +// +// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) +// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" +// } +// +// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(withVariableName) +// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" +// } +// +// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) +// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" +// } +// +// fun removeZeros() = +// RationalFunction( +// numerator.removeZeros(), +// denominator.removeZeros() +// ) + // endregion +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt new file mode 100644 index 000000000..9147bc023 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -0,0 +1,34 @@ +package space.kscience.kmath.functions + + +// region Operator extensions + +// region Field case + +//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) +// +//fun > RationalFunction.reduced(): RationalFunction = +// polynomialGCD(numerator, denominator).let { +// RationalFunction( +// numerator / it, +// denominator / it +// ) +// } + +// endregion + +// endregion + +// region Derivatives +///** +// * Returns result of applying formal derivative to the polynomial. +// * +// * @param T Field where we are working now. +// * @return Result of the operator. +// */ +//fun > RationalFunction.derivative() = +// RationalFunction( +// numerator.derivative() * denominator - denominator.derivative() * numerator, +// denominator * denominator +// ) +// endregion \ No newline at end of file From 07f4b83722e2b509f79a212612a952d8a0d64eba Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:18:15 +0300 Subject: [PATCH 012/174] Fixed forgotten TODOs --- .../kmath/functions/RationalFunction.kt | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 778ffb895..78ca556db 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -105,34 +105,58 @@ public class RationalFunctionSpace> ( * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public override operator fun Int.plus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Int.plus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) /** * 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 override operator fun Int.minus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Int.minus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) /** * 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 override operator fun Int.times(other: RationalFunction): RationalFunction = TODO() + public override operator fun Int.times(other: RationalFunction): RationalFunction = + RationalFunction( + this * other.numerator, + other.denominator + ) // endregion // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ - public override operator fun C.plus(other: RationalFunction): RationalFunction = TODO() + public override operator fun C.plus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) /** * Returns difference between the constant represented as polynomial and the rational function. */ - public override operator fun C.minus(other: RationalFunction): RationalFunction = TODO() + public override operator fun C.minus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) /** * Returns product of the constant represented as polynomial and the rational function. */ - public override operator fun C.times(other: RationalFunction): RationalFunction = TODO() + public override operator fun C.times(other: RationalFunction): RationalFunction = + RationalFunction( + this * other.numerator, + other.denominator + ) // endregion // region Rational-constant relation @@ -166,15 +190,27 @@ public class RationalFunctionSpace> ( /** * Returns sum of the polynomial represented as rational function and the rational function. */ - public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) /** * Returns difference between the polynomial represented as polynomial and the rational function. */ - public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = TODO() + public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = + RationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) /** * Returns product of the polynomial represented as polynomial and the rational function. */ - public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = TODO() + public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = + RationalFunction( + this * other.numerator, + other.denominator + ) // endregion // region Rational-polynomial relation From dd820da76579f93e24dcf8cf4216890f04931515 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 19:59:53 +0300 Subject: [PATCH 013/174] 1. Prototyped rest 2 algebraic structures of rational functions 2. Added `constantZero` and `constantOne` to abstract spaces and applied them instead of `ring.zero` and `ring.one` 3. Moved logic of `R.isZero` and 5 others to `AbstractRationalFunctionalSpace` 4. Deleted forgotten overridden functions of constants 5. Added KMath contributors' copyright notes 6. Added TODO :smile: The `NumberedPolynomial`'s `countOfVariables` is a confusing --- .../kmath/functions/AbstractPolynomial.kt | 30 +- .../functions/AbstractRationalFunction.kt | 60 ++- .../kmath/functions/LabeledPolynomial.kt | 147 +++--- .../functions/LabeledRationalFunction.kt | 464 ++++++++++++++++++ .../kmath/functions/NumberedPolynomial.kt | 26 +- .../functions/NumberedRationalFunction.kt | 453 +++++++++++++++++ .../kscience/kmath/functions/Polynomial.kt | 18 +- .../kmath/functions/RationalFunction.kt | 18 +- .../kmath/functions/labeledPolynomialUtil.kt | 7 +- .../functions/labeledRationalFunctionUtil.kt | 130 +++++ .../functions/numberedRationalFunctionUtil.kt | 23 + .../kmath/functions/rationalFunctionUtil.kt | 5 + 12 files changed, 1211 insertions(+), 170 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt 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 69c45798a..0ca2d1409 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 @@ -149,7 +149,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is zero constant. */ @JvmName("constantIsZero") - public fun C.isZero(): Boolean + public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ @@ -159,7 +159,7 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is unit constant. */ @JvmName("constantIsOne") - public fun C.isOne(): Boolean + public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ @@ -169,12 +169,21 @@ public interface AbstractPolynomialSpace> : Ring

* Check if the instant is minus unit constant. */ @JvmName("constantIsMinusOne") - public fun C.isMinusOne(): Boolean + public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C // endregion // region Constant-polynomial relation @@ -401,19 +410,12 @@ public interface AbstractPolynomialSpaceOverRing, A: public override operator fun C.times(other: C): C = ring { this@times * other } /** - * Check if the instant is zero constant. + * Instance of zero constant (zero of the underlying ring). */ - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } + public override val constantZero: C get() = ring.zero /** - * Check if the instant is unit constant. + * Instance of unit constant (unit of the underlying ring). */ - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - /** - * Check if the instant is minus unit constant. - */ - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } + public override val constantOne: C get() = ring.one // endregion } \ No newline at end of file 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 9725ea078..df366f90f 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 @@ -190,7 +190,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is zero constant. */ @JvmName("constantIsZero") - public fun C.isZero(): Boolean + public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ @@ -200,7 +200,7 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is unit constant. */ @JvmName("constantIsOne") - public fun C.isOne(): Boolean + public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ @@ -210,12 +210,21 @@ public interface AbstractRationalFunctionalSpace, R: * Check if the instant is minus unit constant. */ @JvmName("constantIsMinusOne") - public fun C.isMinusOne(): Boolean + public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C // endregion // region Constant-polynomial relation @@ -399,7 +408,7 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero rational function. */ - public fun R.isZero(): Boolean = this equalsTo zero + public fun R.isZero(): Boolean = numerator equalsTo polynomialZero /** * Check if the instant is NOT zero rational function. */ @@ -407,7 +416,7 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is unit rational function. */ - public fun R.isOne(): Boolean = this equalsTo one + public fun R.isOne(): Boolean = numerator equalsTo denominator /** * Check if the instant is NOT unit rational function. */ @@ -415,7 +424,7 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is minus unit rational function. */ - public fun R.isMinusOne(): Boolean = this equalsTo -one + public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() /** * Check if the instant is NOT minus unit rational function. */ @@ -597,35 +606,13 @@ public interface AbstractRationalFunctionalSpaceOverRing.cleanUp() = filterValues { it > 0U } //fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) // //context(LabeledPolynomialSpace) -//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to ring.one)) +//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to constantOne)) // //context(A) //fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = @@ -328,71 +333,54 @@ internal fun Map.cleanUp() = filterValues { it > 0U } */ @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") public class LabeledPolynomialSpace>( - public val ring: A, -) : AbstractPolynomialSpace> { - // region Constant-integer relation - @JvmName("constantIntPlus") - public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(this@plus, one, other) } - @JvmName("constantIntMinus") - public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(this@minus, one, -other) } - @JvmName("constantIntTimes") - public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } - // endregion - - // region Integer-constant relation - @JvmName("intConstantPlus") - public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(other, one, this@plus) } - @JvmName("intConstantMinus") - public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-other, one, this@minus) } - @JvmName("intConstantTimes") - public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } - // endregion + public override val ring: A, +) : AbstractPolynomialSpaceOverRing, A> { // region Variable-integer relation public operator fun Variable.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, + mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, - emptyMap() to ring.one * other, + mapOf(this@plus to 1U) to constantOne, + emptyMap() to constantOne * other, )) public operator fun Variable.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, + mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, - emptyMap() to ring.one * other, + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to constantOne * other, )) public operator fun Variable.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one * other, + mapOf(this to 1U) to constantOne * other, )) // endregion // region Integer-variable relation public operator fun Int.plus(other: Variable): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, + mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, - emptyMap() to ring.one * this@plus, + mapOf(other to 1U) to constantOne, + emptyMap() to constantOne * this@plus, )) public operator fun Int.minus(other: Variable): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, + mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, - emptyMap() to ring.one * this@minus, + mapOf(other to 1U) to -constantOne, + emptyMap() to constantOne * this@minus, )) public operator fun Int.times(other: Variable): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one * this@times, + mapOf(other to 1U) to constantOne * this@times, )) // endregion @@ -406,7 +394,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -421,7 +409,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -447,7 +435,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -462,7 +450,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -478,44 +466,21 @@ public class LabeledPolynomialSpace>( ) // endregion - // region Constant-constant relation - @JvmName("constantUnaryMinus") - override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - @JvmName("constantPlus") - override operator fun C.plus(other: C): C = ring { this@plus + other } - @JvmName("constantMinus") - override operator fun C.minus(other: C): C = ring { this@minus - other } - @JvmName("constantTimes") - override operator fun C.times(other: C): C = ring { this@times * other } - @JvmName("constantIsZero") - public override fun C.isZero(): Boolean = ring { this == zero } - @JvmName("constantIsNotZero") - public override fun C.isNotZero(): Boolean = ring { this != zero } - @JvmName("constantIsOne") - public override fun C.isOne(): Boolean = ring { this == one } - @JvmName("constantIsNotOne") - public override fun C.isNotOne(): Boolean = ring { this != one } - @JvmName("constantIsMinusOne") - public override fun C.isMinusOne(): Boolean = ring { this == -one } - @JvmName("constantIsNotMinusOne") - public override fun C.isNotMinusOne(): Boolean = ring { this != -one } - // endregion - // region Constant-variable relation public operator fun C.plus(other: Variable): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, + mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to ring.one, + mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) public operator fun C.minus(other: Variable): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, + mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -ring.one, + mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) public operator fun C.times(other: Variable): LabeledPolynomial = @@ -528,18 +493,18 @@ public class LabeledPolynomialSpace>( // region Variable-constant relation public operator fun Variable.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, + mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to ring.one, + mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) public operator fun Variable.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, + mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -ring.one, + mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) public operator fun Variable.times(other: C): LabeledPolynomial = @@ -559,7 +524,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -577,7 +542,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -607,7 +572,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -628,7 +593,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -651,37 +616,37 @@ public class LabeledPolynomialSpace>( // region Variable-variable relation public operator fun Variable.plus(other: Variable): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one * 2 + mapOf(this to 1U) to constantOne * 2 )) else LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one, - mapOf(other to 1U) to ring.one, + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to constantOne, )) public operator fun Variable.minus(other: Variable): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( - mapOf(this to 1U) to ring.one, - mapOf(other to 1U) to -ring.one, + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to -constantOne, )) public operator fun Variable.times(other: Variable): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to ring.one + mapOf(this to 2U) to constantOne )) else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to ring.one, + mapOf(this to 1U, other to 1U) to constantOne, )) // endregion // region Variable-polynomial relation public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { val degs = mapOf(this@plus to 1U) - val result = ring.one + getOrElse(degs) { ring.zero } + val result = constantOne + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -690,7 +655,7 @@ public class LabeledPolynomialSpace>( } public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { @@ -698,7 +663,7 @@ public class LabeledPolynomialSpace>( val degs = mapOf(this@minus to 1U) - val result = ring.one - getOrElse(degs) { ring.zero } + val result = constantOne - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -715,13 +680,13 @@ public class LabeledPolynomialSpace>( // region Polynomial-variable relation public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { val degs = mapOf(other to 1U) - val result = ring.one + getOrElse(degs) { ring.zero } + val result = constantOne + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -730,13 +695,13 @@ public class LabeledPolynomialSpace>( } public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to ring.one)) + if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( toMutableMap() .apply { val degs = mapOf(other to 1U) - val result = ring.one - getOrElse(degs) { ring.zero } + val result = constantOne - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -799,8 +764,8 @@ public class LabeledPolynomialSpace>( ) } - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.zero)) - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to ring.one)) + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) // TODO: Docs @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") @@ -872,7 +837,7 @@ public class LabeledPolynomialSpace>( override fun LabeledPolynomial.asConstantOrNull(): C? = with(coefficients) { - if(isConstant()) getOrElse(emptyMap()) { ring.zero } + if(isConstant()) getOrElse(emptyMap()) { constantZero } else null } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt new file mode 100644 index 000000000..203c9e07c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -0,0 +1,464 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke + + +public class LabeledRationalFunction( + public override val numerator: LabeledPolynomial, + public override val denominator: LabeledPolynomial +) : AbstractRationalFunction> { + override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// region Internal utilities + +/** + * Represents internal [LabeledRationalFunction] errors. + */ +internal class LabeledRationalFunctionError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [LabeledRationalFunctionError] with the given [message]. + */ +internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString()) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +// TODO: Rewrite former constructors as fabrics +//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( +//LabeledPolynomial(numeratorCoefficients), +//LabeledPolynomial(denominatorCoefficients) +//) +// +//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( +//LabeledPolynomial(numeratorCoefficients), +//LabeledPolynomial(denominatorCoefficients) +//) +// +//constructor(numerator: LabeledPolynomial) : this(numerator, numerator.getOne()) +//constructor(numeratorCoefficients: Map, C>) : this( +//LabeledPolynomial(numeratorCoefficients) +//) +// +//constructor(numeratorCoefficients: Collection, C>>) : this( +//LabeledPolynomial(numeratorCoefficients) +//) + +// endregion + +public class LabeledRationalFunctionSpace>( + public val ring: A, +) : AbstractRationalFunctionalSpaceOverPolynomialSpace, LabeledRationalFunction, A> { + + override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun LabeledRationalFunction.plus(other: Int): LabeledRationalFunction = + LabeledRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * 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 override operator fun LabeledRationalFunction.minus(other: Int): LabeledRationalFunction = + LabeledRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * 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 override operator fun LabeledRationalFunction.times(other: Int): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.plus(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.minus(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.times(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledPolynomial.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun LabeledPolynomial.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun LabeledPolynomial.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.plus(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.minus(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun LabeledRationalFunction.times(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Rational-rational relation + /** + * Returns negation of the rational function. + */ + public override operator fun LabeledRationalFunction.unaryMinus(): LabeledRationalFunction = LabeledRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun LabeledRationalFunction.plus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun LabeledRationalFunction.minus(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun LabeledRationalFunction.times(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { + if (this === other) return true + + if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + + val variables = this.variables union other.variables + val thisNumeratorDegrees = this.numerator.degrees + val thisDenominatorDegrees = this.denominator.degrees + val otherNumeratorDegrees = other.numerator.degrees + val otherDenominatorDegrees = other.denominator.degrees + for (variable in variables) + if ( + thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } + != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } + ) return false + + return numerator * other.denominator equalsTo other.numerator * denominator + } + // endregion + + // region Polynomial properties + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + // endregion + + // region Rational properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledRationalFunction.variables: Set + get() = numerator.variables union denominator.variables + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val LabeledRationalFunction.countOfVariables: Int get() = variables.size + // endregion + + // region REST TODO: Разобрать + + public operator fun LabeledRationalFunction.div(other: LabeledRationalFunction): LabeledRationalFunction = + LabeledRationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun LabeledRationalFunction.div(other: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction( + numerator, + denominator * other + ) + + public operator fun LabeledRationalFunction.div(other: C): LabeledRationalFunction = + LabeledRationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: Map): LabeledRationalFunction = +// LabeledRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokeLabeledPolynomial") +// operator fun invoke(arg: Map>): LabeledRationalFunction = +// LabeledRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokeLabeledRationalFunction") +// operator fun invoke(arg: Map>): LabeledRationalFunction { +// var num = numerator invokeRFTakeNumerator arg +// var den = denominator invokeRFTakeNumerator arg +// for (variable in variables) if (variable in arg) { +// val degreeDif = degrees[variable]!! +// if (degreeDif > 0) +// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) +// else +// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) +// } +// return LabeledRationalFunction(num, den) +// } +// +// override fun toString(): String = toString(emptyMap()) +// +// fun toString(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(names) +// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" +// } +// +// fun toString(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(namer) +// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" +// } +// +// fun toStringWithBrackets(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(names) +// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" +// } +// +// fun toStringWithBrackets(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(namer) +// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" +// } +// +// fun toReversedString(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(names) +// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" +// } +// +// fun toReversedString(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(namer) +// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" +// } +// +// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) +// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" +// } +// +// fun toReversedStringWithBrackets(namer: (Variable) -> String): String = +// when (true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) +// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" +// } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index f11338161..39ca43945 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.functions import space.kscience.kmath.operations.* @@ -272,7 +277,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -287,7 +292,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -313,7 +318,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -328,7 +333,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -354,7 +359,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { ring.zero } + val result = this@plus + getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -372,7 +377,7 @@ public open class NumberedPolynomialSpace>( val degs = emptyList() - val result = this@minus - getOrElse(degs) { ring.zero } + val result = this@minus - getOrElse(degs) { constantZero } if (result.isZero()) remove(degs) else this[degs] = result @@ -402,7 +407,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } + other + val result = getOrElse(degs) { constantZero } + other if (result.isZero()) remove(degs) else this[degs] = result @@ -421,7 +426,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { ring.zero } - other + val result = getOrElse(degs) { constantZero } - other if (result.isZero()) remove(degs) else this[degs] = result @@ -522,7 +527,7 @@ public open class NumberedPolynomialSpace>( override val one: NumberedPolynomial = NumberedPolynomial( mapOf( - listOf() to ring.one // 1 * x_1^0 * x_2^0 * ... + listOf() to constantOne // 1 * x_1^0 * x_2^0 * ... ) ) @@ -538,6 +543,7 @@ public open class NumberedPolynomialSpace>( // Not sure is it necessary... // region Polynomial properties + // TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables` /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -590,7 +596,7 @@ public open class NumberedPolynomialSpace>( override fun NumberedPolynomial.asConstantOrNull(): C? = with(coefficients) { - if(isConstant()) getOrElse(emptyList()) { ring.zero } + if(isConstant()) getOrElse(emptyList()) { constantZero } else null } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt new file mode 100644 index 000000000..aff18d1f4 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -0,0 +1,453 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.math.max + + +public class NumberedRationalFunction internal constructor( + public override val numerator: NumberedPolynomial, + public override val denominator: NumberedPolynomial +) : AbstractRationalFunction> { + override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// region Internal utilities + +/** + * Represents internal [NumberedRationalFunction] errors. + */ +internal class NumberedRationalFunctionError : Error { + constructor(): super() + constructor(message: String): super(message) + constructor(message: String?, cause: Throwable?): super(message, cause) + constructor(cause: Throwable?): super(cause) +} + +/** + * Throws an [NumberedRationalFunctionError] with the given [message]. + */ +internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString()) + +// endregion + +// region Constructors and converters +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +// TODO: Rewrite former constructors as fabrics +//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( +//Polynomial(numeratorCoefficients), +//Polynomial(denominatorCoefficients) +//) +//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( +//Polynomial(numeratorCoefficients), +//Polynomial(denominatorCoefficients) +//) +//constructor(numerator: Polynomial) : this(numerator, numerator.getOne()) +//constructor(numeratorCoefficients: Map, C>) : this( +//Polynomial(numeratorCoefficients) +//) +//constructor(numeratorCoefficients: Collection, C>>) : this( +//Polynomial(numeratorCoefficients) +//) + +// endregion + +public class NumberedRationalFunctionSpace> ( + public val ring: A, +) : AbstractRationalFunctionalSpaceOverPolynomialSpace, NumberedRationalFunction, A> { + + override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) + + // region Rational-integer relation + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun NumberedRationalFunction.plus(other: Int): NumberedRationalFunction = + NumberedRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * 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 override operator fun NumberedRationalFunction.minus(other: Int): NumberedRationalFunction = + NumberedRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * 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 override operator fun NumberedRationalFunction.times(other: Int): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Integer-Rational relation + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Constant-rational relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-constant relation + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.plus(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.minus(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.times(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Polynomial-rational relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedPolynomial.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun NumberedPolynomial.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun NumberedPolynomial.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + this * other.numerator, + other.denominator + ) + // endregion + + // region Rational-polynomial relation + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.plus(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.minus(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun NumberedRationalFunction.times(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other, + denominator + ) + // endregion + + // region Rational-rational relation + /** + * Returns negation of the rational function. + */ + public override operator fun NumberedRationalFunction.unaryMinus(): NumberedRationalFunction = NumberedRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun NumberedRationalFunction.plus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun NumberedRationalFunction.minus(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun NumberedRationalFunction.times(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) + + /** + * Checks equality of the rational functions. + */ + @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") + public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { + if (this === other) return true + + if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + + val countOfVariables = max(this.countOfVariables, other.countOfVariables) + val thisNumeratorDegrees = this.numerator.degrees + val thisDenominatorDegrees = this.denominator.degrees + val otherNumeratorDegrees = other.numerator.degrees + val otherDenominatorDegrees = other.denominator.degrees + for (variable in 0 until countOfVariables) + if ( + thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } + != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } + ) return false + + return numerator * other.denominator equalsTo other.numerator * denominator + } + // endregion + + // region Polynomial properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And size of the list is [countOfVariables]. + */ + public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + // endregion + + // region Rational properties + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedRationalFunction.countOfVariables: Int + get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) } + // endregion + + // region REST TODO: Разобрать + + public operator fun NumberedRationalFunction.div(other: NumberedRationalFunction): NumberedRationalFunction = + NumberedRationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun NumberedRationalFunction.div(other: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction( + numerator, + denominator * other + ) + + public operator fun NumberedRationalFunction.div(other: C): NumberedRationalFunction = + NumberedRationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: Map): NumberedRationalFunction = +// NumberedRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokePolynomial") +// operator fun invoke(arg: Map>): NumberedRationalFunction = +// NumberedRationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// @JvmName("invokeRationalFunction") +// operator fun invoke(arg: Map>): NumberedRationalFunction { +// var num = numerator invokeRFTakeNumerator arg +// var den = denominator invokeRFTakeNumerator arg +// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { +// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } +// if (degreeDif > 0) +// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) +// else +// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) +// } +// return NumberedRationalFunction(num, den) +// } +// +// override fun toString(): String = toString(Polynomial.variableName) +// +// fun toString(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(withVariableName) +// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" +// } +// +// fun toString(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(namer) +// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" +// } +// +// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) +// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" +// } +// +// fun toStringWithBrackets(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(namer) +// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" +// } +// +// fun toReversedString(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(withVariableName) +// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" +// } +// +// fun toReversedString(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(namer) +// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" +// } +// +// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) +// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" +// } +// +// fun toReversedStringWithBrackets(namer: (Int) -> String): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) +// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" +// } +} \ No newline at end of file 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 2c764f4f5..1a324f72c 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 @@ -80,7 +80,7 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - val result = getOrElse(0) { ring.zero } + other + val result = getOrElse(0) { constantZero } + other val isResultZero = result.isZero() when { @@ -97,7 +97,7 @@ public open class PolynomialSpace>( coefficients .toMutableList() .apply { - val result = getOrElse(0) { ring.zero } - other + val result = getOrElse(0) { constantZero } - other val isResultZero = result.isZero() when { @@ -124,7 +124,7 @@ public open class PolynomialSpace>( other.coefficients .toMutableList() .apply { - val result = this@plus + getOrElse(0) { ring.zero } + val result = this@plus + getOrElse(0) { constantZero } val isResultZero = result.isZero() when { @@ -143,7 +143,7 @@ public open class PolynomialSpace>( .apply { forEachIndexed { index, c -> if (index != 0) this[index] = -c } - val result = this@minus - getOrElse(0) { ring.zero } + val result = this@minus - getOrElse(0) { constantZero } val isResultZero = result.isZero() when { @@ -281,7 +281,7 @@ public open class PolynomialSpace>( else -> coefficients[it] + other.coefficients[it] } } - .ifEmpty { listOf(ring.zero) } + .ifEmpty { listOf(constantZero) } ) public override operator fun Polynomial.minus(other: Polynomial): Polynomial = Polynomial( @@ -293,7 +293,7 @@ public open class PolynomialSpace>( else -> coefficients[it] - other.coefficients[it] } } - .ifEmpty { listOf(ring.zero) } + .ifEmpty { listOf(constantZero) } ) public override operator fun Polynomial.times(other: Polynomial): Polynomial { val thisDegree = degree @@ -321,7 +321,7 @@ public open class PolynomialSpace>( 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? override val zero: Polynomial = Polynomial(emptyList()) - override val one: Polynomial = Polynomial(listOf(ring.one)) + override val one: Polynomial = Polynomial(listOf(constantZero)) @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = @@ -337,12 +337,12 @@ public open class PolynomialSpace>( // region Polynomial properties - public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != ring.zero } + public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } public override fun Polynomial.asConstantOrNull(): C? = with(coefficients) { when { - isEmpty() -> ring.zero + isEmpty() -> constantZero degree > 0 -> null else -> first() } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 78ca556db..e9916b634 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.functions import space.kscience.kmath.operations.* @@ -270,19 +275,6 @@ public class RationalFunctionSpace> ( denominator * other.denominator ) - /** - * Check if the instant is zero rational function. - */ - public override fun RationalFunction.isZero(): Boolean = numerator.isZero() - /** - * Check if the instant is unit rational function. - */ - public override fun RationalFunction.isOne(): Boolean = numerator.equalsTo(denominator) - /** - * Check if the instant is minus unit rational function. - */ - public override fun RationalFunction.isMinusOne(): Boolean = (numerator + denominator).isZero() - /** * Instance of zero rational function (zero of the rational functions ring). */ 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 62ac31b64..9cf4f2652 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 @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.functions import space.kscience.kmath.operations.* @@ -30,7 +35,7 @@ import kotlin.contracts.* //fun > power(arg: Variable, pow: UInt): LabeledPolynomial = // if (pow == 0U) one // else LabeledPolynomial(mapOf( -// mapOf(arg to pow) to ring.one +// mapOf(arg to pow) to constantOne // )) // //// endregion diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt new file mode 100644 index 000000000..26e8ab17a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -0,0 +1,130 @@ +package math.polynomials + +import math.ringsAndFields.* +import space.kscience.kmath.functions.LabeledRationalFunction + + +fun > T.toLabeledRationalFunction() = LabeledRationalFunction(this.toLabeledPolynomial()) + +// region Operator extensions + +// region Field case + +fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { + val greatestCommonDivider = polynomialGCD(numerator, denominator) + return LabeledRationalFunction( + numerator / greatestCommonDivider, + denominator / greatestCommonDivider + ) +} + +// endregion + +// region Constants + +operator fun > T.plus(other: LabeledRationalFunction) = other + this +operator fun > Integer.plus(other: LabeledRationalFunction) = other + this +operator fun > Int.plus(other: LabeledRationalFunction) = other + this +operator fun > Long.plus(other: LabeledRationalFunction) = other + this + +operator fun > T.minus(other: LabeledRationalFunction) = -other + this +operator fun > Integer.minus(other: LabeledRationalFunction) = -other + this +operator fun > Int.minus(other: LabeledRationalFunction) = -other + this +operator fun > Long.minus(other: LabeledRationalFunction) = -other + this + +operator fun > T.times(other: LabeledRationalFunction) = other * this +operator fun > Integer.times(other: LabeledRationalFunction) = other * this +operator fun > Int.times(other: LabeledRationalFunction) = other * this +operator fun > Long.times(other: LabeledRationalFunction) = other * this + +// endregion + +// region Polynomials + +operator fun > LabeledRationalFunction.plus(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator + denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.plus(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.plus(other: Polynomial) = + LabeledRationalFunction( + numerator + denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.plus(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) + +operator fun > LabeledRationalFunction.minus(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator - denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.minus(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.minus(other: Polynomial) = + LabeledRationalFunction( + numerator - denominator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.minus(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) + +operator fun > LabeledRationalFunction.times(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.times(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.times(other: Polynomial) = + LabeledRationalFunction( + numerator * other.toLabeledPolynomial(), + denominator + ) +operator fun > LabeledRationalFunction.times(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.numerator.toLabeledPolynomial(), + denominator * other.denominator.toLabeledPolynomial() + ) + +operator fun > LabeledRationalFunction.div(other: UnivariatePolynomial) = + LabeledRationalFunction( + numerator, + denominator * other.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.div(other: UnivariateRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial(), + denominator * other.numerator.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.div(other: Polynomial) = + LabeledRationalFunction( + numerator, + denominator * other.toLabeledPolynomial() + ) +operator fun > LabeledRationalFunction.div(other: NumberedRationalFunction) = + LabeledRationalFunction( + numerator * other.denominator.toLabeledPolynomial(), + denominator * other.numerator.toLabeledPolynomial() + ) + +// endregion + +// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt new file mode 100644 index 000000000..7c8120c68 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -0,0 +1,23 @@ +/* + * 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 + + +//// region Operator extensions +// +//// region Field case +// +//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { +// val greatestCommonDivider = polynomialGCD(numerator, denominator) +// return NumberedRationalFunction( +// numerator / greatestCommonDivider, +// denominator / greatestCommonDivider +// ) +//} +// +//// endregion +// +//// endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index 9147bc023..d5bbc3b82 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -1,3 +1,8 @@ +/* + * 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 From 44febbdd730451bb7a941f1bcc973b661bd5d63b Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 20:19:42 +0300 Subject: [PATCH 014/174] Processed labeledRationalFunctionUtil.kt --- .../kscience/kmath/functions/Polynomial.kt | 1 - .../functions/labeledRationalFunctionUtil.kt | 147 +++--------------- 2 files changed, 20 insertions(+), 128 deletions(-) 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 1a324f72c..49184468b 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 @@ -6,7 +6,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.* -import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index 26e8ab17a..575dfed48 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -1,130 +1,23 @@ -package math.polynomials +/* + * 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. + */ -import math.ringsAndFields.* -import space.kscience.kmath.functions.LabeledRationalFunction +package space.kscience.kmath.functions -fun > T.toLabeledRationalFunction() = LabeledRationalFunction(this.toLabeledPolynomial()) - -// region Operator extensions - -// region Field case - -fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { - val greatestCommonDivider = polynomialGCD(numerator, denominator) - return LabeledRationalFunction( - numerator / greatestCommonDivider, - denominator / greatestCommonDivider - ) -} - -// endregion - -// region Constants - -operator fun > T.plus(other: LabeledRationalFunction) = other + this -operator fun > Integer.plus(other: LabeledRationalFunction) = other + this -operator fun > Int.plus(other: LabeledRationalFunction) = other + this -operator fun > Long.plus(other: LabeledRationalFunction) = other + this - -operator fun > T.minus(other: LabeledRationalFunction) = -other + this -operator fun > Integer.minus(other: LabeledRationalFunction) = -other + this -operator fun > Int.minus(other: LabeledRationalFunction) = -other + this -operator fun > Long.minus(other: LabeledRationalFunction) = -other + this - -operator fun > T.times(other: LabeledRationalFunction) = other * this -operator fun > Integer.times(other: LabeledRationalFunction) = other * this -operator fun > Int.times(other: LabeledRationalFunction) = other * this -operator fun > Long.times(other: LabeledRationalFunction) = other * this - -// endregion - -// region Polynomials - -operator fun > LabeledRationalFunction.plus(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator + denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.plus(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.plus(other: Polynomial) = - LabeledRationalFunction( - numerator + denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.plus(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() + denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) - -operator fun > LabeledRationalFunction.minus(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator - denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.minus(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.minus(other: Polynomial) = - LabeledRationalFunction( - numerator - denominator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.minus(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial() - denominator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) - -operator fun > LabeledRationalFunction.times(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.times(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.times(other: Polynomial) = - LabeledRationalFunction( - numerator * other.toLabeledPolynomial(), - denominator - ) -operator fun > LabeledRationalFunction.times(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.numerator.toLabeledPolynomial(), - denominator * other.denominator.toLabeledPolynomial() - ) - -operator fun > LabeledRationalFunction.div(other: UnivariatePolynomial) = - LabeledRationalFunction( - numerator, - denominator * other.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.div(other: UnivariateRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial(), - denominator * other.numerator.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.div(other: Polynomial) = - LabeledRationalFunction( - numerator, - denominator * other.toLabeledPolynomial() - ) -operator fun > LabeledRationalFunction.div(other: NumberedRationalFunction) = - LabeledRationalFunction( - numerator * other.denominator.toLabeledPolynomial(), - denominator * other.numerator.toLabeledPolynomial() - ) - -// endregion - -// endregion \ No newline at end of file +//// region Operator extensions +// +//// region Field case +// +//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { +// val greatestCommonDivider = polynomialGCD(numerator, denominator) +// return LabeledRationalFunction( +// numerator / greatestCommonDivider, +// denominator / greatestCommonDivider +// ) +//} +// +//// endregion +// +//// endregion \ No newline at end of file From fb01d851975a1e681f00f6a530431a5dd326421a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 14 Mar 2022 22:23:50 +0300 Subject: [PATCH 015/174] Removed extra `JSName` annotations. Now everything builds --- .../kscience/kmath/functions/AbstractPolynomial.kt | 4 ---- .../kmath/functions/AbstractRationalFunction.kt | 10 ---------- 2 files changed, 14 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 0ca2d1409..0b16303af 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 @@ -388,25 +388,21 @@ public interface AbstractPolynomialSpaceOverRing, A: * Returns negation of the constant. */ @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } /** * Returns sum of the constants. */ @JvmName("constantPlus") - @JsName("constantPlus") public override operator fun C.plus(other: C): C = ring { this@plus + other } /** * Returns difference of the constants. */ @JvmName("constantMinus") - @JsName("constantMinus") public override operator fun C.minus(other: C): C = ring { this@minus - other } /** * Returns product of the constants. */ @JvmName("constantTimes") - @JsName("constantTimes") public override operator fun C.times(other: C): C = ring { this@times * other } /** 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 df366f90f..cf8f3a6ef 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 @@ -578,31 +578,26 @@ public interface AbstractRationalFunctionalSpaceOverRing Date: Mon, 14 Mar 2022 23:33:00 +0300 Subject: [PATCH 016/174] Deleted useless annotations `JvmName`, `JsName` and `Suppress` --- .../kmath/functions/AbstractPolynomial.kt | 20 +---------- .../functions/AbstractRationalFunction.kt | 34 ++----------------- .../kmath/functions/LabeledPolynomial.kt | 2 -- .../functions/LabeledRationalFunction.kt | 1 - .../kmath/functions/NumberedPolynomial.kt | 2 -- .../functions/NumberedRationalFunction.kt | 1 - .../kscience/kmath/functions/Polynomial.kt | 3 +- .../kmath/functions/RationalFunction.kt | 1 - .../kmath/functions/numberedPolynomialUtil.kt | 9 ++--- 9 files changed, 9 insertions(+), 64 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 0b16303af..b053ffebd 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 @@ -29,21 +29,18 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - @JvmName("constantIntPlus") public operator fun C.plus(other: Int): C /** * 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]. */ - @JvmName("constantIntMinus") public operator fun C.minus(other: Int): C /** * 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]. */ - @JvmName("constantIntTimes") public operator fun C.times(other: Int): C // endregion @@ -53,21 +50,18 @@ public interface AbstractPolynomialSpace> : Ring

* * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - @JvmName("intConstantPlus") public operator fun Int.plus(other: C): C /** * 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]. */ - @JvmName("intConstantMinus") public operator fun Int.minus(other: C): C /** * 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]. */ - @JvmName("intConstantTimes") public operator fun Int.times(other: C): C // endregion @@ -148,32 +142,26 @@ public interface AbstractPolynomialSpace> : Ring

/** * Check if the instant is zero constant. */ - @JvmName("constantIsZero") public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ - @JvmName("constantIsNotZero") public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ - @JvmName("constantIsOne") public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ - @JvmName("constantIsNotOne") public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ - @JvmName("constantIsMinusOne") public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ - @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() /** @@ -330,7 +318,7 @@ public interface AbstractPolynomialSpace> : Ring

* @param C the type of constants. Polynomials have them as a coefficients in their terms. * @param P the type of polynomials. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { public val ring: A @@ -341,21 +329,18 @@ public interface AbstractPolynomialSpaceOverRing, A: * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - @JvmName("constantIntPlus") public override operator fun C.plus(other: Int): C = ring { optimizedAddMultiplied(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]. */ - @JvmName("constantIntMinus") public override operator fun C.minus(other: Int): C = ring { optimizedAddMultiplied(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]. */ - @JvmName("constantIntTimes") public override operator fun C.times(other: Int): C = ring { optimizedMultiply(this@times, other) } // endregion @@ -365,21 +350,18 @@ public interface AbstractPolynomialSpaceOverRing, A: * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - @JvmName("intConstantPlus") public override operator fun Int.plus(other: C): C = ring { optimizedAddMultiplied(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]. */ - @JvmName("intConstantMinus") public override operator fun Int.minus(other: C): C = ring { optimizedAddMultiplied(-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]. */ - @JvmName("intConstantTimes") public override operator fun Int.times(other: C): C = ring { optimizedMultiply(other, this@times) } // endregion 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 cf8f3a6ef..f8d3bb99b 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 @@ -28,21 +28,18 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - @JvmName("constantIntPlus") public operator fun C.plus(other: Int): C /** * 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]. */ - @JvmName("constantIntMinus") public operator fun C.minus(other: Int): C /** * 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]. */ - @JvmName("constantIntTimes") public operator fun C.times(other: Int): C // endregion @@ -52,21 +49,18 @@ public interface AbstractRationalFunctionalSpace, R: * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - @JvmName("intConstantPlus") public operator fun Int.plus(other: C): C /** * 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]. */ - @JvmName("intConstantMinus") public operator fun Int.minus(other: C): C /** * 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]. */ - @JvmName("intConstantTimes") public operator fun Int.times(other: C): C // endregion @@ -189,32 +183,26 @@ public interface AbstractRationalFunctionalSpace, R: /** * Check if the instant is zero constant. */ - @JvmName("constantIsZero") public fun C.isZero(): Boolean = this == constantZero /** * Check if the instant is NOT zero constant. */ - @JvmName("constantIsNotZero") public fun C.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit constant. */ - @JvmName("constantIsOne") public fun C.isOne(): Boolean = this == constantOne /** * Check if the instant is NOT unit constant. */ - @JvmName("constantIsNotOne") public fun C.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit constant. */ - @JvmName("constantIsMinusOne") public fun C.isMinusOne(): Boolean = this == -constantOne /** * Check if the instant is NOT minus unit constant. */ - @JvmName("constantIsNotMinusOne") public fun C.isNotMinusOne(): Boolean = !isMinusOne() /** @@ -520,7 +508,7 @@ public interface AbstractRationalFunctionalSpace, R: // endregion } -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { public val ring: A @@ -531,21 +519,18 @@ public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { public val polynomialRing: AbstractPolynomialSpace @@ -622,21 +604,18 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace.cleanUp() = filterValues { it > 0U } * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. * @param ring the [A] instance. */ -@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") public class LabeledPolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { @@ -768,7 +767,6 @@ public class LabeledPolynomialSpace>( override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) // TODO: Docs - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 203c9e07c..2bec1f3a4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -305,7 +305,6 @@ public class LabeledRationalFunctionSpace>( /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { if (this === other) return true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 39ca43945..de5cc5658 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -263,7 +263,6 @@ public fun > C.asNumberedPolynomial() : NumberedPolynomial = Nu * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. * @param ring the [A] instance. */ -@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE", "INAPPLICABLE_JVM_NAME") public open class NumberedPolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { @@ -532,7 +531,6 @@ public open class NumberedPolynomialSpace>( ) // TODO: Docs - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index aff18d1f4..2053cc7f9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -302,7 +302,6 @@ public class NumberedRationalFunctionSpace> ( /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { if (this === other) return true 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 49184468b..802ff7ea2 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 @@ -66,7 +66,7 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 +//@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { @@ -322,7 +322,6 @@ public open class PolynomialSpace>( override val zero: Polynomial = Polynomial(emptyList()) override val one: Polynomial = Polynomial(listOf(constantZero)) - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index e9916b634..0842f0938 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -287,7 +287,6 @@ public class RationalFunctionSpace> ( /** * Checks equality of the rational functions. */ - @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "CovariantEquals") public override infix fun RationalFunction.equalsTo(other: RationalFunction): Boolean = when { this === other -> true 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 d4053442d..558afa744 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 @@ -6,6 +6,7 @@ import kotlin.contracts.* import kotlin.jvm.JvmName + // TODO: Docs // region Sort of legacy @@ -485,8 +486,8 @@ public fun NumberedPolynomial.substitute(args: Map): Number val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitutor.pow(deg.toInt()) } - if (newDegs !in acc) acc[newDegs] = c - else acc[newDegs] = acc[newDegs]!! + c + if (newDegs !in acc) acc[newDegs] = newC + else acc[newDegs] = acc[newDegs]!! + newC } return NumberedPolynomial(acc) } @@ -504,8 +505,8 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitutor, deg) } - if (newDegs !in acc) acc[newDegs] = c - else acc[newDegs] = acc[newDegs]!! + c + if (newDegs !in acc) acc[newDegs] = newC + else acc[newDegs] = acc[newDegs]!! + newC } return NumberedPolynomial(acc) } From ebd7f799adae2047eb5acdfec6ef5345e2a7c3d6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 00:47:23 +0300 Subject: [PATCH 017/174] Attempts to implement derivatives and antiderivatives --- .../kmath/functions/numberedPolynomialUtil.kt | 175 ++++++++++++++---- .../kmath/functions/polynomialUtil.kt | 32 +++- 2 files changed, 171 insertions(+), 36 deletions(-) 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 558afa744..b7620e792 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 @@ -545,62 +545,169 @@ public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun NumberedPolynomial.derivativeBy( +public fun > NumberedPolynomial.derivativeWithRespectTo( algebra: A, variable: Int, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - TODO() +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }, + optimizedMultiply(c, degs.getOrElse(variable) { 1u }.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ // TODO: This one does not work!!! +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + algebra: A, + variables: IntArray, +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index !in variables -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }, + optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ // TODO: This one does not work!!! +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + algebra: A, + variables: Collection, +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index !in variables -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }, + optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) } /** * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun NumberedPolynomial.derivativeBy( - algebra: A, - variables: IntArray, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - TODO() -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun NumberedPolynomial.derivativeBy( - algebra: A, - variables: Collection, -): Polynomial where A : Ring, A : NumericAlgebra = derivativeBy(algebra, variables.toIntArray()) - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun NumberedPolynomial.antiderivativeBy( +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( algebra: A, variable: Int, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - TODO() + order: UInt +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }, + degs.getOrElse(variable) { 1u }.toInt().let { + (0u until order).fold(c) { acc, ord -> + optimizedMultiply(acc, ord.toInt()) + } + } + ) + } + } + ) } /** - * Create a polynomial witch represents indefinite integral version of this polynomial + * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun NumberedPolynomial.antiderivativeBy( +public fun > NumberedPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Int, +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> if(index != variable) deg else deg + 1u }, + c / optimizedMultiply(one, degs.getOrElse(variable) { 1u }.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ // TODO: This one does not work!!! +@UnstableKMathAPI +public fun > NumberedPolynomial.antiderivativeWithRespectTo( algebra: A, variables: IntArray, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - TODO() +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, + c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) } /** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ + * Returns algebraic antiderivative of received polynomial. + */ // TODO: This one does not work!!! @UnstableKMathAPI -public fun NumberedPolynomial.antiderivativeBy( +public fun > NumberedPolynomial.antiderivativeWithRespectTo( algebra: A, variables: Collection, -): Polynomial where A : Field, A : NumericAlgebra = antiderivativeBy(algebra, variables.toIntArray()) +): NumberedPolynomial = algebra { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients.forEach { (degs, c) -> + put( + degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, + c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) + ) + } + } + ) +} // endregion \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 4d99b3a45..7e40b6246 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 @@ -109,11 +109,23 @@ 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, t -> number(index) * t }) + Polynomial(coefficients.drop(1).mapIndexed { index, c -> number(index) * c }) } /** - * Create a polynomial witch represents indefinite integral version of this polynomial + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +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 }) +} + +/** + * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI public fun Polynomial.antiderivative( @@ -126,6 +138,22 @@ public fun Polynomial.antiderivative( Polynomial(integratedCoefficients) } +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +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)) } + } + Polynomial(integratedCoefficients) +} + /** * Compute a definite integral of a given polynomial in a [range] */ From f86529d65944016631efe09218c4828feed32f03 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 15:35:17 +0300 Subject: [PATCH 018/174] Optimized `optimizedMultiply` and `optimizedAddMultiplied` for cases of negative value of `other` and `multiplier` --- .../kscience/kmath/functions/algebraicStub.kt | 59 +++++++++++++------ 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index 9e5043b8c..3c37a01ec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -16,17 +16,11 @@ import space.kscience.kmath.operations.Group * @receiver the multiplicand. * @param other the multiplier. * @return the difference. + * @author Gleb Minaev */ -internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = - when { - other == 0 -> zero - other == 1 -> arg - other == -1 -> -arg - other % 2 == 0 -> optimizedMultiply(arg + arg, other / 2) - other % 2 == 1 -> optimizedAddMultiplied(arg, arg + arg, other / 2) - other % 2 == -1 -> optimizedAddMultiplied(-arg, arg + arg, other / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") - } +internal fun Group.optimizedMultiply(arg: C, other: Int): C = + if (other >= 0) optimizedMultiply(arg, other.toUInt()) + else optimizedMultiply(arg, (-other).toUInt()) // TODO: Move receiver to context receiver /** @@ -40,12 +34,43 @@ internal tailrec fun Group.optimizedMultiply(arg: C, other: Int): C = * @author Gleb Minaev */ internal tailrec fun Group.optimizedAddMultiplied(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) optimizedAddMultiplied(base, arg, multiplier.toUInt()) + else optimizedAddMultiplied(base, arg, (-multiplier).toUInt()) + +// TODO: Move receiver to context receiver +/** + * Multiplication of element and integer. + * + * @receiver the multiplicand. + * @param other the multiplier. + * @return the difference. + * @author Gleb Minaev + */ +internal tailrec fun Group.optimizedMultiply(arg: C, other: UInt): C = when { - multiplier == 0 -> base - multiplier == 1 -> base + arg - multiplier == -1 -> base - arg - multiplier % 2 == 0 -> optimizedAddMultiplied(base, arg + arg, multiplier / 2) - multiplier % 2 == 1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - multiplier % 2 == -1 -> optimizedAddMultiplied(base + arg, arg + arg, multiplier / 2) - else -> error("Error in multiplication group instant by integer: got reminder by division by 2 different from 0, 1 and -1") + other == 0u -> zero + other == 1u -> arg + other % 2u == 0u -> optimizedMultiply(arg + arg, other / 2u) + other % 2u == 1u -> optimizedAddMultiplied(arg, arg + arg, other / 2u) + 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 +/** + * 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. + * @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 = + 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) + 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 From 79736a0a9b6450df9ae0a7d7209b8aa7603d36c4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 15:36:10 +0300 Subject: [PATCH 019/174] Forgot to remove unnecessary `tailrec` --- .../kotlin/space/kscience/kmath/functions/algebraicStub.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index 3c37a01ec..537184ba3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -33,7 +33,7 @@ internal fun Group.optimizedMultiply(arg: C, other: Int): C = * @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: Int): C = +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()) From 1754ae06951ff0964239cc7c822b869b31ab371e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 16:43:22 +0300 Subject: [PATCH 020/174] Added some docs --- .../kmath/functions/AbstractPolynomial.kt | 8 +- .../functions/AbstractRationalFunction.kt | 36 +++++- .../kmath/functions/LabeledPolynomial.kt | 60 +++++++++- .../functions/LabeledRationalFunction.kt | 7 +- .../kmath/functions/NumberedPolynomial.kt | 69 ++++++++++- .../functions/NumberedRationalFunction.kt | 7 +- .../kscience/kmath/functions/Polynomial.kt | 112 +++++++++++++++--- .../kmath/functions/RationalFunction.kt | 7 +- 8 files changed, 271 insertions(+), 35 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 b053ffebd..8bd8697e3 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 @@ -18,7 +18,7 @@ public interface AbstractPolynomial /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") @@ -313,10 +313,12 @@ public interface AbstractPolynomialSpace> : Ring

} /** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is + * provided [ring] (of type [A]), that provides constant-wise operations. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { 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 f8d3bb99b..685cf4ca3 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 @@ -20,6 +20,14 @@ public interface AbstractRationalFunction> { public operator fun component2(): P = denominator } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { // region Constant-integer relation @@ -508,6 +516,15 @@ public interface AbstractRationalFunctionalSpace, R: // endregion } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [ring] (of type [A]), that provides constant-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. + */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME") public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { @@ -593,10 +610,25 @@ public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { +public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + P: AbstractPolynomial, + R: AbstractRationalFunction, + AP: AbstractPolynomialSpace, + > : AbstractRationalFunctionalSpace { - public val polynomialRing: AbstractPolynomialSpace + public val polynomialRing: AP // region Constant-integer relation /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 81aabb4a4..ebdaa6e26 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -384,6 +384,11 @@ public class LabeledPolynomialSpace>( // endregion // region Polynomial-integer relation + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = if (other == 0) this else @@ -399,6 +404,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * 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 override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = if (other == 0) this else @@ -414,6 +424,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial( @@ -425,6 +440,11 @@ public class LabeledPolynomialSpace>( // endregion // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other else @@ -440,6 +460,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * 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 override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other else @@ -455,6 +480,11 @@ public class LabeledPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial( @@ -514,6 +544,9 @@ public class LabeledPolynomialSpace>( // endregion // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { @@ -530,6 +563,9 @@ public class LabeledPolynomialSpace>( } ) } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { @@ -548,6 +584,9 @@ public class LabeledPolynomialSpace>( } ) } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) zero else LabeledPolynomial( @@ -560,7 +599,7 @@ public class LabeledPolynomialSpace>( // region Polynomial-constant relation /** - * Returns sum of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = if (other.isZero()) this @@ -579,7 +618,7 @@ public class LabeledPolynomialSpace>( ) } /** - * Returns difference of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = if (other.isZero()) this @@ -600,7 +639,7 @@ public class LabeledPolynomialSpace>( ) } /** - * Returns product of the polynomials. [other] is interpreted as [UnivariatePolynomial]. + * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = if (other.isZero()) zero @@ -763,10 +802,18 @@ public class LabeledPolynomialSpace>( ) } + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - // TODO: Docs + /** + * Checks equality of the polynomials. + */ override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = when { this === other -> true @@ -832,7 +879,10 @@ public class LabeledPolynomialSpace>( } foundAbsoluteTermAndItIsNotZero } - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ override fun LabeledPolynomial.asConstantOrNull(): C? = with(coefficients) { if(isConstant()) getOrElse(emptyMap()) { constantZero } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 2bec1f3a4..df4441127 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -85,7 +85,12 @@ internal fun labeledRationalFunctionError(message: Any): Nothing = throw Labeled public class LabeledRationalFunctionSpace>( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace, LabeledRationalFunction, A> { +) : AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + > { override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index de5cc5658..86c76949b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -267,6 +267,11 @@ public open class NumberedPolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = if (other == 0) this else @@ -282,6 +287,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * 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 override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = if (other == 0) this else @@ -297,6 +307,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = if (other == 0) zero else NumberedPolynomial( @@ -308,6 +323,11 @@ public open class NumberedPolynomialSpace>( // endregion // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) other else @@ -323,6 +343,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * 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 override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) other else @@ -338,6 +363,11 @@ public open class NumberedPolynomialSpace>( else this[degs] = result } ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) zero else NumberedPolynomial( @@ -349,6 +379,9 @@ public open class NumberedPolynomialSpace>( // endregion // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) other else with(other.coefficients) { @@ -365,6 +398,9 @@ public open class NumberedPolynomialSpace>( } ) } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) -other else with(other.coefficients) { @@ -383,6 +419,9 @@ public open class NumberedPolynomialSpace>( } ) } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) zero else NumberedPolynomial( @@ -395,7 +434,7 @@ public open class NumberedPolynomialSpace>( // region Polynomial-constant relation /** - * Returns sum of the polynomials. [other] is interpreted as [NumberedPolynomial]. + * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = if (other.isZero()) this @@ -414,7 +453,7 @@ public open class NumberedPolynomialSpace>( ) } /** - * Returns difference of the polynomials. [other] is interpreted as [NumberedPolynomial]. + * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = if (other.isZero()) this @@ -433,7 +472,7 @@ public open class NumberedPolynomialSpace>( ) } /** - * Returns product of the polynomials. [other] is interpreted as [NumberedPolynomial]. + * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = if (other.isZero()) zero @@ -496,7 +535,13 @@ public open class NumberedPolynomialSpace>( ) } + /** + * Check if the instant is zero polynomial. + */ public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } + /** + * Check if the instant is unit polynomial. + */ public override fun NumberedPolynomial.isOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsOne = false @@ -509,6 +554,9 @@ public open class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsOne } + /** + * Check if the instant is minus unit polynomial. + */ public override fun NumberedPolynomial.isMinusOne(): Boolean = with(coefficients) { var foundAbsoluteTermAndItIsMinusOne = false @@ -522,7 +570,13 @@ public open class NumberedPolynomialSpace>( foundAbsoluteTermAndItIsMinusOne } + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ override val one: NumberedPolynomial = NumberedPolynomial( mapOf( @@ -530,7 +584,9 @@ public open class NumberedPolynomialSpace>( ) ) - // TODO: Docs + /** + * Checks equality of the polynomials. + */ override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = when { this === other -> true @@ -591,7 +647,10 @@ public open class NumberedPolynomialSpace>( } foundAbsoluteTermAndItIsNotZero } - + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ override fun NumberedPolynomial.asConstantOrNull(): C? = with(coefficients) { if(isConstant()) getOrElse(emptyList()) { constantZero } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 2053cc7f9..a81795c81 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -82,7 +82,12 @@ internal fun numberedRationalFunctionError(message: Any): Nothing = throw Number public class NumberedRationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace, NumberedRationalFunction, A> { +) : AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + > { override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) 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 802ff7ea2..bdc725e63 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 @@ -68,10 +68,15 @@ public fun T.asPolynomial() : Polynomial = Polynomial(listOf(this)) */ //@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( - public final override val ring: A, + public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { // region Polynomial-integer relation + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ public override operator fun Polynomial.plus(other: Int): Polynomial = if (other == 0) this else @@ -89,6 +94,11 @@ public open class PolynomialSpace>( } } ) + /** + * 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 override operator fun Polynomial.minus(other: Int): Polynomial = if (other == 0) this else @@ -106,6 +116,11 @@ public open class PolynomialSpace>( } } ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ public override operator fun Polynomial.times(other: Int): Polynomial = if (other == 0) zero else Polynomial( @@ -116,6 +131,11 @@ public open class PolynomialSpace>( // endregion // region Integer-polynomial relation + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ public override operator fun Int.plus(other: Polynomial): Polynomial = if (this == 0) other else @@ -133,6 +153,11 @@ public open class PolynomialSpace>( } } ) + /** + * 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 override operator fun Int.minus(other: Polynomial): Polynomial = if (this == 0) other else @@ -152,6 +177,11 @@ public open class PolynomialSpace>( } } ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ public override operator fun Int.times(other: Polynomial): Polynomial = if (this == 0) zero else Polynomial( @@ -162,6 +192,9 @@ public open class PolynomialSpace>( // endregion // region Constant-polynomial relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ public override operator fun C.plus(other: Polynomial): Polynomial = if (this.isZero()) other else with(other.coefficients) { @@ -180,9 +213,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( -// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ public override operator fun C.minus(other: Polynomial): Polynomial = if (this.isZero()) other else with(other.coefficients) { @@ -203,9 +236,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( -// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ public override operator fun C.times(other: Polynomial): Polynomial = if (this.isZero()) other else Polynomial( @@ -216,6 +249,9 @@ public open class PolynomialSpace>( // endregion // region Polynomial-constant relation + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ public override operator fun Polynomial.plus(other: C): Polynomial = if (other.isZero()) this else with(coefficients) { @@ -234,9 +270,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(other) else UnivariatePolynomial( -// listOf(coefficients[0] + other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ public override operator fun Polynomial.minus(other: C): Polynomial = if (other.isZero()) this else with(coefficients) { @@ -255,9 +291,9 @@ public open class PolynomialSpace>( } ) } -// if (degree == -1) UnivariatePolynomial(-other) else UnivariatePolynomial( -// listOf(coefficients[0] - other) + coefficients.subList(1, degree + 1) -// ) + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ public override operator fun Polynomial.times(other: C): Polynomial = if (other.isZero()) this else Polynomial( @@ -268,8 +304,14 @@ public open class PolynomialSpace>( // endregion // region Polynomial-polynomial relation + /** + * Returns negation of the polynomial. + */ public override operator fun Polynomial.unaryMinus(): Polynomial = Polynomial(coefficients.map { -it }) + /** + * Returns sum of the polynomials. + */ public override operator fun Polynomial.plus(other: Polynomial): Polynomial = Polynomial( (0..max(degree, other.degree)) @@ -282,6 +324,9 @@ public open class PolynomialSpace>( } .ifEmpty { listOf(constantZero) } ) + /** + * Returns difference of the polynomials. + */ public override operator fun Polynomial.minus(other: Polynomial): Polynomial = Polynomial( (0..max(degree, other.degree)) @@ -294,6 +339,9 @@ public open class PolynomialSpace>( } .ifEmpty { listOf(constantZero) } ) + /** + * Returns product of the polynomials. + */ public override operator fun Polynomial.times(other: Polynomial): Polynomial { val thisDegree = degree val otherDegree = other.degree @@ -313,15 +361,39 @@ public open class PolynomialSpace>( } } + /** + * Check if the instant is zero polynomial. + */ public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + /** + * Check if the instant is unit polynomial. + */ 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? + 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? + } + /** + * 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? + 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? + } + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ override val zero: Polynomial = Polynomial(emptyList()) + /** + * Instance of unit constant (unit of the underlying ring). + */ override val one: Polynomial = Polynomial(listOf(constantZero)) + /** + * Checks equality of the polynomials. + */ public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true @@ -334,9 +406,16 @@ public open class PolynomialSpace>( // endregion // region Polynomial properties - + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ public override fun Polynomial.asConstantOrNull(): C? = with(coefficients) { when { @@ -345,7 +424,6 @@ public open class PolynomialSpace>( else -> first() } } - public override fun Polynomial.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") @Suppress("NOTHING_TO_INLINE") public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 0842f0938..441136a64 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -67,7 +67,12 @@ internal fun rationalFunctionError(message: Any): Nothing = throw RationalFuncti public class RationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace, RationalFunction, A> { +) : AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + Polynomial, + RationalFunction, + PolynomialSpace, + > { override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) From 91c9ea61da4f9e3ec60003ce25a6448e9b699b85 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:10:11 +0300 Subject: [PATCH 021/174] Added derivative-like functions to `Polynomial` --- .../kscience/kmath/functions/Polynomial.kt | 16 +++---- .../kmath/functions/polynomialUtil.kt | 48 ++++++++++++------- 2 files changed, 39 insertions(+), 25 deletions(-) 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) } /** From 1f9d8d34f5f0476b4ea553bdd2c99a7406d30f61 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:18:39 +0300 Subject: [PATCH 022/174] Tried to add constructors and/or fabrics for polynomials --- .../kmath/functions/LabeledPolynomial.kt | 247 ++---------------- .../kmath/functions/NumberedPolynomial.kt | 223 +++++----------- .../kscience/kmath/functions/Polynomial.kt | 27 +- 3 files changed, 122 insertions(+), 375 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index ebdaa6e26..56dad975d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -73,254 +73,59 @@ internal fun Map.cleanUp() = filterValues { it > 0U } // region Constructors and converters -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(coefs) +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(coefs) // -// // Map for cleaned coefficients. // val fixedCoefs = mutableMapOf, C>() // -// // Cleaning the degrees, summing monomials of the same degrees. // for (entry in coefs) { // val key = entry.key.cleanUp() // val value = entry.value // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } +// return LabeledPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) // -// // Map for cleaned coefficients. +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { +// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) +// // val fixedCoefs = mutableMapOf, C>() // -// // Cleaning the degrees, summing monomials of the same degrees. // for (entry in pairs) { // val key = entry.first.cleanUp() // val value = entry.second // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// // Removing zero monomials. -// return LabeledPolynomial( +// return LabeledPolynomial( // fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) // -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() +//// TODO: Do not know how to make it without context receivers +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) // -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) // -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//internal fun > LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(coefs) +//context(LabeledPolynomialSpace>) +//@Suppress("FunctionName") +//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) // -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() -// -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//internal fun > LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) -// -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() -// -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//internal fun > LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) -// -// // Map for cleaned coefficients. -// val fixedCoefs = mutableMapOf, C>() -// -// // Cleaning the degrees, summing monomials of the same degrees. -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// // Removing zero monomials. -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial(coefs: Map, C>): LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial(pairs: Collection, C>>): LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from keys of received -// * map, sums up proportional monomials, removes aero monomials, and if result is zero map adds only element in it. -// * -// * @param pairs Collection of pairs that represents monomials. -// * -// * @throws LabeledPolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial(vararg pairs: Pair, C>): LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -// -//fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) -// -//context(A) -//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to one)) -// -//context(LabeledPolynomialSpace) -//fun > Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1U) to constantOne)) -// -//context(A) -//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = -// if(c.isZero()) LabeledPolynomial(emptyMap()) -// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) -// -//context(LabeledPolynomialSpace) -//fun > Variable.asLabeledPolynomial(c: C) : LabeledPolynomial = -// if(c.isZero()) zero -// else LabeledPolynomial(mapOf(mapOf(this to 1U) to c)) +//context(LabeledPolynomialSpace>) +//public fun Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) // endregion diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 86c76949b..a1033fcc4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -72,100 +72,10 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) // endregion // region Constructors and converters -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(A) +//context(NumberedPolynomialSpace>) //@Suppress("FunctionName") -//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(coefs) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//@Suppress("FunctionName") -//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } -// ) -//} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//@Suppress("FunctionName") -//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = -// NumberedPolynomial(pairs.toMap(), toCheckInput) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(A) -//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) -// -//context(NumberedPolynomialSpace) -//@Suppress("FunctionName") -//internal fun > NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean): NumberedPolynomial { +//internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { // if (!toCheckInput) return NumberedPolynomial(coefs) // // val fixedCoefs = mutableMapOf, C>() @@ -176,23 +86,14 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } +// return NumberedPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) +// +//context(NumberedPolynomialSpace>) //@Suppress("FunctionName") -//internal fun > NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean): NumberedPolynomial { +//internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { // if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) // // val fixedCoefs = mutableMapOf, C>() @@ -203,56 +104,25 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) // fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value // } // -// return NumberedPolynomial( -// fixedCoefs -// .filter { it.value.isNotZero() } +// return NumberedPolynomial( +// fixedCoefs.filterValues { it.isNotZero() } // ) //} -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * @param toCheckInput If it's `true` cleaning of [coefficients] is executed otherwise it is not. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) +// +//// TODO: Do not know how to make it without context receivers +//context(NumberedPolynomialSpace>) //@Suppress("FunctionName") -//internal fun > NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean): NumberedPolynomial = -// NumberedPolynomial(pairs.toList(), toCheckInput) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param coefs Coefficients of the instants. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial(coefs: Map, C>) = NumberedPolynomial(coefs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial(pairs: Collection, C>>) = NumberedPolynomial(pairs, toCheckInput = true) -///** -// * Gets the coefficients in format of [coefficients] field and cleans it: removes zero degrees from end of received -// * lists, sums up proportional monomials, removes zero monomials, and if result is empty map adds only element in it. -// * -// * @param pairs Collection of pairs that represent monomials. -// * -// * @throws PolynomialError If no coefficient received or if any of degrees in any monomial is negative. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial(vararg pairs: Pair, C>) = NumberedPolynomial(*pairs, toCheckInput = true) +//public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +// +//context(NumberedPolynomialSpace>) +//@Suppress("FunctionName") +//public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +// +//context(NumberedPolynomialSpace>) +//@Suppress("FunctionName") +//public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) -public fun > C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) +public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) // endregion @@ -314,7 +184,7 @@ public open class NumberedPolynomialSpace>( */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = if (other == 0) zero - else NumberedPolynomial( + else NumberedPolynomial( coefficients .applyAndRemoveZeros { mapValues { (_, c) -> c * other } @@ -707,4 +577,51 @@ public open class NumberedPolynomialSpace>( } } // endregion + + // region Constructors and converters + + @Suppress("FunctionName") + internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it.isNotZero() } + ) + } + + @Suppress("FunctionName") + internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it.isNotZero() } + ) + } + + @Suppress("FunctionName") + public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) + + @Suppress("FunctionName") + public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) + + @Suppress("FunctionName") + public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) + + // endregion } \ No newline at end of file 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 1ac413818..2f7976da6 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,32 @@ import kotlin.math.min * * @param coefficients constant is the leftmost coefficient. */ -public data class Polynomial(public val coefficients: List) : AbstractPolynomial { +public data class Polynomial( + /** + * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients + * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not + * prohibited. + */ + public val coefficients: List +) : AbstractPolynomial { override fun toString(): String = "Polynomial$coefficients" } From bb5e638b31186607bf953bff3bd2f5275f13e0c1 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:38:27 +0300 Subject: [PATCH 023/174] Added polynomial spaces and scopes fabrics --- .../kmath/functions/labeledPolynomialUtil.kt | 189 +----------------- .../kmath/functions/numberedPolynomialUtil.kt | 189 +----------------- 2 files changed, 20 insertions(+), 358 deletions(-) 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 9cf4f2652..5689f6e1b 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 @@ -54,7 +54,7 @@ import kotlin.contracts.* // else -> multiplyWithPowerInternalLogic(base, arg, pow) // } // -//// Trivial but slow as duck +//// Trivial but very slow //context(LabeledPolynomialSpace) //internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = // when { @@ -71,7 +71,15 @@ import kotlin.contracts.* // region Utilities -// TODO: Docs +/** + * Crates a [LabeledPolynomialSpace] over received ring. + */ +public fun > A.labeledPolynomial(): LabeledPolynomialSpace = + LabeledPolynomialSpace(this) + +/** + * Crates a [LabeledPolynomialSpace]'s scope over received ring. + */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -254,64 +262,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //// region Field case // -//operator fun > Polynomial.div(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(quotientCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(quotientCoefficients, toCheckInput = false) -//} -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -321,125 +271,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // toCheckInput = false // ) // -//operator fun > Polynomial.rem(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(thisCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(thisCoefficients, toCheckInput = false) -//} -// -//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return Polynomial.Companion.DividingResult(this, this) -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -//} -// //// endregion // endregion 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 b7620e792..de95d0151 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 @@ -38,7 +38,7 @@ import kotlin.jvm.JvmName // else -> multiplyWithPowerInternalLogic(base, arg, pow) // } // -//// Trivial but slow as duck +//// Trivial but very slow //context(NumberedPolynomialSpace) //internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = // when { @@ -55,7 +55,15 @@ import kotlin.jvm.JvmName // region Utilities -// TODO: Docs +/** + * Crates a [NumberedPolynomialSpace] over received ring. + */ +public fun > A.numberedPolynomial(): NumberedPolynomialSpace = + NumberedPolynomialSpace(this) + +/** + * Crates a [NumberedPolynomialSpace]'s scope over received ring. + */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -282,64 +290,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno //// region Field case // -//operator fun > Polynomial.div(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(quotientCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(quotientCoefficients, toCheckInput = false) -//} -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -349,125 +299,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // toCheckInput = false // ) // -//operator fun > Polynomial.rem(other: Polynomial): Polynomial { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return this -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial(thisCoefficients, toCheckInput = false) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial(thisCoefficients, toCheckInput = false) -//} -// -//infix fun > Polynomial.divrem(other: Polynomial): Polynomial.Companion.DividingResult { -// if (other.isZero()) throw ArithmeticException("/ by zero") -// if (isZero()) return Polynomial.Companion.DividingResult(this, this) -// -// fun Map, T>.leadingTerm() = -// this -// .asSequence() -// .map { Pair(it.key, it.value) } -// .reduce { (accDegs, accC), (listDegs, listC) -> -// for (i in 0..accDegs.lastIndex) { -// if (accDegs[i] > listDegs.getOrElse(i) { 0 }) return@reduce accDegs to accC -// if (accDegs[i] < listDegs.getOrElse(i) { 0 }) return@reduce listDegs to listC -// } -// if (accDegs.size < listDegs.size) listDegs to listC else accDegs to accC -// } -// -// var thisCoefficients = coefficients.toMutableMap() -// val otherCoefficients = other.coefficients -// val quotientCoefficients = HashMap, T>() -// -// var (thisLeadingTermDegs, thisLeadingTermC) = thisCoefficients.leadingTerm() -// val (otherLeadingTermDegs, otherLeadingTermC) = otherCoefficients.leadingTerm() -// -// while ( -// thisLeadingTermDegs.size >= otherLeadingTermDegs.size && -// (0..otherLeadingTermDegs.lastIndex).all { thisLeadingTermDegs[it] >= otherLeadingTermDegs[it] } -// ) { -// val multiplierDegs = -// thisLeadingTermDegs -// .mapIndexed { index, deg -> deg - otherLeadingTermDegs.getOrElse(index) { 0 } } -// .cleanUp() -// val multiplierC = thisLeadingTermC / otherLeadingTermC -// -// quotientCoefficients[multiplierDegs] = multiplierC -// -// for ((degs, t) in otherCoefficients) { -// val productDegs = -// (0..max(degs.lastIndex, multiplierDegs.lastIndex)) -// .map { degs.getOrElse(it) { 0 } + multiplierDegs.getOrElse(it) { 0 } } -// .cleanUp() -// val productC = t * multiplierC -// thisCoefficients[productDegs] = -// if (productDegs in thisCoefficients) thisCoefficients[productDegs]!! - productC else -productC -// } -// -// thisCoefficients = thisCoefficients.filterValues { it.isNotZero() }.toMutableMap() -// -// if (thisCoefficients.isEmpty()) -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -// -// val t = thisCoefficients.leadingTerm() -// thisLeadingTermDegs = t.first -// thisLeadingTermC = t.second -// } -// -// return Polynomial.Companion.DividingResult( -// Polynomial(quotientCoefficients, toCheckInput = false), -// Polynomial(thisCoefficients, toCheckInput = false) -// ) -//} -// //// endregion // endregion From 16cf1bc65e6cd1a2955c9ca3bf5e4200eae71c71 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 00:47:07 +0300 Subject: [PATCH 024/174] Implemented all derivative-like functions --- .../kmath/functions/labeledPolynomialUtil.kt | 253 ++++++++++++++++- .../kmath/functions/numberedPolynomialUtil.kt | 255 +++++++++++------- .../kmath/functions/polynomialUtil.kt | 2 +- 3 files changed, 407 insertions(+), 103 deletions(-) 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 5689f6e1b..544cca410 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 @@ -5,8 +5,10 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.* +import kotlin.math.max // TODO: Docs @@ -321,6 +323,251 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // //// endregion -//// region Algebraic derivative and antiderivative -//// TODO -//// endregion \ No newline at end of file +// region Algebraic derivative and antiderivative + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variable: Variable, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (variable !in degs) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + optimizedMultiply(c, degs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variables: Collection, +): LabeledPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (!degs.keys.containsAll(cleanedVariables)) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari !in cleanedVariables -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]!!) } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variable: Variable, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.getOrElse(variable) { 0u } < order) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > order -> put(vari, deg - order) + } + } + }, + degs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + if (vari !in filteredVariablesAndOrders) put(vari, deg) + else { + val order = filteredVariablesAndOrders[vari]!! + if (deg > order) put(vari, deg - order) + } + } + }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Variable, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + c / optimizedMultiply(one, newDegs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variables: Collection, +): LabeledPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for (variable in cleanedVariables) put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + cleanedVariables.fold(c) { acc, variable -> acc / optimizedMultiply(one, newDegs[variable]!!) } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Variable, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + newDegs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / optimizedMultiply(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for ((variable, order) in filteredVariablesAndOrders) put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + newDegs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(one, ord) } + } + } + ) + } + } + ) +} + +// endregion \ No newline at end of file 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 de95d0151..47644b26a 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 @@ -4,7 +4,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.contracts.* import kotlin.jvm.JvmName - +import kotlin.math.max // TODO: Docs @@ -382,70 +382,51 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( ): NumberedPolynomial = algebra { NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }, - optimizedMultiply(c, degs.getOrElse(variable) { 1u }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + optimizedMultiply(c, degs[variable]) + ) + } } ) } /** * Returns algebraic derivative of received polynomial. - */ // TODO: This one does not work!!! -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: IntArray, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index !in variables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }, - optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ // TODO: This one does not work!!! + */ @UnstableKMathAPI public fun > NumberedPolynomial.derivativeWithRespectTo( algebra: A, variables: Collection, ): NumberedPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo + val maxRespectedVariable = cleanedVariables.maxOrNull()!! NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index !in variables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }, - optimizedMultiply(c, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index !in cleanedVariables -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + cleanedVariables.fold(c) { acc, variable -> optimizedMultiply(acc, degs[variable]) } + ) + } } ) } @@ -459,24 +440,60 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( variable: Int, order: UInt ): NumberedPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }.cleanUp(), + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> optimizedMultiply(acc, ord) } } - }, - degs.getOrElse(variable) { 1u }.toInt().let { - (0u until order).fold(c) { acc, ord -> - optimizedMultiply(acc, ord.toInt()) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): NumberedPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + if (index !in filteredVariablesAndOrders) return@mapIndexed deg + val order = filteredVariablesAndOrders[index]!! + if (deg >= order) deg - order else return@forEach + }.cleanUp(), + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> optimizedMultiply(acc2, ord) } + } } - } - ) - } + ) + } } ) } @@ -491,52 +508,92 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( ): NumberedPolynomial = algebra { NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> if(index != variable) deg else deg + 1u }, - c / optimizedMultiply(one, degs.getOrElse(variable) { 1u }.toInt()) - ) - } + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, + c / optimizedMultiply(one, degs[variable]) + ) + } } ) } /** * Returns algebraic antiderivative of received polynomial. - */ // TODO: This one does not work!!! -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: IntArray, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, - c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ // TODO: This one does not work!!! + */ @UnstableKMathAPI public fun > NumberedPolynomial.antiderivativeWithRespectTo( algebra: A, variables: Collection, ): NumberedPolynomial = algebra { + val cleanedVariables = variables.toSet() + if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo + val maxRespectedVariable = cleanedVariables.maxOrNull()!! NumberedPolynomial( buildMap(coefficients.size) { - coefficients.forEach { (degs, c) -> - put( - degs.mapIndexed { index, deg -> if(index !in variables) deg else deg + 1u }, - c / optimizedMultiply(one, variables.fold(1u) { acc, variable -> acc * degs.getOrElse(variable) { 1u } }.toInt()) - ) - } + coefficients + .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]) } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Int, + order: UInt +): NumberedPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + 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) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): NumberedPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / optimizedMultiply(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 a41a6cbd6..9c8cc0090 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 @@ -138,7 +138,7 @@ public fun Polynomial.nthDerivative( algebra: A, order: UInt, ): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (1..order.toInt()).fold(c) { acc, i -> acc * number(index + i) } }) + Polynomial(coefficients.drop(order.toInt()).mapIndexed { index, c -> (index + 1..index + order.toInt()).fold(c) { acc, i -> acc * number(i) } }) } /** From 9aa131a9c6c69145761bc63fdae436da01916634 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 01:06:39 +0300 Subject: [PATCH 025/174] Replaced `Variable` in `Labeled...` by `Symbol` and deleted it --- .../kmath/functions/LabeledPolynomial.kt | 145 +++++++++--------- .../functions/LabeledRationalFunction.kt | 37 ++--- .../kscience/kmath/functions/Variable.kt | 38 ----- .../kmath/functions/labeledPolynomialUtil.kt | 64 ++++---- 4 files changed, 126 insertions(+), 158 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 56dad975d..4106371cc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -40,9 +41,9 @@ internal constructor( * ) to (-6) * ) * ``` - * where `a`, `b` and `c` are corresponding [Variable] objects. + * where `a`, `b` and `c` are corresponding [Symbol] objects. */ - public val coefficients: Map, C> + public val coefficients: Map, C> ) : AbstractPolynomial { override fun toString(): String = "LabeledPolynomial$coefficients" } @@ -67,7 +68,7 @@ internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolyno /** * Returns the same degrees description of the monomial, but without zero degrees. */ -internal fun Map.cleanUp() = filterValues { it > 0U } +internal fun Map.cleanUp() = filterValues { it > 0U } // endregion @@ -75,10 +76,10 @@ internal fun Map.cleanUp() = filterValues { it > 0U } //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { +//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { // if (!toCheckInput) return LabeledPolynomial(coefs) // -// val fixedCoefs = mutableMapOf, C>() +// val fixedCoefs = mutableMapOf, C>() // // for (entry in coefs) { // val key = entry.key.cleanUp() @@ -93,10 +94,10 @@ internal fun Map.cleanUp() = filterValues { it > 0U } // //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { +//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { // if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) // -// val fixedCoefs = mutableMapOf, C>() +// val fixedCoefs = mutableMapOf, C>() // // for (entry in pairs) { // val key = entry.first.cleanUp() @@ -112,20 +113,20 @@ internal fun Map.cleanUp() = filterValues { it > 0U } //// TODO: Do not know how to make it without context receivers //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) // //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) // //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") -//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) +//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) // //context(LabeledPolynomialSpace>) -//public fun Variable.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +//public fun Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) // endregion @@ -140,24 +141,24 @@ public class LabeledPolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - // region Variable-integer relation - public operator fun Variable.plus(other: Int): LabeledPolynomial = + // region Symbol-integer relation + public operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, + emptyMap() to constantOne * other, )) - public operator fun Variable.minus(other: Int): LabeledPolynomial = + public operator fun Symbol.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, + emptyMap() to constantOne * other, )) - public operator fun Variable.times(other: Int): LabeledPolynomial = + public operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, @@ -165,23 +166,23 @@ public class LabeledPolynomialSpace>( // endregion // region Integer-variable relation - public operator fun Int.plus(other: Variable): LabeledPolynomial = + public operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, + emptyMap() to constantOne * this@plus, )) - public operator fun Int.minus(other: Variable): LabeledPolynomial = + public operator fun Int.minus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, + emptyMap() to constantOne * this@minus, )) - public operator fun Int.times(other: Variable): LabeledPolynomial = + public operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, @@ -201,7 +202,7 @@ public class LabeledPolynomialSpace>( coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } + other @@ -221,7 +222,7 @@ public class LabeledPolynomialSpace>( coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } - other @@ -257,7 +258,7 @@ public class LabeledPolynomialSpace>( other.coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = this@plus + getOrElse(degs) { constantZero } @@ -277,7 +278,7 @@ public class LabeledPolynomialSpace>( other.coefficients .toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = this@minus - getOrElse(degs) { constantZero } @@ -301,47 +302,47 @@ public class LabeledPolynomialSpace>( // endregion // region Constant-variable relation - public operator fun C.plus(other: Variable): LabeledPolynomial = + public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, + emptyMap() to this@plus, )) - public operator fun C.minus(other: Variable): LabeledPolynomial = + public operator fun C.minus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, + emptyMap() to this@minus, )) - public operator fun C.times(other: Variable): LabeledPolynomial = + public operator fun C.times(other: Symbol): LabeledPolynomial = if (isZero()) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) // endregion - // region Variable-constant relation - public operator fun Variable.plus(other: C): LabeledPolynomial = + // region Symbol-constant relation + public operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, + emptyMap() to other, )) - public operator fun Variable.minus(other: C): LabeledPolynomial = + public operator fun Symbol.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) else LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, + emptyMap() to other, )) - public operator fun Variable.times(other: C): LabeledPolynomial = + public operator fun Symbol.times(other: C): LabeledPolynomial = if (other.isZero()) zero else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, @@ -355,11 +356,11 @@ public class LabeledPolynomialSpace>( override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) else LabeledPolynomial( toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = this@plus + getOrElse(degs) { constantZero } @@ -374,13 +375,13 @@ public class LabeledPolynomialSpace>( override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = if (this.isZero()) other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) else LabeledPolynomial( toMutableMap() .apply { forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - val degs = emptyMap() + val degs = emptyMap() val result = this@minus - getOrElse(degs) { constantZero } @@ -409,11 +410,11 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() .apply { - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } + other @@ -428,13 +429,13 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() .apply { forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - val degs = emptyMap() + val degs = emptyMap() val result = getOrElse(degs) { constantZero } - other @@ -456,8 +457,8 @@ public class LabeledPolynomialSpace>( ) // endregion - // region Variable-variable relation - public operator fun Variable.plus(other: Variable): LabeledPolynomial = + // region Symbol-variable relation + public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 )) @@ -465,13 +466,13 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, )) - public operator fun Variable.minus(other: Variable): LabeledPolynomial = + public operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, )) - public operator fun Variable.times(other: Variable): LabeledPolynomial = + public operator fun Symbol.times(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 2U) to constantOne )) @@ -480,8 +481,8 @@ public class LabeledPolynomialSpace>( )) // endregion - // region Variable-polynomial relation - public operator fun Variable.plus(other: LabeledPolynomial): LabeledPolynomial = + // region Symbol-polynomial relation + public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( @@ -496,7 +497,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Variable.minus(other: LabeledPolynomial): LabeledPolynomial = + public operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( @@ -513,7 +514,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Variable.times(other: LabeledPolynomial): LabeledPolynomial = + public operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } @@ -521,7 +522,7 @@ public class LabeledPolynomialSpace>( // endregion // region Polynomial-variable relation - public operator fun LabeledPolynomial.plus(other: Variable): LabeledPolynomial = + public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -536,7 +537,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.minus(other: Variable): LabeledPolynomial = + public operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -551,7 +552,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.times(other: Variable): LabeledPolynomial = + public operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomial( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } @@ -610,11 +611,11 @@ public class LabeledPolynomialSpace>( /** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) + override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) + override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) /** * Checks equality of the polynomials. @@ -642,7 +643,7 @@ public class LabeledPolynomialSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map + public val LabeledPolynomial.degrees: Map get() = buildMap { coefficients.entries.forEach { (degs, c) -> @@ -654,7 +655,7 @@ public class LabeledPolynomialSpace>( /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set + public val LabeledPolynomial.variables: Set get() = buildSet { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } @@ -695,29 +696,29 @@ public class LabeledPolynomialSpace>( } // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) // @Suppress("NOTHING_TO_INLINE") // @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) // // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } +// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } // @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } +// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } // // @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) +// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) // @Suppress("NOTHING_TO_INLINE") // @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) +// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) // endregion // region Utilities // TODO: Move to region internal utilities with context receiver @JvmName("applyAndRemoveZerosInternal") - internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { + internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -725,10 +726,10 @@ public class LabeledPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) return this } - internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = + internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = toMutableMap().applyAndRemoveZeros(block) @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap { builderAction() @@ -736,7 +737,7 @@ public class LabeledPolynomialSpace>( } } @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildMap(capacity) { builderAction() diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index df4441127..3077a2b82 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke @@ -62,22 +63,22 @@ internal fun labeledRationalFunctionError(message: Any): Nothing = throw Labeled // ) // TODO: Rewrite former constructors as fabrics -//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( +//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( //LabeledPolynomial(numeratorCoefficients), //LabeledPolynomial(denominatorCoefficients) //) // -//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( +//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( //LabeledPolynomial(numeratorCoefficients), //LabeledPolynomial(denominatorCoefficients) //) // //constructor(numerator: LabeledPolynomial) : this(numerator, numerator.getOne()) -//constructor(numeratorCoefficients: Map, C>) : this( +//constructor(numeratorCoefficients: Map, C>) : this( //LabeledPolynomial(numeratorCoefficients) //) // -//constructor(numeratorCoefficients: Collection, C>>) : this( +//constructor(numeratorCoefficients: Collection, C>>) : this( //LabeledPolynomial(numeratorCoefficients) //) @@ -338,11 +339,11 @@ public class LabeledRationalFunctionSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } + public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } + public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -353,7 +354,7 @@ public class LabeledRationalFunctionSpace>( /** * Count of all variables that appear in the polynomial in positive exponents. */ - public val LabeledRationalFunction.variables: Set + public val LabeledRationalFunction.variables: Set get() = numerator.variables union denominator.variables /** * Count of all variables that appear in the polynomial in positive exponents. @@ -381,21 +382,21 @@ public class LabeledRationalFunctionSpace>( denominator * other ) -// operator fun invoke(arg: Map): LabeledRationalFunction = +// operator fun invoke(arg: Map): LabeledRationalFunction = // LabeledRationalFunction( // numerator(arg), // denominator(arg) // ) // // @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = +// operator fun invoke(arg: Map>): LabeledRationalFunction = // LabeledRationalFunction( // numerator(arg), // denominator(arg) // ) // // @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { +// operator fun invoke(arg: Map>): LabeledRationalFunction { // var num = numerator invokeRFTakeNumerator arg // var den = denominator invokeRFTakeNumerator arg // for (variable in variables) if (variable in arg) { @@ -410,56 +411,56 @@ public class LabeledRationalFunctionSpace>( // // override fun toString(): String = toString(emptyMap()) // -// fun toString(names: Map = emptyMap()): String = +// fun toString(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toString(names) // else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" // } // -// fun toString(namer: (Variable) -> String): String = +// fun toString(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toString(namer) // else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" // } // -// fun toStringWithBrackets(names: Map = emptyMap()): String = +// fun toStringWithBrackets(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toStringWithBrackets(names) // else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" // } // -// fun toStringWithBrackets(namer: (Variable) -> String): String = +// fun toStringWithBrackets(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toStringWithBrackets(namer) // else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" // } // -// fun toReversedString(names: Map = emptyMap()): String = +// fun toReversedString(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedString(names) // else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" // } // -// fun toReversedString(namer: (Variable) -> String): String = +// fun toReversedString(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedString(namer) // else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" // } // -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = +// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedStringWithBrackets(names) // else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" // } // -// fun toReversedStringWithBrackets(namer: (Variable) -> String): String = +// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = // when (true) { // numerator.isZero() -> "0" // denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt deleted file mode 100644 index 410604fd3..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Variable.kt +++ /dev/null @@ -1,38 +0,0 @@ -package space.kscience.kmath.functions - -import kotlin.reflect.KProperty - - -/** - * Represents class of labeled variables like usual - * `x`, `y`, `z`, `a`, `b`, `n`, `m`, etc. - * - * Variables does not contain any information about field (or ring, ets.) they are considered in - * and therefore about coefficient. - * - * @property name Is the label or name of variable. For `x` it is `"x"`, for `n` – `"n"`, etc. - */ -public data class Variable (val name: String) : Comparable { - /** - * Represents the variable as a string. - * - * @return Only name of the variable. - */ - override fun toString(): String = name - /** - * Compares two variables. - * Comparison is realised by comparison of variables' names. - * - * Used in [LabeledPolynomial] and [LabeledRationalFunction] to sort monomials in - * [LabeledPolynomial.toString] and [LabeledRationalFunction.toString] in lexicographic order. - * - * @see Comparable.compareTo - * @sample LabeledPolynomial.monomialComparator - * @return Only name of the variable. - */ - override fun compareTo(other: Variable): Int = name.compareTo(other.name) - - public companion object { - public operator fun getValue(thisRef: Any?, property: KProperty<*>) : Variable = Variable(property.name) - } -} \ 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 544cca410..9408a09f2 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 @@ -5,10 +5,14 @@ package space.kscience.kmath.functions +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.math.max +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract // TODO: Docs @@ -31,10 +35,10 @@ import kotlin.math.max // //// endregion -//// region Variables +//// region Symbols // //context(LabeledPolynomialSpace) -//fun > power(arg: Variable, pow: UInt): LabeledPolynomial = +//fun > power(arg: Symbol, pow: UInt): LabeledPolynomial = // if (pow == 0U) one // else LabeledPolynomial(mapOf( // mapOf(arg to pow) to constantOne @@ -45,7 +49,7 @@ import kotlin.math.max //// region Polynomials // //context(LabeledPolynomialSpace) -//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } +//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } // //context(LabeledPolynomialSpace) //fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = @@ -97,7 +101,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = // coefficients.entries // .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -130,7 +134,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = // coefficients.entries // .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -163,7 +167,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = // with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } // ///** @@ -172,7 +176,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = // with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } // ///** @@ -180,7 +184,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = // coefficients.entries // .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -213,7 +217,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = // coefficients.entries // .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } // .asSequence() @@ -246,7 +250,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = +//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = // with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } // ///** @@ -255,7 +259,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // * Consider that monomials are sorted in **reversed** lexicographic order. // */ //context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Variable) -> String): String = +//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = // with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } // //// endregion @@ -279,7 +283,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //// region Polynomial substitution and functional representation // -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { +//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { // if (coefficients.isEmpty()) return this@substitute // LabeledPolynomial( // buildMap { @@ -297,7 +301,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as //// possible on it //@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = +//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = // ring.labeledPolynomial { // if (coefficients.isEmpty()) return zero // coefficients @@ -315,10 +319,10 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // //// TODO: Substitute rational function // -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = +//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = // { substitute(ring, it) } // -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = +//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = // { substitute(ring, it) } // //// endregion @@ -331,7 +335,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi @UnstableKMathAPI public fun > LabeledPolynomial.derivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, ): LabeledPolynomial = algebra { LabeledPolynomial( buildMap(coefficients.size) { @@ -360,7 +364,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.derivativeWithRespectTo( algebra: A, - variables: Collection, + variables: Collection, ): LabeledPolynomial = algebra { val cleanedVariables = variables.toSet() if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo @@ -391,7 +395,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.nthDerivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, order: UInt ): LabeledPolynomial = algebra { if (order == 0u) return this@nthDerivativeWithRespectTo @@ -425,7 +429,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.nthDerivativeWithRespectTo( algebra: A, - variablesAndOrders: Map, + variablesAndOrders: Map, ): LabeledPolynomial = algebra { val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo @@ -462,13 +466,13 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.antiderivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, ): LabeledPolynomial = algebra { LabeledPolynomial( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { put(variable, 1u) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } @@ -487,7 +491,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.antiderivativeWithRespectTo( algebra: A, - variables: Collection, + variables: Collection, ): LabeledPolynomial = algebra { val cleanedVariables = variables.toSet() if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo @@ -495,7 +499,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { for (variable in cleanedVariables) put(variable, 1u) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } @@ -514,7 +518,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( @UnstableKMathAPI public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( algebra: A, - variable: Variable, + variable: Symbol, order: UInt ): LabeledPolynomial = algebra { if (order == 0u) return this@nthAntiderivativeWithRespectTo @@ -522,7 +526,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { put(variable, order) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } @@ -544,7 +548,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo @UnstableKMathAPI public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( algebra: A, - variablesAndOrders: Map, + variablesAndOrders: Map, ): LabeledPolynomial = algebra { val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo @@ -552,7 +556,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { + val newDegs = buildMap(degs.size + 1) { for ((variable, order) in filteredVariablesAndOrders) put(variable, order) for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) } 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 026/174] 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) } }) } From 3c9d8a4eee586962ba59a3790c3d7ddb18572637 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 22:44:55 +0300 Subject: [PATCH 027/174] Deleted all region marks --- .../kmath/functions/AbstractPolynomial.kt | 27 ------- .../functions/AbstractRationalFunction.kt | 79 ------------------- .../kmath/functions/LabeledPolynomial.kt | 40 +--------- .../functions/LabeledRationalFunction.kt | 27 +------ .../kmath/functions/NumberedPolynomial.kt | 29 +------ .../functions/NumberedRationalFunction.kt | 27 +------ .../kscience/kmath/functions/Polynomial.kt | 1 - .../kmath/functions/RationalFunction.kt | 24 +----- .../kmath/functions/labeledPolynomialUtil.kt | 37 +-------- .../functions/labeledRationalFunctionUtil.kt | 10 +-- .../kmath/functions/numberedPolynomialUtil.kt | 42 +--------- .../functions/numberedRationalFunctionUtil.kt | 10 +-- .../kmath/functions/polynomialUtil.kt | 14 +--- .../kmath/functions/rationalFunctionUtil.kt | 12 +-- 14 files changed, 11 insertions(+), 368 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 2d2d22fd3..aacf055fa 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 @@ -23,7 +23,6 @@ public interface AbstractPolynomial */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractPolynomialSpace> : Ring

{ - // region Constant-integer relation /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). * @@ -42,9 +41,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C - // endregion - // region Integer-constant relation /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * @@ -63,9 +60,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: C): C - // endregion - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -84,9 +79,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -105,9 +98,7 @@ public interface AbstractPolynomialSpace> : Ring

* The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) - // endregion - // region Constant-constant relation /** * Returns the same constant. */ @@ -178,9 +169,7 @@ public interface AbstractPolynomialSpace> : Ring

* Instance of unit constant (unit of the underlying ring). */ public val constantOne: C - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -193,9 +182,7 @@ public interface AbstractPolynomialSpace> : Ring

* Returns product of the constant represented as polynomial and the polynomial. */ public operator fun C.times(other: P): P - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -208,9 +195,7 @@ public interface AbstractPolynomialSpace> : Ring

* Returns product of the constant represented as polynomial and the polynomial. */ public operator fun P.times(other: C): P - // endregion - // region Polynomial-polynomial relation /** * Returns the same polynomial. */ @@ -278,10 +263,7 @@ public interface AbstractPolynomialSpace> : Ring

* Checks NOT equality of the polynomials. */ public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - // endregion - // Not sure is it necessary... - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -314,12 +296,9 @@ public interface AbstractPolynomialSpace> : Ring

* Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") - // endregion - // region Legacy of Ring interface override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right - // endregion } /** @@ -335,7 +314,6 @@ public interface AbstractPolynomialSpaceOverRing, A: public val ring: A - // region Constant-integer relation /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). * @@ -354,9 +332,7 @@ public interface AbstractPolynomialSpaceOverRing, A: * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyBySquaring(this@times, other) } - // endregion - // region Integer-constant relation /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * @@ -375,9 +351,7 @@ public interface AbstractPolynomialSpaceOverRing, A: * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: C): C = ring { multiplyBySquaring(other, this@times) } - // endregion - // region Constant-constant relation /** * Returns negation of the constant. */ @@ -412,5 +386,4 @@ public interface AbstractPolynomialSpaceOverRing, A: * Instance of unit constant (unit of the underlying ring). */ public override val constantOne: C get() = ring.one - // endregion } \ No newline at end of file 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 c6f1d7a7a..b9ca01da4 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 @@ -30,7 +30,6 @@ public interface AbstractRationalFunction> { */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { - // region Constant-integer relation /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). * @@ -49,9 +48,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C - // endregion - // region Integer-constant relation /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * @@ -70,9 +67,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: C): C - // endregion - // region Polynomial-integer relation /** * Returns sum of the constant and the integer represented as polynomial. * @@ -91,9 +86,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the constant. * @@ -112,9 +105,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: P): P - // endregion - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -133,9 +124,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -154,9 +143,7 @@ public interface AbstractRationalFunctionalSpace, R: * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) - // endregion - // region Constant-constant relation /** * Returns the same constant. */ @@ -227,9 +214,7 @@ public interface AbstractRationalFunctionalSpace, R: * Instance of unit constant (unit of the underlying ring). */ public val constantOne: C - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -242,9 +227,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as polynomial and the polynomial. */ public operator fun C.times(other: P): P - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -257,9 +240,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as polynomial and the polynomial. */ public operator fun P.times(other: C): P - // endregion - // region Polynomial-polynomial relation /** * Returns the same polynomial. */ @@ -327,9 +308,7 @@ public interface AbstractRationalFunctionalSpace, R: * Checks NOT equality of the polynomials. */ public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -342,9 +321,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as polynomial and the rational function. */ public operator fun C.times(other: R): R - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -357,9 +334,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the constant represented as rational function and the rational function. */ public operator fun R.times(other: C): R - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -372,9 +347,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the polynomial represented as polynomial and the rational function. */ public operator fun P.times(other: R): R - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -387,9 +360,7 @@ public interface AbstractRationalFunctionalSpace, R: * Returns product of the polynomial represented as rational function and the rational function. */ public operator fun R.times(other: P): R - // endregion - // region Rational-rational relation /** * Returns the same rational function. */ @@ -457,10 +428,7 @@ public interface AbstractRationalFunctionalSpace, R: * Checks NOT equality of the polynomials. */ public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - // endregion - // Not sure is it necessary... - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -494,10 +462,6 @@ public interface AbstractRationalFunctionalSpace, R: */ public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") - // endregion - - // Not sure is it necessary... - // region Rational properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -509,25 +473,8 @@ public interface AbstractRationalFunctionalSpace, R: */ public val R.denominatorDegree: Int get() = denominator.degree - // TODO: Перенести в реализацию -// fun R.substitute(argument: C): C -// fun R.substitute(argument: P): R -// fun R.substitute(argument: R): R -// -// fun R.asFunction(): (C) -> C = /*this::substitute*/ { this.substitute(it) } -// fun R.asFunctionOnConstants(): (C) -> C = /*this::substitute*/ { this.substitute(it) } -// fun P.asFunctionOnPolynomials(): (P) -> R = /*this::substitute*/ { this.substitute(it) } -// fun R.asFunctionOnRationalFunctions(): (R) -> R = /*this::substitute*/ { this.substitute(it) } -// -// operator fun R.invoke(argument: C): C = this.substitute(argument) -// operator fun R.invoke(argument: P): R = this.substitute(argument) -// operator fun R.invoke(argument: R): R = this.substitute(argument) - // endregion - - // region Legacy override fun add(left: R, right: R): R = left + right override fun multiply(left: R, right: R): R = left * right - // endregion } /** @@ -544,7 +491,6 @@ public interface AbstractRationalFunctionalSpaceOverRing.cleanUp() = filterValues { it > 0U } -// endregion - -// region Constructors and converters - //context(LabeledPolynomialSpace>) //@Suppress("FunctionName") //internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { @@ -128,8 +122,6 @@ internal fun Map.cleanUp() = filterValues { it > 0U } public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) -// endregion - /** * Space of polynomials. * @@ -140,8 +132,6 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia public class LabeledPolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - - // region Symbol-integer relation public operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, @@ -163,9 +153,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, )) - // endregion - // region Integer-variable relation public operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, @@ -187,9 +175,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, )) - // endregion - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -243,9 +229,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -299,9 +283,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Constant-variable relation public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, @@ -323,9 +305,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) - // endregion - // region Symbol-constant relation public operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, @@ -347,9 +327,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, )) - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -401,9 +379,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -455,9 +431,7 @@ public class LabeledPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Symbol-variable relation public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 @@ -479,9 +453,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial(mapOf( mapOf(this to 1U, other to 1U) to constantOne, )) - // endregion - // region Symbol-polynomial relation public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) @@ -519,9 +491,7 @@ public class LabeledPolynomialSpace>( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } ) - // endregion - // region Polynomial-variable relation public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) @@ -557,9 +527,7 @@ public class LabeledPolynomialSpace>( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } ) - // endregion - // region Polynomial-polynomial relation /** * Returns negation of the polynomial. */ @@ -626,10 +594,7 @@ public class LabeledPolynomialSpace>( else -> coefficients.size == other.coefficients.size && coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } } - // endregion - // Not sure is it necessary... - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -713,10 +678,8 @@ public class LabeledPolynomialSpace>( // @Suppress("NOTHING_TO_INLINE") // @JvmName("invokePolynomial") // public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) - // endregion - // region Utilities - // TODO: Move to region internal utilities with context receiver + // TODO: Move to other internal utilities with context receiver @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { @@ -744,5 +707,4 @@ public class LabeledPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } - // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 3077a2b82..3908933e6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -17,8 +17,6 @@ public class LabeledRationalFunction( override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// region Internal utilities - /** * Represents internal [LabeledRationalFunction] errors. */ @@ -34,9 +32,6 @@ internal class LabeledRationalFunctionError : Error { */ internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString()) -// endregion - -// region Constructors and converters // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) @@ -82,8 +77,6 @@ internal fun labeledRationalFunctionError(message: Any): Nothing = throw Labeled //LabeledPolynomial(numeratorCoefficients) //) -// endregion - public class LabeledRationalFunctionSpace>( public val ring: A, ) : AbstractRationalFunctionalSpaceOverPolynomialSpace< @@ -95,7 +88,6 @@ public class LabeledRationalFunctionSpace>( override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -126,9 +118,7 @@ public class LabeledRationalFunctionSpace>( numerator * other, denominator ) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -159,9 +149,7 @@ public class LabeledRationalFunctionSpace>( this * other.numerator, other.denominator ) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -186,9 +174,7 @@ public class LabeledRationalFunctionSpace>( this * other.numerator, other.denominator ) - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -213,9 +199,7 @@ public class LabeledRationalFunctionSpace>( numerator * other, denominator ) - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -240,9 +224,7 @@ public class LabeledRationalFunctionSpace>( this * other.numerator, other.denominator ) - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -267,9 +249,7 @@ public class LabeledRationalFunctionSpace>( numerator * other, denominator ) - // endregion - // region Rational-rational relation /** * Returns negation of the rational function. */ @@ -329,9 +309,7 @@ public class LabeledRationalFunctionSpace>( return numerator * other.denominator equalsTo other.numerator * denominator } - // endregion - // region Polynomial properties /** * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents * in which they are appeared in the polynomial. @@ -348,9 +326,7 @@ public class LabeledRationalFunctionSpace>( * Count of all variables that appear in the polynomial in positive exponents. */ public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - // endregion - // region Rational properties /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -360,9 +336,8 @@ public class LabeledRationalFunctionSpace>( * Count of all variables that appear in the polynomial in positive exponents. */ public val LabeledRationalFunction.countOfVariables: Int get() = variables.size - // endregion - // region REST TODO: Разобрать + // TODO: Разобрать public operator fun LabeledRationalFunction.div(other: LabeledRationalFunction): LabeledRationalFunction = LabeledRationalFunction( diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index a1033fcc4..fe6bb597d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -47,8 +47,6 @@ internal constructor( override fun toString(): String = "NumberedPolynomial$coefficients" } -// region Internal utilities - /** * Represents internal [Polynomial] errors. */ @@ -69,10 +67,6 @@ internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialEr */ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) -// endregion - -// region Constructors and converters - //context(NumberedPolynomialSpace>) //@Suppress("FunctionName") //internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { @@ -124,8 +118,6 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -// endregion - /** * Space of polynomials. * @@ -136,7 +128,6 @@ public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolyno public open class NumberedPolynomialSpace>( public final override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -190,9 +181,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -246,9 +235,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -300,9 +287,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> this@times * c } } ) - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -352,9 +337,7 @@ public open class NumberedPolynomialSpace>( mapValues { (_, c) -> c * other } } ) - // endregion - // region Polynomial-polynomial relation /** * Returns negation of the polynomial. */ @@ -463,10 +446,7 @@ public open class NumberedPolynomialSpace>( else -> coefficients.size == other.coefficients.size && coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } } - // endregion - // Not sure is it necessary... - // region Polynomial properties // TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables` /** * Count of all variables that appear in the polynomial in positive exponents. @@ -545,10 +525,8 @@ public open class NumberedPolynomialSpace>( @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - // endregion - // region Utilities - // TODO: Move to region internal utilities with context receiver + // TODO: Move to other internal utilities with context receiver @JvmName("applyAndRemoveZerosInternal") internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { contract { @@ -576,9 +554,6 @@ public open class NumberedPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } - // endregion - - // region Constructors and converters @Suppress("FunctionName") internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { @@ -622,6 +597,4 @@ public open class NumberedPolynomialSpace>( @Suppress("FunctionName") public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) - - // endregion } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index a81795c81..745df10e8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -16,8 +16,6 @@ public class NumberedRationalFunction internal constructor( override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// region Internal utilities - /** * Represents internal [NumberedRationalFunction] errors. */ @@ -33,9 +31,6 @@ internal class NumberedRationalFunctionError : Error { */ internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString()) -// endregion - -// region Constructors and converters // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) @@ -78,8 +73,6 @@ internal fun numberedRationalFunctionError(message: Any): Nothing = throw Number //Polynomial(numeratorCoefficients) //) -// endregion - public class NumberedRationalFunctionSpace> ( public val ring: A, ) : AbstractRationalFunctionalSpaceOverPolynomialSpace< @@ -91,7 +84,6 @@ public class NumberedRationalFunctionSpace> ( override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -122,9 +114,7 @@ public class NumberedRationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -155,9 +145,7 @@ public class NumberedRationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -182,9 +170,7 @@ public class NumberedRationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -209,9 +195,7 @@ public class NumberedRationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -236,9 +220,7 @@ public class NumberedRationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -263,9 +245,7 @@ public class NumberedRationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Rational-rational relation /** * Returns negation of the rational function. */ @@ -325,9 +305,7 @@ public class NumberedRationalFunctionSpace> ( return numerator * other.denominator equalsTo other.numerator * denominator } - // endregion - // region Polynomial properties /** * Count of all variables that appear in the polynomial in positive exponents. */ @@ -340,17 +318,14 @@ public class NumberedRationalFunctionSpace> ( * And size of the list is [countOfVariables]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - // endregion - // region Rational properties /** * Count of all variables that appear in the polynomial in positive exponents. */ public val NumberedRationalFunction.countOfVariables: Int get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) } - // endregion - // region REST TODO: Разобрать + // TODO: Разобрать public operator fun NumberedRationalFunction.div(other: NumberedRationalFunction): NumberedRationalFunction = NumberedRationalFunction( 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 2f7976da6..3f3838f53 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 @@ -91,7 +91,6 @@ public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -//@Suppress("INAPPLICABLE_JVM_NAME") // TODO: KT-31420 public open class PolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 441136a64..5ff3edd2e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -18,8 +18,6 @@ public data class RationalFunction internal constructor ( override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// region Internal utilities - /** * Represents internal [RationalFunction] errors. */ @@ -35,9 +33,6 @@ internal class RationalFunctionError : Error { */ internal fun rationalFunctionError(message: Any): Nothing = throw RationalFunctionError(message.toString()) -// endregion - -// region Constructors and converters // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) @@ -63,8 +58,6 @@ internal fun rationalFunctionError(message: Any): Nothing = throw RationalFuncti // Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) // ) -// endregion - public class RationalFunctionSpace> ( public val ring: A, ) : AbstractRationalFunctionalSpaceOverPolynomialSpace< @@ -76,7 +69,6 @@ public class RationalFunctionSpace> ( override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) - // region Rational-integer relation /** * Returns sum of the rational function and the integer represented as rational function. * @@ -107,9 +99,7 @@ public class RationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Integer-Rational relation /** * Returns sum of the integer represented as rational function and the rational function. * @@ -140,9 +130,7 @@ public class RationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Constant-rational relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -167,9 +155,7 @@ public class RationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-constant relation /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -194,9 +180,7 @@ public class RationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Polynomial-rational relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -221,9 +205,7 @@ public class RationalFunctionSpace> ( this * other.numerator, other.denominator ) - // endregion - // region Rational-polynomial relation /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -248,9 +230,7 @@ public class RationalFunctionSpace> ( numerator * other, denominator ) - // endregion - // region Rational-rational relation /** * Returns negation of the rational function. */ @@ -298,9 +278,8 @@ public class RationalFunctionSpace> ( numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false else -> numerator * other.denominator equalsTo other.numerator * denominator } - // endregion - // region REST TODO: Разобрать + // TODO: Разобрать public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = RationalFunction( @@ -383,5 +362,4 @@ public class RationalFunctionSpace> ( // numerator.removeZeros(), // denominator.removeZeros() // ) - // endregion } \ 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 516e76b8f..19417d767 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 @@ -17,10 +17,6 @@ import kotlin.contracts.contract // TODO: Docs -// region Sort of legacy - -//// region Constants -// //// TODO: Reuse underlying ring extensions // //context(LabeledPolynomialSpace) @@ -33,9 +29,7 @@ import kotlin.contracts.contract //context(LabeledPolynomialSpace) //fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } // -//// endregion -//// region Symbols // //context(LabeledPolynomialSpace) //fun > power(arg: Symbol, pow: UInt): LabeledPolynomial = @@ -44,9 +38,7 @@ import kotlin.contracts.contract // mapOf(arg to pow) to constantOne // )) // -//// endregion -//// region Polynomials // //context(LabeledPolynomialSpace) //fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } @@ -71,11 +63,6 @@ import kotlin.contracts.contract // else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") // } // -//// endregion - -// endregion - -// region Utilities /** * Crates a [LabeledPolynomialSpace] over received ring. @@ -92,10 +79,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi return LabeledPolynomialSpace(this).block() } -// endregion - -//// region String representations -// ///** // * Represents the polynomial as a [String] with names of variables substituted with names from [names]. // * Consider that monomials are sorted in lexicographic order. @@ -261,13 +244,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi //context(LabeledPolynomialSpace) //fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = // with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -//// endregion -// region Operator extensions - -//// region Field case -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -276,13 +253,7 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // .mapValues { it.value / other }, // toCheckInput = false // ) -// -//// endregion -// endregion - -//// region Polynomial substitution and functional representation -// //public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { // if (coefficients.isEmpty()) return this@substitute // LabeledPolynomial( @@ -324,10 +295,6 @@ public inline fun , R> A.labeledPolynomial(block: LabeledPolynomi // //fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = // { substitute(ring, it) } -// -//// endregion - -// region Algebraic derivative and antiderivative /** * Returns algebraic derivative of received polynomial. @@ -572,6 +539,4 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo } } ) -} - -// endregion \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index 575dfed48..61f443871 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -6,18 +6,10 @@ package space.kscience.kmath.functions -//// region Operator extensions -// -//// region Field case -// //fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) // return LabeledRationalFunction( // numerator / greatestCommonDivider, // denominator / greatestCommonDivider // ) -//} -// -//// endregion -// -//// endregion \ No newline at end of file +//} \ No newline at end of file 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 ac411fc28..b2778343d 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 @@ -9,10 +9,6 @@ import kotlin.math.max // TODO: Docs -// region Sort of legacy - -//// region Constants -// //// TODO: Reuse underlying ring extensions // //context(NumberedPolynomialSpace) @@ -21,11 +17,7 @@ import kotlin.math.max // //context(NumberedPolynomialSpace) //public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } -// -//// endregion -//// region Polynomials -// //context(NumberedPolynomialSpace) //public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } // @@ -48,12 +40,6 @@ import kotlin.math.max // exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) // else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") // } -// -//// endregion - -// endregion - -// region Utilities /** * Crates a [NumberedPolynomialSpace] over received ring. @@ -70,10 +56,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno return NumberedPolynomialSpace(this).block() } -// endregion - -//// region String representations -// ///** // * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. // * Consider that monomials are sorted in lexicographic order. @@ -237,11 +219,7 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno //context(NumberedPolynomialSpace) //public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = // with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -//// endregion -//// region Polynomial substitution and functional representation -// //public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { // if (coefficients.isEmpty()) return this@substitute // NumberedPolynomial( @@ -283,13 +261,7 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // //public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = // { substitute(ring, it) } -// -//// endregion -// region Operator extensions - -//// region Field case -// //operator fun > Polynomial.div(other: T): Polynomial = // if (other.isZero()) throw ArithmeticException("/ by zero") // else @@ -298,12 +270,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // .mapValues { it.value / other }, // toCheckInput = false // ) -// -//// endregion - -// endregion - -// region Polynomial substitution and functional representation // TODO: May be apply Horner's method too? /** @@ -368,10 +334,6 @@ public fun > NumberedPolynomial.asFunction(ring: A): (Map> NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } -// endregion - -// region Algebraic derivative and antiderivative - /** * Returns algebraic derivative of received polynomial. */ @@ -596,6 +558,4 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT } } ) -} - -// endregion \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt index 7c8120c68..035e201f7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -6,18 +6,10 @@ package space.kscience.kmath.functions -//// region Operator extensions -// -//// region Field case -// //fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) // return NumberedRationalFunction( // numerator / greatestCommonDivider, // denominator / greatestCommonDivider // ) -//} -// -//// endregion -// -//// endregion \ No newline at end of file +//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index 2d0377d2c..e6d6b1ae6 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 @@ -14,8 +14,6 @@ import kotlin.math.min import kotlin.math.pow -// region Utilities - /** * Removes zeros on the end of the coefficient list of polynomial. */ @@ -51,10 +49,6 @@ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace< return ScalablePolynomialSpace(this).block() } -// endregion - -// region Polynomial substitution and functional representation - // TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. @@ -116,10 +110,6 @@ public fun > Polynomial.asFunction(ring: A): (C) -> C = { subs */ public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } -// endregion - -// region Algebraic derivative and antiderivative - /** * Returns algebraic derivative of received polynomial. */ @@ -180,6 +170,4 @@ public fun > Polynomial.integrate( ): C = algebra { val integral = antiderivative(algebra) integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} - -// endregion \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index d5bbc3b82..359c781b5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -6,10 +6,6 @@ package space.kscience.kmath.functions -// region Operator extensions - -// region Field case - //operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) // //fun > RationalFunction.reduced(): RationalFunction = @@ -20,11 +16,6 @@ package space.kscience.kmath.functions // ) // } -// endregion - -// endregion - -// region Derivatives ///** // * Returns result of applying formal derivative to the polynomial. // * @@ -35,5 +26,4 @@ package space.kscience.kmath.functions // RationalFunction( // numerator.derivative() * denominator - denominator.derivative() * numerator, // denominator * denominator -// ) -// endregion \ No newline at end of file +// ) \ No newline at end of file From 75fd9207352c2cdbd4ad4de1275a0f8639f83f76 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 23:22:51 +0300 Subject: [PATCH 028/174] Deleted suddenly missed region marks and unused error classes --- .../kmath/functions/LabeledPolynomial.kt | 15 -------- .../functions/LabeledRationalFunction.kt | 15 -------- .../kmath/functions/NumberedPolynomial.kt | 17 +-------- .../functions/NumberedRationalFunction.kt | 15 -------- .../kscience/kmath/functions/Polynomial.kt | 37 ------------------- .../kmath/functions/RationalFunction.kt | 15 -------- 6 files changed, 1 insertion(+), 113 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index f4dd74b94..d263b7102 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -48,21 +48,6 @@ internal constructor( override fun toString(): String = "LabeledPolynomial$coefficients" } -/** - * Represents internal [LabeledPolynomial] errors. - */ -internal class LabeledPolynomialError: Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [LabeledPolynomialError] with the given [message]. - */ -internal fun labeledPolynomialError(message: Any): Nothing = throw LabeledPolynomialError(message.toString()) - /** * Returns the same degrees description of the monomial, but without zero degrees. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 3908933e6..9b5022f85 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -17,21 +17,6 @@ public class LabeledRationalFunction( override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -/** - * Represents internal [LabeledRationalFunction] errors. - */ -internal class LabeledRationalFunctionError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [LabeledRationalFunctionError] with the given [message]. - */ -internal fun labeledRationalFunctionError(message: Any): Nothing = throw LabeledRationalFunctionError(message.toString()) - // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index fe6bb597d..307b78f29 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -48,22 +48,7 @@ internal constructor( } /** - * Represents internal [Polynomial] errors. - */ -internal class NumberedPolynomialError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [PolynomialError] with the given [message]. - */ -internal fun numberedPolynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) - -/** - * Returns the same degrees description of the monomial, but without extra zero degrees on the end. + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. */ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 745df10e8..8e3b3b1c5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -16,21 +16,6 @@ public class NumberedRationalFunction internal constructor( override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -/** - * Represents internal [NumberedRationalFunction] errors. - */ -internal class NumberedRationalFunctionError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [NumberedRationalFunctionError] with the given [message]. - */ -internal fun numberedRationalFunctionError(message: Any): Nothing = throw NumberedRationalFunctionError(message.toString()) - // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) 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 3f3838f53..c6f649fe8 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 @@ -43,27 +43,6 @@ public data class Polynomial( override fun toString(): String = "Polynomial$coefficients" } -// region Internal utilities - -/** - * Represents internal [Polynomial] errors. - */ -internal class PolynomialError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [PolynomialError] with the given [message]. - */ -internal fun polynomialError(message: Any): Nothing = throw PolynomialError(message.toString()) - -// endregion - -// region Constructors and converters - /** * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if * [reverse] parameter is true. @@ -82,8 +61,6 @@ public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Pol public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) -// endregion - /** * Space of univariate polynomials constructed over ring. * @@ -94,8 +71,6 @@ public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) public open class PolynomialSpace>( public override val ring: A, ) : AbstractPolynomialSpaceOverRing, A> { - - // region Polynomial-integer relation /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -152,9 +127,7 @@ public open class PolynomialSpace>( .subList(0, degree + 1) .map { it * other } ) - // endregion - // region Integer-polynomial relation /** * Returns sum of the integer represented as polynomial and the polynomial. * @@ -213,9 +186,7 @@ public open class PolynomialSpace>( .subList(0, other.degree + 1) .map { it * this } ) - // endregion - // region Constant-polynomial relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -270,9 +241,7 @@ public open class PolynomialSpace>( .subList(0, other.degree + 1) .map { it * this } ) - // endregion - // region Polynomial-constant relation /** * Returns sum of the constant represented as polynomial and the polynomial. */ @@ -325,9 +294,7 @@ public open class PolynomialSpace>( .subList(0, degree + 1) .map { it * other } ) - // endregion - // region Polynomial-polynomial relation /** * Returns negation of the polynomial. */ @@ -425,9 +392,7 @@ public open class PolynomialSpace>( else false } } - // endregion - // region Polynomial properties /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -466,8 +431,6 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) - - // endregion } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 5ff3edd2e..f4ae64e81 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -18,21 +18,6 @@ public data class RationalFunction internal constructor ( override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" } -/** - * Represents internal [RationalFunction] errors. - */ -internal class RationalFunctionError : Error { - constructor(): super() - constructor(message: String): super(message) - constructor(message: String?, cause: Throwable?): super(message, cause) - constructor(cause: Throwable?): super(cause) -} - -/** - * Throws an [RationalFunction] with the given [message]. - */ -internal fun rationalFunctionError(message: Any): Nothing = throw RationalFunctionError(message.toString()) - // Waiting for context receivers :( TODO: Replace with context receivers when they will be available //context(RationalFunctionSpace) From 2082175af5e9e811d3a6dfa3079a7dcb2d25a2fe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 16 Mar 2022 23:31:07 +0300 Subject: [PATCH 029/174] Fixed typos. --- .../kmath/functions/LabeledPolynomial.kt | 2 +- .../space/kscience/kmath/functions/Polynomial.kt | 2 +- .../kscience/kmath/functions/RationalFunction.kt | 5 +---- .../kmath/functions/labeledPolynomialUtil.kt | 4 ++-- .../kmath/functions/numberedPolynomialUtil.kt | 16 ++++++++-------- .../kscience/kmath/functions/polynomialUtil.kt | 8 ++++---- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index d263b7102..369c7078a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -49,7 +49,7 @@ internal constructor( } /** - * Returns the same degrees description of the monomial, but without zero degrees. + * Returns the same degrees' description of the monomial, but without zero degrees. */ internal fun Map.cleanUp() = filterValues { it > 0U } 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 c6f649fe8..220bde8ff 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 @@ -425,7 +425,7 @@ public open class PolynomialSpace>( public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } /** - * Evaluates the polynomial for the given value [arg]. + * Evaluates the polynomial for the given value [argument]. */ @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index f4ae64e81..226eddce9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -5,10 +5,7 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* -import kotlin.jvm.JvmName -import kotlin.math.max -import kotlin.math.min +import space.kscience.kmath.operations.Ring public data class RationalFunction internal constructor ( 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 19417d767..27fdd7d7b 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 @@ -65,13 +65,13 @@ import kotlin.contracts.contract // /** - * Crates a [LabeledPolynomialSpace] over received ring. + * Creates a [LabeledPolynomialSpace] over a received ring. */ public fun > A.labeledPolynomial(): LabeledPolynomialSpace = LabeledPolynomialSpace(this) /** - * Crates a [LabeledPolynomialSpace]'s scope over received ring. + * Creates a [LabeledPolynomialSpace]'s scope over a received ring. */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { 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 b2778343d..d544ca93c 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 @@ -42,13 +42,13 @@ import kotlin.math.max // } /** - * Crates a [NumberedPolynomialSpace] over received ring. + * Creates a [NumberedPolynomialSpace] over a received ring. */ public fun > A.numberedPolynomial(): NumberedPolynomialSpace = NumberedPolynomialSpace(this) /** - * Crates a [NumberedPolynomialSpace]'s scope over received ring. + * Creates a [NumberedPolynomialSpace]'s scope over a received ring. */ @OptIn(ExperimentalContracts::class) public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { @@ -279,9 +279,9 @@ public fun NumberedPolynomial.substitute(args: Map): Number val acc = LinkedHashMap, Double>(coefficients.size) for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitutor.pow(deg.toInt()) + if (deg == 0u) product else product * substitution.pow(deg.toInt()) } if (newDegs !in acc) acc[newDegs] = newC else acc[newDegs] = acc[newDegs]!! + newC @@ -298,9 +298,9 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map val acc = LinkedHashMap, C>(coefficients.size) for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitutor) -> + val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitutor, deg) + if (deg == 0u) product else product * power(substitution, deg) } if (newDegs !in acc) acc[newDegs] = newC else acc[newDegs] = acc[newDegs]!! + newC @@ -315,9 +315,9 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map, NumberedPolynomial>(coefficients.size) for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitutor) -> + val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitutor, deg) + if (deg == 0u) product else product * power(substitution, deg) } if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() else acc[newDegs] = acc[newDegs]!! + c 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 e6d6b1ae6..a0c11b0a8 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 @@ -22,13 +22,13 @@ import kotlin.math.pow // if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero /** - * Crates a [PolynomialSpace] over received ring. + * Creates a [PolynomialSpace] over a received ring. */ public fun > A.polynomial(): PolynomialSpace = PolynomialSpace(this) /** - * Crates a [PolynomialSpace]'s scope over received ring. + * Creates a [PolynomialSpace]'s scope over a received ring. */ public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } @@ -36,13 +36,13 @@ public inline fun , R> A.polynomial(block: PolynomialSpace. } /** - * Crates a [ScalablePolynomialSpace] over received scalable ring. + * Creates a [ScalablePolynomialSpace] over a received scalable ring. */ public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = ScalablePolynomialSpace(this) /** - * Crates a [ScalablePolynomialSpace]'s scope over received scalable ring. + * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. */ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } From e5186d469a68cf6284e7e1151cad184b33e25821 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:12:40 +0300 Subject: [PATCH 030/174] Fixed issue with confusing `countOfVariables` in `Numbered...` --- .../kmath/functions/NumberedPolynomial.kt | 26 ++++++++++---- .../functions/NumberedRationalFunction.kt | 34 ++++++++++++++++--- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 307b78f29..37c0c96f0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -432,12 +432,12 @@ public open class NumberedPolynomialSpace>( coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } } - // TODO: Replace `countOfVariables` with `lastVariable` and create new `countOfVariables` /** - * Count of all variables that appear in the polynomial in positive exponents. + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. */ - public val NumberedPolynomial.countOfVariables: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0 else degs.size } ?: 0 + public val NumberedPolynomial.lastVariable: Int + get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.lastIndex } ?: -1 /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -449,18 +449,30 @@ public open class NumberedPolynomialSpace>( * exponents in which the variables are appeared in the polynomial. * * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And size of the list is [countOfVariables]. + * And last index of the list is [lastVariable]. */ public val NumberedPolynomial.degrees: List get() = - buildList(countOfVariables) { - repeat(countOfVariables) { add(0U) } + MutableList(lastVariable + 1) { 0u }.apply { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) degs.forEachIndexed { index, deg -> this[index] = max(this[index], deg) } } } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } /** * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 8e3b3b1c5..6542bc89b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -277,12 +277,12 @@ public class NumberedRationalFunctionSpace> ( if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false - val countOfVariables = max(this.countOfVariables, other.countOfVariables) + val countOfVariables = max(this.lastVariable, other.lastVariable) val thisNumeratorDegrees = this.numerator.degrees val thisDenominatorDegrees = this.denominator.degrees val otherNumeratorDegrees = other.numerator.degrees val otherDenominatorDegrees = other.denominator.degrees - for (variable in 0 until countOfVariables) + for (variable in 0 .. countOfVariables) if ( thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } @@ -292,9 +292,10 @@ public class NumberedRationalFunctionSpace> ( } /** - * Count of all variables that appear in the polynomial in positive exponents. + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } /** * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most * exponents in which the variables are appeared in the polynomial. @@ -303,12 +304,35 @@ public class NumberedRationalFunctionSpace> ( * And size of the list is [countOfVariables]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } /** * Count of all variables that appear in the polynomial in positive exponents. */ + public val NumberedRationalFunction.lastVariable: Int + get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } + /** + * Count of variables occurring in the rational function with positive power. If there is no such variable, + * the result is `0`. + */ public val NumberedRationalFunction.countOfVariables: Int - get() = polynomialRing { max(numerator.countOfVariables, denominator.countOfVariables) } + get() = + MutableList(lastVariable + 1) { false }.apply { + numerator.coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + denominator.coefficients.entries.forEach { (degs, c) -> + if (c.isNotZero()) degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } // TODO: Разобрать From a8a95c9df7727f0a2b4bada88c122a912e8b1796 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:15:48 +0300 Subject: [PATCH 031/174] Fixed typo --- .../space/kscience/kmath/functions/NumberedRationalFunction.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 6542bc89b..78ba233f5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -301,7 +301,7 @@ public class NumberedRationalFunctionSpace> ( * exponents in which the variables are appeared in the polynomial. * * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And size of the list is [countOfVariables]. + * And last index of the list is [lastVariable]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } /** From ffd3ae76844499ca9a6ac46ce23eaa7fc87f06e3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:02:41 +0300 Subject: [PATCH 032/174] Optimized allocation during coefficients generation in `Polynomial` --- .../kscience/kmath/functions/Polynomial.kt | 114 ++++++++++++------ 1 file changed, 79 insertions(+), 35 deletions(-) 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 220bde8ff..862ee6a60 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 @@ -6,6 +6,10 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min @@ -124,8 +128,9 @@ public open class PolynomialSpace>( if (other == 0) zero else Polynomial( coefficients - .subList(0, degree + 1) - .map { it * other } + .applyAndRemoveZeros { + map { it * other } + } ) /** @@ -183,8 +188,9 @@ public open class PolynomialSpace>( if (this == 0) zero else Polynomial( other.coefficients - .subList(0, other.degree + 1) - .map { it * this } + .applyAndRemoveZeros { + map { it * this@times } + } ) /** @@ -238,8 +244,9 @@ public open class PolynomialSpace>( if (this.isZero()) other else Polynomial( other.coefficients - .subList(0, other.degree + 1) - .map { it * this } + .applyAndRemoveZeros { + map { it * this@times } + } ) /** @@ -291,8 +298,9 @@ public open class PolynomialSpace>( if (other.isZero()) this else Polynomial( coefficients - .subList(0, degree + 1) - .map { it * other } + .applyAndRemoveZeros { + map { it * other } + } ) /** @@ -303,33 +311,35 @@ public open class PolynomialSpace>( /** * Returns sum of the polynomials. */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial = - Polynomial( - (0..max(degree, other.degree)) - .map { - when { - it > degree -> other.coefficients[it] - it > other.degree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } + public override operator fun Polynomial.plus(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] } - .ifEmpty { listOf(constantZero) } + } ) + } /** * Returns difference of the polynomials. */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial = - Polynomial( - (0..max(degree, other.degree)) - .map { - when { - it > degree -> -other.coefficients[it] - it > other.degree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } + public override operator fun Polynomial.minus(other: Polynomial): Polynomial { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] } - .ifEmpty { listOf(constantZero) } + } ) + } /** * Returns product of the polynomials. */ @@ -341,13 +351,11 @@ public open class PolynomialSpace>( otherDegree == -1 -> zero else -> Polynomial( - (0..(thisDegree + otherDegree)) - .map { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - .run { subList(0, indexOfLast { it.isNotZero() } + 1) } + Coefficients(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } ) } } @@ -431,6 +439,42 @@ public open class PolynomialSpace>( public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + + // TODO: Move to other internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") + internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + return this + } + internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = + toMutableList().applyAndRemoveZeros(block) + internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { + val list = ArrayList(size) + repeat(size) { index -> list.add(init(index)) } + with(list) { while (elementAt(lastIndex).isZero()) removeAt(lastIndex) } + return list + } + internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList { + builderAction() + while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList(capacity) { + builderAction() + while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } } /** From d63c4acf101849c0bbe2242d841bf7faaf6047e3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:27:02 +0300 Subject: [PATCH 033/174] Added space and scope fabrics for RFs --- .../functions/labeledRationalFunctionUtil.kt | 18 ++++++++++++++++++ .../functions/numberedRationalFunctionUtil.kt | 18 ++++++++++++++++++ .../kmath/functions/rationalFunctionUtil.kt | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index 61f443871..d79e8eda3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -5,6 +5,24 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a [LabeledRationalFunctionSpace] over a received ring. + */ +public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = + LabeledRationalFunctionSpace(this) + +/** + * Creates a [RationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledRationalFunctionSpace(this).block() +} //fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt index 035e201f7..cc725f981 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -5,6 +5,24 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a [NumberedRationalFunctionSpace] over a received ring. + */ +public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = + NumberedRationalFunctionSpace(this) + +/** + * Creates a [RationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedRationalFunctionSpace(this).block() +} //fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { // val greatestCommonDivider = polynomialGCD(numerator, denominator) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index 359c781b5..456a1fa2b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -5,6 +5,24 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Ring +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + + +/** + * Creates a [RationalFunctionSpace] over a received ring. + */ +public fun > A.rationalFunction(): RationalFunctionSpace = + RationalFunctionSpace(this) + +/** + * Creates a [RationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.rationalFunction(block: RationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return RationalFunctionSpace(this).block() +} //operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) // From 86553e9f35aa5891b89bdcd187ff348dcc9955fb Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Thu, 17 Mar 2022 16:28:41 +0300 Subject: [PATCH 034/174] Added utilities. Rewrote polynomial-in-polynomial substitution --- .../kmath/functions/polynomialUtil.kt | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) 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 a0c11b0a8..c624380be 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 @@ -49,6 +49,41 @@ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace< return ScalablePolynomialSpace(this).block() } +@Suppress("NOTHING_TO_INLINE") +internal inline fun iadd( + ring: Ring, + augend: MutableList, + addend: List, + degree: Int +) = ring { + for (deg in 0 .. degree) augend[deg] += addend[deg] +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun addTo( + ring: Ring, + augend: List, + addend: List, + degree: Int, + target: MutableList +) = ring { + for (deg in 0 .. degree) target[deg] = augend[deg] + addend[deg] +} + +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = ring { + for (d in 0 .. multiplicandDegree + multiplierDegree) + for (k in max(0, d - multiplierDegree)..min(multiplicandDegree, d)) + target[d] += multiplicand[k] * multiplier[d - k] +} + // TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. @@ -80,19 +115,21 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol 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 } + 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 - } + multiplyAddingTo( + ring=ring, + multiplicand = resultCoefs, + multiplicandDegree = resultDegree, + multiplier = arg.coefficients, + multiplierDegree = argDegree, + target = resultCoefsUpdate + ) resultDegree += argDegree - for (updateDeg in 0 .. resultDegree + argDegree) { + for (updateDeg in 0 .. resultDegree) { resultCoefs[updateDeg] = resultCoefsUpdate[updateDeg] resultCoefsUpdate[updateDeg] = constantZero } From ed2f14b68e7f799fcbe370bf744256a278cfcf74 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 18 Mar 2022 01:47:03 +0300 Subject: [PATCH 035/174] Optimised existing substitution function. Prototyped substitution for RFs. --- .../kmath/functions/polynomialUtil.kt | 63 ++++--- .../kmath/functions/rationalFunctionUtil.kt | 174 ++++++++++++++++++ 2 files changed, 210 insertions(+), 27 deletions(-) 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 c624380be..1a7245b9f 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 @@ -50,24 +50,36 @@ public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace< } @Suppress("NOTHING_TO_INLINE") -internal inline fun iadd( - ring: Ring, - augend: MutableList, - addend: List, - degree: Int -) = ring { - for (deg in 0 .. degree) augend[deg] += addend[deg] +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } @Suppress("NOTHING_TO_INLINE") -internal inline fun addTo( +internal inline fun multiplyAddingToUpdater( ring: Ring, - augend: List, - addend: List, - degree: Int, - target: MutableList -) = ring { - for (deg in 0 .. degree) target[deg] = augend[deg] + addend[deg] + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + 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") @@ -107,32 +119,29 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { return result } -public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring.polynomial { - if (coefficients.isEmpty()) return zero +public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring { + if (coefficients.isEmpty()) return Polynomial(emptyList()) - val thisDegree = degree - if (thisDegree == -1) return zero - val argDegree = arg.degree + val thisDegree = coefficients.indexOfLast { it != zero } + if (thisDegree == -1) return Polynomial(emptyList()) + val argDegree = arg.coefficients.indexOfLast { it != zero } if (argDegree == -1) return coefficients[0].asPolynomial() - val constantZero = constantZero + val constantZero = zero 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] - multiplyAddingTo( - ring=ring, + multiplyAddingToUpdater( + ring = ring, multiplicand = resultCoefs, multiplicandDegree = resultDegree, multiplier = arg.coefficients, multiplierDegree = argDegree, - target = resultCoefsUpdate + updater = resultCoefsUpdate, + zero = constantZero ) resultDegree += argDegree - for (updateDeg in 0 .. resultDegree) { - resultCoefs[updateDeg] = resultCoefsUpdate[updateDeg] - resultCoefsUpdate[updateDeg] = constantZero - } } return Polynomial(resultCoefs) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt index 456a1fa2b..8d2073834 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt @@ -5,9 +5,12 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.math.max /** @@ -24,6 +27,177 @@ public inline fun , R> A.rationalFunction(block: RationalFunction return RationalFunctionSpace(this).block() } +/** + * Evaluates the value of the given double polynomial for given double argument. + */ +public fun RationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * 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 RationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Returns numerator (polynomial) of rational function gotten by substitution rational function [arg] to the polynomial instance. + * More concrete, if [arg] is a fraction `f(x)/g(x)` and the receiving instance is `p(x)`, then + * ``` + * p(f/g) * g^deg(p) + * ``` + * is returned. + * + * Used in [Polynomial.substitute] and [RationalFunction.substitute] for performance optimisation. + */ // TODO: Дописать +internal fun Polynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: RationalFunction): Polynomial = ring { + if (coefficients.isEmpty()) return Polynomial(emptyList()) + + val thisDegree = coefficients.indexOfLast { it != zero } + if (thisDegree == -1) return Polynomial(emptyList()) + val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() + val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } + val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } + val argDegree = max(numeratorDegree, denominatorDegree) + val constantZero = zero + val powersOf2 = buildList(thisDegreeLog2 + 1) { + var result = 1 + for (exp in 0 .. thisDegreeLog2) { + add(result) + result = result shl 1 + } + } + val hashes = powersOf2.runningReduce { acc, i -> acc + i } + val numeratorPowers = buildList>(thisDegreeLog2 + 1) { + add(arg.numerator.coefficients) + repeat(thisDegreeLog2) { + val next = MutableList(powersOf2[it + 1] * numeratorDegree + 1) { constantZero } + add(next) + val last = last() + multiplyAddingTo( + ring = ring, + multiplicand = last, + multiplicandDegree = powersOf2[it] * numeratorDegree + 1, + multiplier = last, + multiplierDegree = powersOf2[it] * numeratorDegree + 1, + target = next, + ) + } + } + val denominatorPowers = buildList>(thisDegreeLog2 + 1) { + add(arg.denominator.coefficients) + repeat(thisDegreeLog2) { + val next = MutableList(powersOf2[it + 1] * denominatorDegree + 1) { constantZero } + add(next) + val last = last() + multiplyAddingTo( + ring = ring, + multiplicand = last, + multiplicandDegree = powersOf2[it] * denominatorDegree + 1, + multiplier = last, + multiplierDegree = powersOf2[it] * denominatorDegree + 1, + target = next, + ) + } + } + val levelResultCoefsPool = buildList>(thisDegreeLog2 + 1) { + repeat(thisDegreeLog2 + 1) { + add(MutableList(hashes[it] * argDegree) { constantZero }) + } + } + val edgedMultiplier = MutableList(0) { TODO() } + val edgedMultiplierUpdater = MutableList(0) { TODO() } + + fun MutableList.reset() { + for (i in indices) set(i, constantZero) + } + + fun processLevel(level: Int, start: Int, end: Int) : List { + val levelResultCoefs = levelResultCoefsPool[level + 1] + + if (level == -1) { + levelResultCoefs[0] = coefficients[start] + } else { + levelResultCoefs.reset() + multiplyAddingTo( + ring = ring, + multiplicand = processLevel(level = level - 1, start = start, end = (start + end) / 2), + multiplicandDegree = hashes[level] * argDegree, + multiplier = denominatorPowers[level], + multiplierDegree = powersOf2[level] * denominatorDegree, + target = levelResultCoefs + ) + multiplyAddingTo( + ring = ring, + multiplicand = processLevel(level = level - 1, start = (start + end) / 2, end = end), + multiplicandDegree = hashes[level] * argDegree, + multiplier = numeratorPowers[level], + multiplierDegree = powersOf2[level] * numeratorDegree, + target = levelResultCoefs + ) + } + + return levelResultCoefs + } + + fun processLevelEdged(level: Int, start: Int, end: Int) : List { + val levelResultCoefs = levelResultCoefsPool[level + 1] + + if (level == -1) { + levelResultCoefs[0] = coefficients[start] + } else { + val levelsPowerOf2 = powersOf2[level] + if (end - start >= levelsPowerOf2) { + multiplyAddingTo( + ring = ring, + multiplicand = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), + multiplicandDegree = hashes[level] * argDegree, // TODO: Ввести переменную + multiplier = numeratorPowers[level], + multiplierDegree = powersOf2[level] * numeratorDegree, + target = levelResultCoefs + ) + multiplyAddingTo( + ring = ring, + multiplicand = processLevel(level = level - 1, start = start, end = start + levelsPowerOf2), + multiplicandDegree = hashes[level] * argDegree, + multiplier = edgedMultiplier, + multiplierDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную + target = levelResultCoefs + ) + if (level != thisDegreeLog2) { + multiplyAddingToUpdater( + ring = ring, + multiplicand = edgedMultiplier, + multiplicandDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную + multiplier = denominatorPowers[level], + multiplierDegree = powersOf2[level] * denominatorDegree, + updater = edgedMultiplierUpdater, + zero = constantZero + ) + } + } else { + copyTo( + origin = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), + originDegree = hashes[level] * argDegree, // TODO: Ввести переменную + target = levelResultCoefs + ) + } + } + + return levelResultCoefs + } + + return Polynomial( + processLevelEdged( + level = thisDegreeLog2, + start = 0, + end = thisDegree + 1 + ) + ) +} + //operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) // //fun > RationalFunction.reduced(): RationalFunction = From cdc85291bc5d5c9313e25c5d11649415155087d0 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 18 Mar 2022 20:04:21 +0300 Subject: [PATCH 036/174] Fixed bug in implementations of polynomial operations --- .../kmath/functions/LabeledPolynomial.kt | 26 +++++++++---------- .../kmath/functions/NumberedPolynomial.kt | 26 +++++++++---------- .../kscience/kmath/functions/Polynomial.kt | 10 ++++--- .../kmath/functions/polynomialUtil.kt | 1 - 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 369c7078a..76f5fc29c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -211,7 +211,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -265,7 +265,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -361,7 +361,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -413,7 +413,7 @@ public class LabeledPolynomialSpace>( else LabeledPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -525,22 +525,20 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } ) /** * Returns difference of the polynomials. */ override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } ) /** * Returns product of the polynomials. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 37c0c96f0..88349f003 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -163,7 +163,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -217,7 +217,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -269,7 +269,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( other.coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> this@times * c } + for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -319,7 +319,7 @@ public open class NumberedPolynomialSpace>( else NumberedPolynomial( coefficients .applyAndRemoveZeros { - mapValues { (_, c) -> c * other } + for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -335,22 +335,20 @@ public open class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } ) /** * Returns difference of the polynomials. */ override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - coefficients - .applyAndRemoveZeros { - other.coefficients - .mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } + buildCoefficients(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } ) /** * Returns product of the polynomials. 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 862ee6a60..a60ca563a 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 @@ -129,7 +129,7 @@ public open class PolynomialSpace>( else Polynomial( coefficients .applyAndRemoveZeros { - map { it * other } + for (deg in indices) this[deg] = this[deg] * other } ) @@ -189,7 +189,7 @@ public open class PolynomialSpace>( else Polynomial( other.coefficients .applyAndRemoveZeros { - map { it * this@times } + for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -245,7 +245,7 @@ public open class PolynomialSpace>( else Polynomial( other.coefficients .applyAndRemoveZeros { - map { it * this@times } + for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -299,7 +299,7 @@ public open class PolynomialSpace>( else Polynomial( coefficients .applyAndRemoveZeros { - map { it * other } + for (deg in indices) this[deg] = this[deg] * other } ) @@ -452,12 +452,14 @@ public open class PolynomialSpace>( } internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = toMutableList().applyAndRemoveZeros(block) + @Suppress("FunctionName") internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { val list = ArrayList(size) repeat(size) { index -> list.add(init(index)) } with(list) { while (elementAt(lastIndex).isZero()) removeAt(lastIndex) } return list } + @Suppress("FunctionName") internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) @OptIn(ExperimentalTypeInference::class) internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { 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 1a7245b9f..84c8d2e88 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 @@ -96,7 +96,6 @@ internal inline fun multiplyAddingTo( target[d] += multiplicand[k] * multiplier[d - k] } -// TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. */ From 85cd3b4de64b35718d603033dba4aec97879578d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 18 Mar 2022 20:39:01 +0300 Subject: [PATCH 037/174] Added some test. Fixed bug in algebraicStub.kt --- .../kscience/kmath/functions/algebraicStub.kt | 2 +- .../kmath/functions/AlgebraicStubTest.kt | 589 ++++++++++++++++++ .../kmath/functions/PolynomialTest.kt | 5 +- 3 files changed, 593 insertions(+), 3 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index ee81f3d79..ca93e4259 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -139,7 +139,7 @@ internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt internal tailrec fun RingOps.multiplyExponentiationBySquaring(base: C, arg: C, exponent: UInt): C = when { exponent == 0u -> base - exponent == 1u -> base + arg + 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") diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt new file mode 100644 index 000000000..fe4a82f11 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -0,0 +1,589 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Field +import kotlin.jvm.JvmInline +import kotlin.test.Test +import kotlin.test.assertEquals + +@JvmInline +value class Expr(val expr: String) + +object ExprRing : Field { + override fun Expr.unaryMinus(): Expr = Expr("-${expr}") + override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})") + override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})") + override val zero: Expr = Expr("0") + override val one: Expr = Expr("1") + override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})") + override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)") +} + +class AlgebraicStubTest { + @Test + fun test_addMultipliedBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + addMultipliedBySquaring(Expr("57"), Expr("179"), 0u).expr, + "tried addMultipliedBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 + 179)", + addMultipliedBySquaring(Expr("57"), Expr("179"), 1u).expr, + "tried addMultipliedBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 2u).expr, + "tried addMultipliedBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 3u).expr, + "tried addMultipliedBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 4u).expr, + "tried addMultipliedBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 5u).expr, + "tried addMultipliedBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 6u).expr, + "tried addMultipliedBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 7u).expr, + "tried addMultipliedBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 8u).expr, + "tried addMultipliedBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + multiplyBySquaring(Expr("57"), 0u).expr, + "tried multiplyBySquaring(57, 0u)" + ) + assertEquals( + "57", + multiplyBySquaring(Expr("57"), 1u).expr, + "tried multiplyBySquaring(57, 1u)" + ) + assertEquals( + "(57 + 57)", + multiplyBySquaring(Expr("57"), 2u).expr, + "tried multiplyBySquaring(57, 2u)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyBySquaring(Expr("57"), 3u).expr, + "tried multiplyBySquaring(57, 3u)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyBySquaring(Expr("57"), 4u).expr, + "tried multiplyBySquaring(57, 4u)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 5u).expr, + "tried multiplyBySquaring(57, 5u)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 6u).expr, + "tried multiplyBySquaring(57, 6u)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 7u).expr, + "tried multiplyBySquaring(57, 7u)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 8u).expr, + "tried multiplyBySquaring(57, 8u)" + ) + } + } + @Test + fun test_addMultipliedBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + addMultipliedBySquaring(Expr("57"), Expr("179"), 0).expr, + "tried addMultipliedBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 + 179)", + addMultipliedBySquaring(Expr("57"), Expr("179"), 1).expr, + "tried addMultipliedBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 + -179)", + addMultipliedBySquaring(Expr("57"), Expr("179"), -1).expr, + "tried addMultipliedBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 2).expr, + "tried addMultipliedBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 + (-179 + -179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -2).expr, + "tried addMultipliedBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 3).expr, + "tried addMultipliedBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 + -179) + (-179 + -179))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -3).expr, + "tried addMultipliedBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 4).expr, + "tried addMultipliedBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -4).expr, + "tried addMultipliedBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 5).expr, + "tried addMultipliedBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 + -179) + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -5).expr, + "tried addMultipliedBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 6).expr, + "tried addMultipliedBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -6).expr, + "tried addMultipliedBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 7).expr, + "tried addMultipliedBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -7).expr, + "tried addMultipliedBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedBySquaring(Expr("57"), Expr("179"), 8).expr, + "tried addMultipliedBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", + addMultipliedBySquaring(Expr("57"), Expr("179"), -8).expr, + "tried addMultipliedBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + multiplyBySquaring(Expr("57"), 0).expr, + "tried multiplyBySquaring(57, 0)" + ) + assertEquals( + "57", + multiplyBySquaring(Expr("57"), 1).expr, + "tried multiplyBySquaring(57, 1)" + ) + assertEquals( + "-57", + multiplyBySquaring(Expr("57"), -1).expr, + "tried multiplyBySquaring(57, -1)" + ) + assertEquals( + "(57 + 57)", + multiplyBySquaring(Expr("57"), 2).expr, + "tried multiplyBySquaring(57, 2)" + ) + assertEquals( + "(-57 + -57)", + multiplyBySquaring(Expr("57"), -2).expr, + "tried multiplyBySquaring(57, -2)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyBySquaring(Expr("57"), 3).expr, + "tried multiplyBySquaring(57, 3)" + ) + assertEquals( + "(-57 + (-57 + -57))", + multiplyBySquaring(Expr("57"), -3).expr, + "tried multiplyBySquaring(57, -3)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyBySquaring(Expr("57"), 4).expr, + "tried multiplyBySquaring(57, 4)" + ) + assertEquals( + "((-57 + -57) + (-57 + -57))", + multiplyBySquaring(Expr("57"), -4).expr, + "tried multiplyBySquaring(57, -4)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 5).expr, + "tried multiplyBySquaring(57, 5)" + ) + assertEquals( + "(-57 + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -5).expr, + "tried multiplyBySquaring(57, -5)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 6).expr, + "tried multiplyBySquaring(57, 6)" + ) + assertEquals( + "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -6).expr, + "tried multiplyBySquaring(57, -6)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 7).expr, + "tried multiplyBySquaring(57, 7)" + ) + assertEquals( + "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -7).expr, + "tried multiplyBySquaring(57, -7)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyBySquaring(Expr("57"), 8).expr, + "tried multiplyBySquaring(57, 8)" + ) + assertEquals( + "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyBySquaring(Expr("57"), -8).expr, + "tried multiplyBySquaring(57, -8)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + exponentiationBySquaring(Expr("57"), 0u).expr, + "tried exponentiationBySquaring(57, 0u)" + ) + assertEquals( + "57", + exponentiationBySquaring(Expr("57"), 1u).expr, + "tried exponentiationBySquaring(57, 1u)" + ) + assertEquals( + "(57 * 57)", + exponentiationBySquaring(Expr("57"), 2u).expr, + "tried exponentiationBySquaring(57, 2u)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiationBySquaring(Expr("57"), 3u).expr, + "tried exponentiationBySquaring(57, 3u)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiationBySquaring(Expr("57"), 4u).expr, + "tried exponentiationBySquaring(57, 4u)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 5u).expr, + "tried exponentiationBySquaring(57, 5u)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 6u).expr, + "tried exponentiationBySquaring(57, 6u)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 7u).expr, + "tried exponentiationBySquaring(57, 7u)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 8u).expr, + "tried exponentiationBySquaring(57, 8u)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 * (1 / 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -1).expr, + "tried multiplyExponentiationBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 * ((1 / 179) * (1 / 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -2).expr, + "tried multiplyExponentiationBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -3).expr, + "tried multiplyExponentiationBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -4).expr, + "tried multiplyExponentiationBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -5).expr, + "tried multiplyExponentiationBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -6).expr, + "tried multiplyExponentiationBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -7).expr, + "tried multiplyExponentiationBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", + multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -8).expr, + "tried multiplyExponentiationBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + exponentiationBySquaring(Expr("57"), 0).expr, + "tried exponentiationBySquaring(57, 0)" + ) + assertEquals( + "57", + exponentiationBySquaring(Expr("57"), 1).expr, + "tried exponentiationBySquaring(57, 1)" + ) + assertEquals( + "(1 / 57)", + exponentiationBySquaring(Expr("57"), -1).expr, + "tried exponentiationBySquaring(57, -1)" + ) + assertEquals( + "(57 * 57)", + exponentiationBySquaring(Expr("57"), 2).expr, + "tried exponentiationBySquaring(57, 2)" + ) + assertEquals( + "((1 / 57) * (1 / 57))", + exponentiationBySquaring(Expr("57"), -2).expr, + "tried exponentiationBySquaring(57, -2)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiationBySquaring(Expr("57"), 3).expr, + "tried exponentiationBySquaring(57, 3)" + ) + assertEquals( + "((1 / 57) * ((1 / 57) * (1 / 57)))", + exponentiationBySquaring(Expr("57"), -3).expr, + "tried exponentiationBySquaring(57, -3)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiationBySquaring(Expr("57"), 4).expr, + "tried exponentiationBySquaring(57, 4)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", + exponentiationBySquaring(Expr("57"), -4).expr, + "tried exponentiationBySquaring(57, -4)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 5).expr, + "tried exponentiationBySquaring(57, 5)" + ) + assertEquals( + "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -5).expr, + "tried exponentiationBySquaring(57, -5)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 6).expr, + "tried exponentiationBySquaring(57, 6)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -6).expr, + "tried exponentiationBySquaring(57, -6)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 7).expr, + "tried exponentiationBySquaring(57, 7)" + ) + assertEquals( + "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -7).expr, + "tried exponentiationBySquaring(57, -7)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiationBySquaring(Expr("57"), 8).expr, + "tried exponentiationBySquaring(57, 8)" + ) + assertEquals( + "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiationBySquaring(Expr("57"), -8).expr, + "tried exponentiationBySquaring(57, -8)" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index e0f0e32a4..a11242b2a 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -12,11 +12,12 @@ import kotlin.test.assertEquals class PolynomialTest { @Test fun simple_polynomial_test() { + val polynomial : Polynomial Double.algebra.scalablePolynomial { val x = Polynomial(listOf(0.0, 1.0)) - val polynomial = x * x - 2 * x + 1 - assertEquals(0.0, polynomial.substitute(1.0), 0.001) + polynomial = x * x - 2 * x + 1 } + assertEquals(0.0, polynomial.substitute(1.0), 0.001) } @Test fun testIntegration() { From a965f5683f055daf20058f81e62fc8cc16e48141 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 19 Mar 2022 16:54:30 +0300 Subject: [PATCH 038/174] Added some tests and some utilities for tests. Fixed bug in utility of PolynomialSpace. --- .../kscience/kmath/functions/Polynomial.kt | 8 +- .../kmath/functions/PolynomialTest.kt | 67 +++ .../kscience/kmath/test/misc/Rational.kt | 387 ++++++++++++++++++ .../test/misc/RationalWithMemorization.kt | 113 +++++ .../kscience/kmath/test/misc/memorization.kt | 51 +++ .../space/kscience/kmath/test/misc/misc.kt | 25 ++ 6 files changed, 647 insertions(+), 4 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt 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 a60ca563a..3f0d073b3 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 @@ -447,7 +447,7 @@ public open class PolynomialSpace>( callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() - while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) return this } internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = @@ -456,7 +456,7 @@ public open class PolynomialSpace>( internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { val list = ArrayList(size) repeat(size) { index -> list.add(init(index)) } - with(list) { while (elementAt(lastIndex).isZero()) removeAt(lastIndex) } + with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } return list } @Suppress("FunctionName") @@ -466,7 +466,7 @@ public open class PolynomialSpace>( contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildList { builderAction() - while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } } @OptIn(ExperimentalTypeInference::class) @@ -474,7 +474,7 @@ public open class PolynomialSpace>( contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } return buildList(capacity) { builderAction() - while (elementAt(lastIndex).isZero()) removeAt(lastIndex) + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index a11242b2a..9e3dea615 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -5,11 +5,78 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.BigInt import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.toBigInt +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.gcd import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.polynomial { + // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 + assertEquals( + Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + Polynomial(Rational(-2, 9), Rational(-8, 3)) + + Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 + assertEquals( + Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), + Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 + assertEquals( + Polynomial(), + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } +// @Test +// fun test_Polynomial_Polynomial_minus() { +// RationalField.polynomial { +// assertEquals( +// Polynomial(Rational(1, 2), Rational(3, 5), Rational(-2)) + +// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), +// Polynomial(Rational(7, 2), Rational(59, 40), Rational(-17, 9)), +// "test 1" +// ) +// assertEquals( +// Polynomial(Rational(1, 2), Rational(3, 5)) + +// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), +// Polynomial(Rational(7, 2), Rational(59, 40), Rational(1, 9)), +// "test 2" +// ) +// assertEquals( +// Polynomial(Rational(1, 2), Rational(3, 5), Rational(0), Rational(0)) + +// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), +// Polynomial(Rational(7, 2), Rational(59, 40), Rational(1, 9)), +// "test 3" +// ) +// assertEquals( +// Polynomial(Rational(1, 2), Rational(-3, 5), Rational(7, 3)) + +// Polynomial(Rational(3), Rational(3, 5), Rational(-7, 3)), +// Polynomial(Rational(7, 2)), +// "test 4" +// ) +// } +// } @Test fun simple_polynomial_test() { val polynomial : Polynomial diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt new file mode 100644 index 000000000..fad13f88a --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -0,0 +1,387 @@ +/* + * 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.BigInt +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.toBigInt +import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 +import space.kscience.kmath.operations.BigInt.Companion.ONE as I1 + +/** + * The class represents rational numbers. + * + * Instances contain [numerator] and [denominator] represented as [Long]. + * + * Also [numerator] and [denominator] are coprime and [denominator] is positive. + * + * @author [Gleb Minaev](https://github.com/lounres) + */ +public class Rational: Comparable { + public companion object { + /** + * Constant containing the zero (the additive identity) of the [Rational] field. + */ + public val ZERO: Rational = Rational(I0) + /** + * Constant containing the one (the multiplicative identity) of the [Rational] field. + */ + public val ONE: Rational = Rational(I1) + } + + /** + * Numerator of the fraction. It's stored as non-negative coprime with [denominator] integer. + */ + public val numerator: BigInt + /** + * Denominator of the fraction. It's stored as non-zero coprime with [numerator] integer. + */ + public val denominator: BigInt + + /** + * If [toCheckInput] is `true` before assigning values to [Rational.numerator] and [Rational.denominator] makes them coprime and makes + * denominator positive. Otherwise, just assigns the values. + * + * @throws ArithmeticException If denominator is zero. + */ + internal constructor(numerator: BigInt, denominator: BigInt, toCheckInput: Boolean = true) { + if (toCheckInput) { + if (denominator == I0) throw ArithmeticException("/ by zero") + + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < I0) -it else it } + + this.numerator = numerator / greatestCommonDivider + this.denominator = denominator / greatestCommonDivider + } else { + this.numerator = numerator + this.denominator = denominator + } + } + + /** + * Before assigning values to [Rational.numerator] and [Rational.denominator] makes them coprime and makes + * denominator positive. + * + * @throws ArithmeticException If denominator is zero. + */ + public constructor(numerator: BigInt, denominator: BigInt) : this(numerator, denominator, true) + public constructor(numerator: Int, denominator: BigInt) : this(numerator.toBigInt(), denominator, true) + public constructor(numerator: Long, denominator: BigInt) : this(numerator.toBigInt(), denominator, true) + public constructor(numerator: BigInt, denominator: Int) : this(numerator, denominator.toBigInt(), true) + public constructor(numerator: BigInt, denominator: Long) : this(numerator, denominator.toBigInt(), true) + public constructor(numerator: Int, denominator: Int) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: Int, denominator: Long) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: Long, denominator: Int) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: Long, denominator: Long) : this(numerator.toBigInt(), denominator.toBigInt(), true) + public constructor(numerator: BigInt) : this(numerator, I1, false) + public constructor(numerator: Int) : this(numerator.toBigInt(), I1, false) + public constructor(numerator: Long) : this(numerator.toBigInt(), I1, false) + + /** + * Returns the same instant. + */ + public operator fun unaryPlus(): Rational = this + + /** + * Returns negation of the instant of [Rational] field. + */ + public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + + /** + * Returns sum of the instants of [Rational] field. + */ + public operator fun plus(other: Rational): Rational = + Rational( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + + /** + * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun plus(other: BigInt): Rational = + Rational( + numerator + denominator * other, + denominator + ) + + /** + * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toBigInt(), + denominator + ) + + /** + * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other.toBigInt(), + denominator + ) + + /** + * Returns difference of the instants of [Rational] field. + */ + public operator fun minus(other: Rational): Rational = + Rational( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + + /** + * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun minus(other: BigInt): Rational = + Rational( + numerator - denominator * other, + denominator + ) + + /** + * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toBigInt(), + denominator + ) + + /** + * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other.toBigInt(), + denominator + ) + + /** + * Returns product of the instants of [Rational] field. + */ + public operator fun times(other: Rational): Rational = + Rational( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun times(other: BigInt): Rational = + Rational( + numerator * other, + denominator + ) + + /** + * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun times(other: Int): Rational = + Rational( + numerator * other.toBigInt(), + denominator + ) + + /** + * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. + */ + public operator fun times(other: Long): Rational = + Rational( + numerator * other.toBigInt(), + denominator + ) + + /** + * Returns quotient of the instants of [Rational] field. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: Rational): Rational = + Rational( + numerator * other.denominator, + denominator * other.numerator + ) + + /** + * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: BigInt): Rational = + Rational( + numerator, + denominator * other + ) + + /** + * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toBigInt() + ) + + /** + * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun div(other: Long): Rational = + Rational( + numerator, + denominator * other.toBigInt() + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: Rational): Rational = + Rational( + (numerator * other.denominator) % (denominator * other.numerator), + denominator * other.denominator + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: BigInt): Rational = + Rational( + numerator % denominator * other, + denominator * other + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: Int): Rational = + Rational( + numerator % denominator * other.toBigInt(), + denominator * other.toBigInt() + ) + + /** + * Returns reminder from integral division. + * + * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. + */ + public operator fun rem(other: Long): Rational = + Rational( + numerator % denominator * other.toBigInt(), + denominator * other.toBigInt() + ) + + /** + * Checks equality of the instance to [other]. + * + * [BigInt], [Int] and [Long] values are also checked as Rational ones. + */ + override fun equals(other: Any?): Boolean = + when (other) { + is Rational -> numerator == other.numerator && denominator == other.denominator + is BigInt -> numerator == other && denominator == I1 + is Int -> numerator == other && denominator == I1 + is Long -> numerator == other && denominator == I1 + else -> false + } + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * @see Comparable.compareTo + */ + override operator fun compareTo(other: Rational): Int = (numerator * other.denominator).compareTo(other.numerator * denominator) + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * [Integer] values are also checked as Rational ones. + * + * @see Comparable.compareTo + */ + public operator fun compareTo(other: BigInt): Int = (numerator).compareTo(denominator * other) + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * [Int] values are also checked as Rational ones. + * + * @see Comparable.compareTo + */ + public operator fun compareTo(other: Int): Int = (numerator).compareTo(denominator * other.toBigInt()) + + /** + * Compares the instance to [other] as [Comparable.compareTo]. + * + * [Long] values are also checked as Rational ones. + * + * @see Comparable.compareTo + */ + public operator fun compareTo(other: Long): Int = (numerator).compareTo(denominator * other.toBigInt()) + + public override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() + +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: JBInt) = ClosedRationalRange(this, other.toRational()) +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: Rational) = ClosedRationalRange(this, other) +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: Int) = ClosedRationalRange(this, other.toRational()) +// /** Creates a range from this value to the specified [other] value. */ +// operator fun rangeTo(other: Long) = ClosedRationalRange(this, other.toRational()) + + public fun toRational(): Rational = this + + public fun toBigInt(): BigInt = numerator / denominator + +// public fun toInt(): Int = (numerator / denominator).toInt() +// +// public fun toLong(): Long = (numerator / denominator).toLong() +// +// public fun toDouble(): Double = (numerator.toDouble() / denominator.toDouble()) +// +// public fun toFloat(): Float = (numerator.toFloat() / denominator.toFloat()) + + public override fun toString(): String = if (denominator == I1) "$numerator" else "$numerator/$denominator" +} + + +/** + * Algebraic structure for rational numbers. + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +public object RationalField : Field, NumbersAddOps { + 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 +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt new file mode 100644 index 000000000..6aa5ecc09 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt @@ -0,0 +1,113 @@ +/* + * 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.* + +class RationalWithMemorization private constructor( + val value: Rational, + override val memory : OperationsMemory +): WithMemorization { + public companion object { + /** + * Constant containing the zero (the additive identity) of the [Rational] field. + */ + public val ZERO: RationalWithMemorization = RationalWithMemorization(Rational.ZERO, object : Endpoint {}) + /** + * Constant containing the one (the multiplicative identity) of the [Rational] field. + */ + public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {}) + } + public constructor(numerator: BigInt, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Int, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Long, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: BigInt, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: BigInt, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + public constructor(numerator: BigInt) : this(Rational(numerator), object : Endpoint {}) + public constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) + public constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) + + public operator fun unaryPlus(): RationalWithMemorization = this + public operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( + -value, + object : Negation { + override val negated: OperationsMemory = memory + } + ) + public operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value + other.value, + object : Sum { + override val augend: OperationsMemory = memory + override val addend: OperationsMemory = other.memory + } + ) + public operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value - other.value, + object : Difference { + override val minuend: OperationsMemory = memory + override val subtrahend: OperationsMemory = other.memory + } + ) + public operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value * other.value, + object : Product { + override val multiplicand: OperationsMemory = memory + override val multiplier: OperationsMemory = other.memory + } + ) + public operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + value / other.value, + object : Quotient { + override val dividend: OperationsMemory = memory + override val divisor: OperationsMemory = other.memory + } + ) + + public override fun equals(other: Any?): Boolean = + other is RationalWithMemorization && value == other.value + + public override fun hashCode(): Int = value.hashCode() + + public override fun toString(): String = value.toString() +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object RationalWithMemorizationRing : Ring { + override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO + override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE + + override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right + override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right + + override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this + override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg + override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg + override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object RationalWithMemorizationField : Field { + override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO + override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE + + override inline fun number(value: Number): RationalWithMemorization = RationalWithMemorization(value.toLong()) + + override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right + override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right + override inline fun divide(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left / right + override inline fun scale(a: RationalWithMemorization, value: Double): RationalWithMemorization = a * number(value) + + override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this + override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg + override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg + override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg + override inline fun RationalWithMemorization.div(arg: RationalWithMemorization): RationalWithMemorization = this / arg +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt new file mode 100644 index 000000000..a4fb81274 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt @@ -0,0 +1,51 @@ +/* + * 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 + +sealed interface OperationsMemory + +interface Endpoint: OperationsMemory + +interface Negation: OperationsMemory { + val negated: OperationsMemory +} + +interface Sum: OperationsMemory { + val augend: OperationsMemory + val addend: OperationsMemory +} + +interface Difference: OperationsMemory { + val minuend: OperationsMemory + val subtrahend: OperationsMemory +} + +interface Product: OperationsMemory { + val multiplicand: OperationsMemory + val multiplier: OperationsMemory +} + +interface Quotient: OperationsMemory { + val dividend: OperationsMemory + val divisor: OperationsMemory +} + + +fun equalMemories(one: OperationsMemory, other: OperationsMemory) : Boolean = + when(one) { + is Negation -> other is Negation && equalMemories(one.negated, other.negated) + is Sum -> other is Sum && equalMemories(one.augend, other.augend) && equalMemories(one.addend, other.addend) + is Difference -> other is Difference && equalMemories(one.minuend, other.minuend) && equalMemories(one.subtrahend, other.subtrahend) + is Product -> other is Product && equalMemories(one.multiplicand, other.multiplicand) && equalMemories(one.multiplier, other.multiplier) + is Quotient -> other is Quotient && equalMemories(one.dividend, other.dividend) && equalMemories(one.divisor, other.divisor) + is Endpoint -> one === other + } + +interface WithMemorization { + val memory: OperationsMemory +} + +fun equalMemories(one: WithMemorization, other: WithMemorization) : Boolean = equalMemories(one.memory, other.memory) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..eab29842c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -0,0 +1,25 @@ +/* + * 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.operations.* +import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 + +// TODO: Move to corresponding module "kmath-number-theory" + +/** + * Computes [Greatest Common Divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) of [a] and [b]. + * + * It's computed by [Euclidean algorithm](https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclidean_algorithm). + * Hence, its time complexity is $$O(\log(a+b))$$ (see [Wolfram MathWorld](https://mathworld.wolfram.com/EuclideanAlgorithm.html)). + */ +public tailrec fun gcd(a: BigInt, b: BigInt): BigInt = if (a == I0) abs(b) else gcd(b % a, a) + +/** + * Computes [Greatest Common Divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) of the [values]. + */ +public fun gcd(vararg values: BigInt): BigInt = values.reduce(::gcd) +public fun gcd(values: Iterable): BigInt = values.reduce(::gcd) \ No newline at end of file From 90a7c4d901d6383b2de5326b0fa852f27bc47320 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 19 Mar 2022 18:08:43 +0300 Subject: [PATCH 039/174] Simplified use of Rational (current BigInt are hard to use and actually useless). Added tests, fixed bug. --- .../kmath/functions/NumberedPolynomial.kt | 8 +- .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kmath/functions/PolynomialTest.kt | 225 +++++++++-- .../kscience/kmath/test/misc/Rational.kt | 348 +++--------------- .../test/misc/RationalWithMemorization.kt | 42 +-- .../space/kscience/kmath/test/misc/misc.kt | 17 +- 6 files changed, 268 insertions(+), 374 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 88349f003..c05bc30ec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -246,7 +246,7 @@ public open class NumberedPolynomialSpace>( override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = if (this.isZero()) -other else with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(listOf() to this@minus)) + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) else NumberedPolynomial( toMutableMap() .apply { @@ -279,7 +279,7 @@ public open class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { @@ -298,7 +298,7 @@ public open class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(listOf() to other)) + if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { @@ -416,7 +416,7 @@ public open class NumberedPolynomialSpace>( override val one: NumberedPolynomial = NumberedPolynomial( mapOf( - listOf() to constantOne // 1 * x_1^0 * x_2^0 * ... + emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... ) ) 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 3f0d073b3..722566f5d 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 @@ -276,7 +276,7 @@ public open class PolynomialSpace>( public override operator fun Polynomial.minus(other: C): Polynomial = if (other.isZero()) this else with(coefficients) { - if (isEmpty()) Polynomial(listOf(other)) + if (isEmpty()) Polynomial(listOf(-other)) else Polynomial( toMutableList() .apply { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 9e3dea615..e2970d953 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -5,16 +5,173 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.BigInt import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.toBigInt import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.gcd import kotlin.test.Test import kotlin.test.assertEquals class PolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(-2)) + 2, + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() + 0, + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Polynomial(Rational(-2)) + 1, + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial() + 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(2)) - 2, + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() - 0, + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Polynomial(Rational(2)) - 1, + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Polynomial() - 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() + Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Polynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + Polynomial(), + Polynomial() - Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Polynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Polynomial() - Rational(2), + "test 7" + ) + } + } @Test fun test_Polynomial_Polynomial_plus() { RationalField.polynomial { @@ -48,35 +205,39 @@ class PolynomialTest { ) } } -// @Test -// fun test_Polynomial_Polynomial_minus() { -// RationalField.polynomial { -// assertEquals( -// Polynomial(Rational(1, 2), Rational(3, 5), Rational(-2)) + -// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), -// Polynomial(Rational(7, 2), Rational(59, 40), Rational(-17, 9)), -// "test 1" -// ) -// assertEquals( -// Polynomial(Rational(1, 2), Rational(3, 5)) + -// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), -// Polynomial(Rational(7, 2), Rational(59, 40), Rational(1, 9)), -// "test 2" -// ) -// assertEquals( -// Polynomial(Rational(1, 2), Rational(3, 5), Rational(0), Rational(0)) + -// Polynomial(Rational(3), Rational(7, 8), Rational(1, 9)), -// Polynomial(Rational(7, 2), Rational(59, 40), Rational(1, 9)), -// "test 3" -// ) -// assertEquals( -// Polynomial(Rational(1, 2), Rational(-3, 5), Rational(7, 3)) + -// Polynomial(Rational(3), Rational(3, 5), Rational(-7, 3)), -// Polynomial(Rational(7, 2)), -// "test 4" -// ) -// } -// } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.polynomial { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - + Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), + Polynomial(Rational(-2, 9), Rational(-8, 3)) - + Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)), + Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - + Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 + assertEquals( + Polynomial(), + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), + "test 4" + ) + } + } @Test fun simple_polynomial_test() { val polynomial : Polynomial diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt index fad13f88a..842e354db 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -6,54 +6,23 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.BigInt import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps -import space.kscience.kmath.operations.toBigInt -import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 -import space.kscience.kmath.operations.BigInt.Companion.ONE as I1 -/** - * The class represents rational numbers. - * - * Instances contain [numerator] and [denominator] represented as [Long]. - * - * Also [numerator] and [denominator] are coprime and [denominator] is positive. - * - * @author [Gleb Minaev](https://github.com/lounres) - */ -public class Rational: Comparable { - public companion object { - /** - * Constant containing the zero (the additive identity) of the [Rational] field. - */ - public val ZERO: Rational = Rational(I0) - /** - * Constant containing the one (the multiplicative identity) of the [Rational] field. - */ - public val ONE: Rational = Rational(I1) +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) } - /** - * Numerator of the fraction. It's stored as non-negative coprime with [denominator] integer. - */ - public val numerator: BigInt - /** - * Denominator of the fraction. It's stored as non-zero coprime with [numerator] integer. - */ - public val denominator: BigInt + val numerator: Long + val denominator: Long - /** - * If [toCheckInput] is `true` before assigning values to [Rational.numerator] and [Rational.denominator] makes them coprime and makes - * denominator positive. Otherwise, just assigns the values. - * - * @throws ArithmeticException If denominator is zero. - */ - internal constructor(numerator: BigInt, denominator: BigInt, toCheckInput: Boolean = true) { + internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { - if (denominator == I0) throw ArithmeticException("/ by zero") + if (denominator == 0L) throw ArithmeticException("/ by zero") - val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < I0) -it else it } + val greatestCommonDivider = gcd(numerator, denominator).let { if (denominator < 0L) -it else it } this.numerator = numerator / greatestCommonDivider this.denominator = denominator / greatestCommonDivider @@ -63,303 +32,86 @@ public class Rational: Comparable { } } - /** - * Before assigning values to [Rational.numerator] and [Rational.denominator] makes them coprime and makes - * denominator positive. - * - * @throws ArithmeticException If denominator is zero. - */ - public constructor(numerator: BigInt, denominator: BigInt) : this(numerator, denominator, true) - public constructor(numerator: Int, denominator: BigInt) : this(numerator.toBigInt(), denominator, true) - public constructor(numerator: Long, denominator: BigInt) : this(numerator.toBigInt(), denominator, true) - public constructor(numerator: BigInt, denominator: Int) : this(numerator, denominator.toBigInt(), true) - public constructor(numerator: BigInt, denominator: Long) : this(numerator, denominator.toBigInt(), true) - public constructor(numerator: Int, denominator: Int) : this(numerator.toBigInt(), denominator.toBigInt(), true) - public constructor(numerator: Int, denominator: Long) : this(numerator.toBigInt(), denominator.toBigInt(), true) - public constructor(numerator: Long, denominator: Int) : this(numerator.toBigInt(), denominator.toBigInt(), true) - public constructor(numerator: Long, denominator: Long) : this(numerator.toBigInt(), denominator.toBigInt(), true) - public constructor(numerator: BigInt) : this(numerator, I1, false) - public constructor(numerator: Int) : this(numerator.toBigInt(), I1, false) - public constructor(numerator: Long) : this(numerator.toBigInt(), I1, false) + 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) - /** - * Returns the same instant. - */ - public operator fun unaryPlus(): Rational = this - - /** - * Returns negation of the instant of [Rational] field. - */ - public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - - /** - * Returns sum of the instants of [Rational] field. - */ - public operator fun plus(other: Rational): Rational = + 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 ) - - /** - * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun plus(other: BigInt): Rational = + operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator + ) + operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator ) - - /** - * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun plus(other: Int): Rational = - Rational( - numerator + denominator * other.toBigInt(), - denominator - ) - - /** - * Returns sum of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun plus(other: Long): Rational = - Rational( - numerator + denominator * other.toBigInt(), - denominator - ) - - /** - * Returns difference of the instants of [Rational] field. - */ - public operator fun minus(other: Rational): Rational = + operator fun minus(other: Rational): Rational = Rational( numerator * other.denominator - denominator * other.numerator, denominator * other.denominator ) - - /** - * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun minus(other: BigInt): Rational = + operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator + ) + operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator ) - - /** - * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun minus(other: Int): Rational = - Rational( - numerator - denominator * other.toBigInt(), - denominator - ) - - /** - * Returns difference of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun minus(other: Long): Rational = - Rational( - numerator - denominator * other.toBigInt(), - denominator - ) - - /** - * Returns product of the instants of [Rational] field. - */ - public operator fun times(other: Rational): Rational = + operator fun times(other: Rational): Rational = Rational( numerator * other.numerator, denominator * other.denominator ) - - /** - * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun times(other: BigInt): Rational = + operator fun times(other: Int): Rational = + Rational( + numerator * other.toLong(), + denominator + ) + operator fun times(other: Long): Rational = Rational( numerator * other, denominator ) - - /** - * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun times(other: Int): Rational = - Rational( - numerator * other.toBigInt(), - denominator - ) - - /** - * Returns product of the instants of [Rational] field. [other] is represented as [Rational]. - */ - public operator fun times(other: Long): Rational = - Rational( - numerator * other.toBigInt(), - denominator - ) - - /** - * Returns quotient of the instants of [Rational] field. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun div(other: Rational): Rational = + operator fun div(other: Rational): Rational = Rational( numerator * other.denominator, denominator * other.numerator ) - - /** - * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun div(other: BigInt): Rational = + operator fun div(other: Int): Rational = + Rational( + numerator, + denominator * other.toLong() + ) + operator fun div(other: Long): Rational = Rational( numerator, denominator * other ) - - /** - * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun div(other: Int): Rational = - Rational( - numerator, - denominator * other.toBigInt() - ) - - /** - * Returns quotient of the instants of [Rational] field. [other] is represented as [Rational]. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun div(other: Long): Rational = - Rational( - numerator, - denominator * other.toBigInt() - ) - - /** - * Returns reminder from integral division. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun rem(other: Rational): Rational = - Rational( - (numerator * other.denominator) % (denominator * other.numerator), - denominator * other.denominator - ) - - /** - * Returns reminder from integral division. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun rem(other: BigInt): Rational = - Rational( - numerator % denominator * other, - denominator * other - ) - - /** - * Returns reminder from integral division. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun rem(other: Int): Rational = - Rational( - numerator % denominator * other.toBigInt(), - denominator * other.toBigInt() - ) - - /** - * Returns reminder from integral division. - * - * @throws ArithmeticException if [other] is the zero of the field it can't be a divisor. - */ - public operator fun rem(other: Long): Rational = - Rational( - numerator % denominator * other.toBigInt(), - denominator * other.toBigInt() - ) - - /** - * Checks equality of the instance to [other]. - * - * [BigInt], [Int] and [Long] values are also checked as Rational ones. - */ override fun equals(other: Any?): Boolean = when (other) { is Rational -> numerator == other.numerator && denominator == other.denominator - is BigInt -> numerator == other && denominator == I1 - is Int -> numerator == other && denominator == I1 - is Long -> numerator == other && denominator == I1 + is Int -> numerator == other && denominator == 1L + is Long -> numerator == other && denominator == 1L else -> false } - /** - * Compares the instance to [other] as [Comparable.compareTo]. - * - * @see Comparable.compareTo - */ - override operator fun compareTo(other: Rational): Int = (numerator * other.denominator).compareTo(other.numerator * denominator) + override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - /** - * Compares the instance to [other] as [Comparable.compareTo]. - * - * [Integer] values are also checked as Rational ones. - * - * @see Comparable.compareTo - */ - public operator fun compareTo(other: BigInt): Int = (numerator).compareTo(denominator * other) - - /** - * Compares the instance to [other] as [Comparable.compareTo]. - * - * [Int] values are also checked as Rational ones. - * - * @see Comparable.compareTo - */ - public operator fun compareTo(other: Int): Int = (numerator).compareTo(denominator * other.toBigInt()) - - /** - * Compares the instance to [other] as [Comparable.compareTo]. - * - * [Long] values are also checked as Rational ones. - * - * @see Comparable.compareTo - */ - public operator fun compareTo(other: Long): Int = (numerator).compareTo(denominator * other.toBigInt()) - - public override fun hashCode(): Int = 31 * numerator.hashCode() + denominator.hashCode() - -// /** Creates a range from this value to the specified [other] value. */ -// operator fun rangeTo(other: JBInt) = ClosedRationalRange(this, other.toRational()) -// /** Creates a range from this value to the specified [other] value. */ -// operator fun rangeTo(other: Rational) = ClosedRationalRange(this, other) -// /** Creates a range from this value to the specified [other] value. */ -// operator fun rangeTo(other: Int) = ClosedRationalRange(this, other.toRational()) -// /** Creates a range from this value to the specified [other] value. */ -// operator fun rangeTo(other: Long) = ClosedRationalRange(this, other.toRational()) - - public fun toRational(): Rational = this - - public fun toBigInt(): BigInt = numerator / denominator - -// public fun toInt(): Int = (numerator / denominator).toInt() -// -// public fun toLong(): Long = (numerator / denominator).toLong() -// -// public fun toDouble(): Double = (numerator.toDouble() / denominator.toDouble()) -// -// public fun toFloat(): Float = (numerator.toFloat() / denominator.toFloat()) - - public override fun toString(): String = if (denominator == I1) "$numerator" else "$numerator/$denominator" + override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" } @@ -368,7 +120,7 @@ public class Rational: Comparable { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @OptIn(UnstableKMathAPI::class) -public object RationalField : Field, NumbersAddOps { +object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt index 6aa5ecc09..05d9115fa 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt @@ -12,7 +12,7 @@ class RationalWithMemorization private constructor( val value: Rational, override val memory : OperationsMemory ): WithMemorization { - public companion object { + companion object { /** * Constant containing the zero (the additive identity) of the [Rational] field. */ @@ -22,48 +22,42 @@ class RationalWithMemorization private constructor( */ public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {}) } - public constructor(numerator: BigInt, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: Int, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: Long, denominator: BigInt) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: BigInt, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: BigInt, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - public constructor(numerator: BigInt) : this(Rational(numerator), object : Endpoint {}) - public constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - public constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) + constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) + constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) + constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - public operator fun unaryPlus(): RationalWithMemorization = this - public operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( + operator fun unaryPlus(): RationalWithMemorization = this + operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( -value, object : Negation { override val negated: OperationsMemory = memory } ) - public operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( value + other.value, object : Sum { override val augend: OperationsMemory = memory override val addend: OperationsMemory = other.memory } ) - public operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( value - other.value, object : Difference { override val minuend: OperationsMemory = memory override val subtrahend: OperationsMemory = other.memory } ) - public operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( value * other.value, object : Product { override val multiplicand: OperationsMemory = memory override val multiplier: OperationsMemory = other.memory } ) - public operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( + operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( value / other.value, object : Quotient { override val dividend: OperationsMemory = memory @@ -71,16 +65,16 @@ class RationalWithMemorization private constructor( } ) - public override fun equals(other: Any?): Boolean = + override fun equals(other: Any?): Boolean = other is RationalWithMemorization && value == other.value - public override fun hashCode(): Int = value.hashCode() + override fun hashCode(): Int = value.hashCode() - public override fun toString(): String = value.toString() + override fun toString(): String = value.toString() } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object RationalWithMemorizationRing : Ring { +object RationalWithMemorizationRing : Ring { override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE @@ -94,7 +88,7 @@ public object RationalWithMemorizationRing : Ring { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object RationalWithMemorizationField : Field { +object RationalWithMemorizationField : Field { override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt index eab29842c..2eb421024 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -5,21 +5,8 @@ package space.kscience.kmath.test.misc -import space.kscience.kmath.operations.* -import space.kscience.kmath.operations.BigInt.Companion.ZERO as I0 +import kotlin.math.abs // TODO: Move to corresponding module "kmath-number-theory" -/** - * Computes [Greatest Common Divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) of [a] and [b]. - * - * It's computed by [Euclidean algorithm](https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclidean_algorithm). - * Hence, its time complexity is $$O(\log(a+b))$$ (see [Wolfram MathWorld](https://mathworld.wolfram.com/EuclideanAlgorithm.html)). - */ -public tailrec fun gcd(a: BigInt, b: BigInt): BigInt = if (a == I0) abs(b) else gcd(b % a, a) - -/** - * Computes [Greatest Common Divisor](https://en.wikipedia.org/wiki/Greatest_common_divisor) of the [values]. - */ -public fun gcd(vararg values: BigInt): BigInt = values.reduce(::gcd) -public fun gcd(values: Iterable): BigInt = values.reduce(::gcd) \ No newline at end of file +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) \ No newline at end of file From 5d4514a742d0c36dabf2b0e03243f61381453313 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 19 Mar 2022 19:35:41 +0300 Subject: [PATCH 040/174] More test tools! More tests!! More fixes of stupid bugs!!! :sob: --- .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kmath/functions/PolynomialTest.kt | 224 +++++++++++++++++- .../kscience/kmath/test/misc/IntModulo.kt | 142 +++++++++++ .../kscience/kmath/test/misc/Rational.kt | 4 - .../space/kscience/kmath/test/misc/misc.kt | 25 +- 5 files changed, 387 insertions(+), 10 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt 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 722566f5d..9c1f9efae 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 @@ -220,7 +220,7 @@ public open class PolynomialSpace>( public override operator fun C.minus(other: Polynomial): Polynomial = if (this.isZero()) other else with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(-this@minus)) + if (isEmpty()) Polynomial(listOf(this@minus)) else Polynomial( toMutableList() .apply { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index e2970d953..0bf34f198 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -6,11 +6,11 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.algebra -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.* import kotlin.test.Test import kotlin.test.assertEquals + class PolynomialTest { @Test fun test_Polynomial_Int_plus() { @@ -93,6 +93,116 @@ class PolynomialTest { } } @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + Polynomial(22, 26, 13, 15, 26) * 27, + "test 1" + ) + assertEquals( + Polynomial(), + Polynomial(7, 0, 49, 21, 14) * 15, + "test 2" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + -3 + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + 2 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + 2 + Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + 0 + Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + 1 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + 1 + Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + 2 + Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + 3 - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + -2 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + -2 - Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + 0 - Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + -1 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + -1 - Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + -2 - Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + 27 * Polynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + Polynomial(), + 15 * Polynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test fun test_Polynomial_Constant_plus() { RationalField.polynomial { assertEquals( @@ -173,6 +283,116 @@ class PolynomialTest { } } @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + Polynomial(22, 26, 13, 15, 26) * number(27), + "test 1" + ) + assertEquals( + Polynomial(), + Polynomial(7, 0, 49, 21, 14) * number(15), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + Rational(2) + Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + Rational(0) + Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Rational(1) + Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Rational(2) + Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(), + Rational(-2) - Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(), + Rational(0) - Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Rational(-1) - Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Rational(-2) - Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).polynomial { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + 27 * Polynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + Polynomial(), + 15 * Polynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test fun test_Polynomial_Polynomial_plus() { RationalField.polynomial { // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..a8a8a09bc --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,142 @@ +/* + * 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.functions.Polynomial +import space.kscience.kmath.functions.PolynomialSpace +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun PolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) + +fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt index 842e354db..72bb5942c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -114,10 +114,6 @@ class Rational { override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" } - -/** - * Algebraic structure for rational numbers. - */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") @OptIn(UnstableKMathAPI::class) object RationalField : Field, NumbersAddOps { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt index 2eb421024..cc647fa2c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -5,8 +5,27 @@ package space.kscience.kmath.test.misc -import kotlin.math.abs - // TODO: Move to corresponding module "kmath-number-theory" -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) \ No newline at end of file +import kotlin.math.abs + + +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file From fbc21101bbcb2cbc9a383fa2c18d635cba72c25e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 20 Mar 2022 06:26:52 +0300 Subject: [PATCH 041/174] Added test. Fixed isOne and isMinusOne for Polynomial. --- .../kscience/kmath/functions/Polynomial.kt | 6 +- .../kmath/functions/PolynomialTest.kt | 86 ++++++++++++++++--- .../kmath/functions/PolynomialUtilTest.kt | 27 ++++++ 3 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt 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 9c1f9efae..7e0f6f62d 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 @@ -369,14 +369,14 @@ public open class PolynomialSpace>( */ public override fun Polynomial.isOne(): Boolean = with(coefficients) { - isNotEmpty() && withIndex().any { (index, c) -> if (index == 0) c.isOne() else c.isZero() } + isNotEmpty() && withIndex().all { (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() && withIndex().any { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } } /** @@ -415,7 +415,7 @@ public open class PolynomialSpace>( with(coefficients) { when { isEmpty() -> constantZero - degree > 0 -> null + withIndex().any { (index, c) -> index == 0 || c.isZero() } -> null else -> first() } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 0bf34f198..85b309467 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -5,10 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.algebra import space.kscience.kmath.test.misc.* -import kotlin.test.Test -import kotlin.test.assertEquals +import kotlin.test.* class PolynomialTest { @@ -393,6 +391,21 @@ class PolynomialTest { } } @Test + fun test_Polynomial_unaryMinus() { + RationalField.polynomial { + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test fun test_Polynomial_Polynomial_plus() { RationalField.polynomial { // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 @@ -459,17 +472,66 @@ class PolynomialTest { } } @Test - fun simple_polynomial_test() { - val polynomial : Polynomial - Double.algebra.scalablePolynomial { - val x = Polynomial(listOf(0.0, 1.0)) - polynomial = x * x - 2 * x + 1 + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).polynomial { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + Polynomial(1, 0, 1, 0, 1), + Polynomial(1, -1, 1) * Polynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + Polynomial(), + Polynomial(5, -25, 10) * Polynomial(21, 14, -7), + "test 2" + ) } - assertEquals(0.0, polynomial.substitute(1.0), 0.001) } @Test - fun testIntegration() { - val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.substitute(1.0), 0.001) + fun test_Polynomial_isZero() { + RationalField.polynomial { + assertTrue("test 1") { Polynomial().isZero() } + assertTrue("test 2") { Polynomial(Rational(0)).isZero() } + assertTrue("test 3") { Polynomial(Rational(0), Rational(0)).isZero() } + assertTrue("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isZero() } + assertFalse("test 5") { Polynomial(Rational(3, 5)).isZero() } + assertFalse("test 6") { Polynomial(Rational(3, 5), Rational(0)).isZero() } + assertFalse("test 7") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isZero() } + } + } + @Test + fun test_Polynomial_isOne() { + RationalField.polynomial { + assertFalse("test 1") { Polynomial().isOne() } + assertFalse("test 2") { Polynomial(Rational(0)).isOne() } + assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isOne() } + assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isOne() } + assertFalse("test 5") { Polynomial(Rational(3, 5)).isOne() } + assertTrue("test 6") { Polynomial(Rational(5, 5)).isOne() } + assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isOne() } + assertTrue("test 8") { Polynomial(Rational(3, 3), Rational(0)).isOne() } + assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isOne() } + assertFalse("test 10") { Polynomial(Rational(0), Rational(5, 5), Rational(0)).isOne() } + assertFalse("test 11") { Polynomial(Rational(1), Rational(3, 5), Rational(0)).isOne() } + assertFalse("test 12") { Polynomial(Rational(1), Rational(5, 5), Rational(0)).isOne() } + } + } + @Test + fun test_Polynomial_isMinusOne() { + RationalField.polynomial { + assertFalse("test 1") { Polynomial().isMinusOne() } + assertFalse("test 2") { Polynomial(Rational(0)).isMinusOne() } + assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isMinusOne() } + assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isMinusOne() } + assertFalse("test 5") { Polynomial(Rational(3, 5)).isMinusOne() } + assertTrue("test 6") { Polynomial(Rational(-5, 5)).isMinusOne() } + assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isMinusOne() } + assertTrue("test 8") { Polynomial(Rational(-3, 3), Rational(0)).isMinusOne() } + assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isMinusOne() } + assertFalse("test 10") { Polynomial(Rational(0), Rational(5, -5), Rational(0)).isMinusOne() } + assertFalse("test 11") { Polynomial(Rational(-1), Rational(3, 5), Rational(0)).isMinusOne() } + assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() } + } } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt new file mode 100644 index 000000000..b9dd74800 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.algebra +import kotlin.test.Test +import kotlin.test.assertEquals + +class PolynomialUtilTest { + @Test + fun simple_polynomial_test() { + val polynomial : Polynomial + Double.algebra.scalablePolynomial { + val x = Polynomial(listOf(0.0, 1.0)) + polynomial = x * x - 2 * x + 1 + } + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + @Test + fun testIntegration() { + val polynomial = Polynomial(1.0, -2.0, 1.0) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } +} \ No newline at end of file From 25ec59b9851e71e3a652e043002a50902e8479b4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 20 Mar 2022 23:22:39 +0300 Subject: [PATCH 042/174] Finished with tests for Polynomial. --- .../kscience/kmath/functions/Polynomial.kt | 17 +- .../kmath/functions/polynomialUtil.kt | 50 ++-- .../kmath/functions/PolynomialTest.kt | 154 ++++++++++++ .../kmath/functions/PolynomialUtilTest.kt | 223 +++++++++++++++++- 4 files changed, 407 insertions(+), 37 deletions(-) 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 7e0f6f62d..d6c959fd1 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 @@ -386,7 +386,7 @@ public open class PolynomialSpace>( /** * Instance of unit constant (unit of the underlying ring). */ - override val one: Polynomial = Polynomial(listOf(constantZero)) + override val one: Polynomial = Polynomial(listOf(constantOne)) /** * Checks equality of the polynomials. @@ -394,11 +394,8 @@ public open class PolynomialSpace>( public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = when { this === other -> true - else -> { - if (this.degree == other.degree) - (0..degree).all { coefficients[it] == other.coefficients[it] } - else false - } + this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } + else -> false } /** @@ -415,8 +412,8 @@ public open class PolynomialSpace>( with(coefficients) { when { isEmpty() -> constantZero - withIndex().any { (index, c) -> index == 0 || c.isZero() } -> null - else -> first() + withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() + else -> null } } @@ -489,8 +486,6 @@ public open class PolynomialSpace>( public class ScalablePolynomialSpace( ring: A, ) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } - + ring { Polynomial(a.coefficients.map { scale(it, value) }) } } 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 84c8d2e88..afaf27a52 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 @@ -127,9 +127,10 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol if (argDegree == -1) return coefficients[0].asPolynomial() val constantZero = zero val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] val resultCoefsUpdate: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } var resultDegree = 0 - for (deg in thisDegree downTo 0) { + for (deg in thisDegree - 1 downTo 0) { resultCoefsUpdate[0] = coefficients[deg] multiplyAddingToUpdater( ring = ring, @@ -142,6 +143,8 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol ) resultDegree += argDegree } + + with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) } return Polynomial(resultCoefs) } @@ -162,7 +165,12 @@ 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 + 1) * c }) + Polynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** @@ -171,9 +179,16 @@ public fun Polynomial.derivative( @UnstableKMathAPI public fun Polynomial.nthDerivative( algebra: A, - order: UInt, + order: Int, ): 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) } }) + require(order >= 0) { "Order of derivative must be non-negative" } + Polynomial( + 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) }) + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** @@ -183,11 +198,13 @@ public fun Polynomial.nthDerivative( public fun Polynomial.antiderivative( algebra: A, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - Polynomial(integratedCoefficients) + Polynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** @@ -196,13 +213,16 @@ public fun Polynomial.antiderivative( @UnstableKMathAPI public fun Polynomial.nthAntiderivative( algebra: A, - order: UInt, + order: Int, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - 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) } } - } - return Polynomial(newCoefficients) + require(order >= 0) { "Order of antiderivative must be non-negative" } + Polynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) + } + ) } /** diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 85b309467..141bdd436 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -534,4 +534,158 @@ class PolynomialTest { assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() } } } + @Test + fun test_Polynomial_equalsTo() { + RationalField.polynomial { + assertTrue("test 1") { + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertTrue("test 2") { + Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertTrue("test 3") { + Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + Polynomial(Rational(0), Rational(0), Rational(-8, 7)) + } + assertFalse("test 4") { + Polynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertFalse("test 5") { + Polynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo + Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertFalse("test 6") { + Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + Polynomial(Rational(0), Rational(0), Rational(8, 7)) + } + } + } + @Test + fun test_Polynomial_degree() { + RationalField.polynomial { + assertEquals( + 2, + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, + "test 1" + ) + assertEquals( + -1, + Polynomial().degree, + "test 2" + ) + assertEquals( + -1, + Polynomial(Rational(0)).degree, + "test 3" + ) + assertEquals( + -1, + Polynomial(Rational(0), Rational(0)).degree, + "test 4" + ) + assertEquals( + -1, + Polynomial(Rational(0), Rational(0), Rational(0)).degree, + "test 5" + ) + assertEquals( + 0, + Polynomial(Rational(5, 9)).degree, + "test 6" + ) + assertEquals( + 0, + Polynomial(Rational(5, 9), Rational(0)).degree, + "test 7" + ) + assertEquals( + 0, + Polynomial(Rational(5, 9), Rational(0), Rational(0)).degree, + "test 8" + ) + assertEquals( + 2, + Polynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, + "test 9" + ) + assertEquals( + 2, + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 10" + ) + assertEquals( + 2, + Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 11" + ) + } + } + @Test + fun test_Polynomial_asConstantOrNull() { + RationalField.polynomial { + assertEquals( + Rational(0), + Polynomial().asConstantOrNull(), + "test 1" + ) + assertEquals( + Rational(0), + Polynomial(Rational(0)).asConstantOrNull(), + "test 2" + ) + assertEquals( + Rational(0), + Polynomial(Rational(0), Rational(0)).asConstantOrNull(), + "test 3" + ) + assertEquals( + Rational(0), + Polynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), + "test 4" + ) + assertEquals( + Rational(-7, 9), + Polynomial(Rational(-7, 9)).asConstantOrNull(), + "test 5" + ) + assertEquals( + Rational(-7, 9), + Polynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 6" + ) + assertEquals( + Rational(-7, 9), + Polynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), + "test 7" + ) + assertEquals( + null, + Polynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 8" + ) + assertEquals( + null, + Polynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 9" + ) + assertEquals( + null, + Polynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 10" + ) + assertEquals( + null, + Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 11" + ) + assertEquals( + null, + Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 12" + ) + } + } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index b9dd74800..fbae61ed1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -5,23 +5,224 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFailsWith class PolynomialUtilTest { @Test - fun simple_polynomial_test() { - val polynomial : Polynomial - Double.algebra.scalablePolynomial { - val x = Polynomial(listOf(0.0, 1.0)) - polynomial = x * x - 2 * x + 1 - } - assertEquals(0.0, polynomial.substitute(1.0), 0.001) - } - @Test - fun testIntegration() { + fun test_substitute_Double() { val polynomial = Polynomial(1.0, -2.0, 1.0) assertEquals(0.0, polynomial.substitute(1.0), 0.001) } + @Test + fun test_substitute_Constant() { + assertEquals( + Rational(0), + Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + Polynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + Polynomial(), + Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Polynomial(Rational(1))), + "test 1" + ) + assertEquals( + Polynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 2" + ) + assertEquals( + Polynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 3" + ) + assertEquals( + Polynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), + Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 4" + ) + assertEquals( + Polynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), + Polynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), + "test 5" + ) + assertEquals( + Polynomial(Rational(89, 54)), + Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, Polynomial(Rational(6, 9), Rational(0))), + "test 6" + ) + } + @Test + fun test_derivative() { + assertEquals( + Polynomial(Rational(-2), Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthDerivative() { + assertEquals( + Polynomial(Rational(-2), Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) + } + assertEquals( + Polynomial(Rational(1), Rational(-2), Rational(1)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), + "test 3" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), + "test 4" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), + "test 5" + ) + assertEquals( + Polynomial(), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), + "test 6" + ) + assertEquals( + Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 7" + ) + assertEquals( + Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 8" + ) + assertEquals( + Polynomial(Rational(8, 9), Rational(30, 7)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), + "test 9" + ) + } + @Test + fun test_antiderivative() { + assertEquals( + Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthAntiderivative() { + assertEquals( + Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) + } + assertEquals( + Polynomial(Rational(1), Rational(-2), Rational(1)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), + "test 3" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), + "test 4" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), + "test 5" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), + Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), + "test 6" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 7" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 8" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), + "test 9" + ) + } } \ No newline at end of file From 88e0dcf413d518e571118eb5d1bf3310110bad5c Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 18:26:09 +0300 Subject: [PATCH 043/174] Added usage of more correct exceptions. --- .../kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt | 2 +- .../space/kscience/kmath/functions/AbstractRationalFunction.kt | 2 +- .../kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt | 1 + 3 files changed, 3 insertions(+), 2 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 aacf055fa..fd1b51fae 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 @@ -295,7 +295,7 @@ public interface AbstractPolynomialSpace> : Ring

* If polynomial is a constant polynomial represents and returns it as constant. * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ - public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right 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 b9ca01da4..cdc4bf530 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 @@ -460,7 +460,7 @@ public interface AbstractRationalFunctionalSpace, R: * If polynomial is a constant polynomial represents and returns it as constant. * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ - public fun P.asConstant(): C = asConstantOrNull() ?: error("Can not represent non-constant polynomial as a constant") + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index fbae61ed1..21c5436d3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -11,6 +11,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith + class PolynomialUtilTest { @Test fun test_substitute_Double() { From 83d57c7295a7b79a9991417c8ede01efc935a54d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 21:22:25 +0300 Subject: [PATCH 044/174] Added RFs' interface to remove another boilerplate. Fixed bug in RFs' equalsTo. --- .../functions/AbstractRationalFunction.kt | 228 +++++++++++++++++- .../functions/LabeledRationalFunction.kt | 216 ++--------------- .../functions/NumberedRationalFunction.kt | 216 ++--------------- .../kmath/functions/RationalFunction.kt | 221 ++--------------- 4 files changed, 277 insertions(+), 604 deletions(-) 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 cdc4bf530..7feab3dfb 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 @@ -423,7 +423,13 @@ public interface AbstractRationalFunctionalSpace, R: /** * Checks equality of the rational functions. */ - public infix fun R.equalsTo(other: R): Boolean + public infix fun R.equalsTo(other: R): Boolean = + when { + this === other -> true + numerator.isZero() != other.numerator.isZero() -> false + numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false + else -> numerator * other.denominator equalsTo other.numerator * denominator + } /** * Checks NOT equality of the polynomials. */ @@ -857,4 +863,224 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and + * polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public abstract class AbstractPolynomialFractionsSpace< + C, + P: AbstractPolynomial, + R: AbstractRationalFunction, + > : AbstractRationalFunctionalSpace { + protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R + + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun R.plus(other: Int): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * 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 override operator fun R.minus(other: Int): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * 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 override operator fun R.times(other: Int): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun R.plus(other: C): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun R.minus(other: C): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun R.times(other: C): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun P.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.plus(other: P): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun R.minus(other: P): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.times(other: P): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R = constructRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R = + constructRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R = + constructRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R = + constructRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) + + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 9b5022f85..09b0b25ae 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -64,205 +64,25 @@ public class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - > { +) : + AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + >, + AbstractPolynomialFractionsSpace< + C, + LabeledPolynomial, + LabeledRationalFunction, + >() { override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledRationalFunction.plus(other: Int): LabeledRationalFunction = - LabeledRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * 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 override operator fun LabeledRationalFunction.minus(other: Int): LabeledRationalFunction = - LabeledRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * 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 override operator fun LabeledRationalFunction.times(other: Int): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.plus(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.minus(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.times(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledPolynomial.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun LabeledPolynomial.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun LabeledPolynomial.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.plus(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.minus(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun LabeledRationalFunction.times(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun LabeledRationalFunction.unaryMinus(): LabeledRationalFunction = LabeledRationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun LabeledRationalFunction.plus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun LabeledRationalFunction.minus(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun LabeledRationalFunction.times(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) + override fun constructRationalFunction( + numerator: LabeledPolynomial, + denominator: LabeledPolynomial + ): LabeledRationalFunction = + LabeledRationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). @@ -279,7 +99,7 @@ public class LabeledRationalFunctionSpace>( public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { if (this === other) return true - if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + if (numerator.isZero() != other.numerator.isZero()) return false val variables = this.variables union other.variables val thisNumeratorDegrees = this.numerator.degrees diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 78ba233f5..4927460fb 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -60,205 +60,25 @@ public class NumberedRationalFunction internal constructor( public class NumberedRationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - > { +) : + AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + >, + AbstractPolynomialFractionsSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + >() { override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedRationalFunction.plus(other: Int): NumberedRationalFunction = - NumberedRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * 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 override operator fun NumberedRationalFunction.minus(other: Int): NumberedRationalFunction = - NumberedRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * 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 override operator fun NumberedRationalFunction.times(other: Int): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.plus(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.minus(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.times(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedPolynomial.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun NumberedPolynomial.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun NumberedPolynomial.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.plus(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.minus(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun NumberedRationalFunction.times(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun NumberedRationalFunction.unaryMinus(): NumberedRationalFunction = NumberedRationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun NumberedRationalFunction.plus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun NumberedRationalFunction.minus(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun NumberedRationalFunction.times(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) + override fun constructRationalFunction( + numerator: NumberedPolynomial, + denominator: NumberedPolynomial + ): NumberedRationalFunction = + NumberedRationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). @@ -275,7 +95,7 @@ public class NumberedRationalFunctionSpace> ( public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { if (this === other) return true - if ( !(numerator.isZero() xor other.numerator.isZero()) ) return false + if (numerator.isZero() != other.numerator.isZero()) return false val countOfVariables = max(this.lastVariable, other.lastVariable) val thisNumeratorDegrees = this.numerator.degrees diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 226eddce9..506aa4004 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -42,205 +42,22 @@ public data class RationalFunction internal constructor ( public class RationalFunctionSpace> ( public val ring: A, -) : AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - Polynomial, - RationalFunction, - PolynomialSpace, - > { +) : + AbstractRationalFunctionalSpaceOverPolynomialSpace< + C, + Polynomial, + RationalFunction, + PolynomialSpace, + >, + AbstractPolynomialFractionsSpace< + C, + Polynomial, + RationalFunction, + >() { override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun RationalFunction.plus(other: Int): RationalFunction = - RationalFunction( - numerator + denominator * other, - denominator - ) - /** - * 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 override operator fun RationalFunction.minus(other: Int): RationalFunction = - RationalFunction( - numerator - denominator * other, - denominator - ) - /** - * 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 override operator fun RationalFunction.times(other: Int): RationalFunction = - RationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.minus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.times(other: RationalFunction): RationalFunction = - RationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: RationalFunction): RationalFunction = - RationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun RationalFunction.plus(other: C): RationalFunction = - RationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun RationalFunction.minus(other: C): RationalFunction = - RationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun RationalFunction.times(other: C): RationalFunction = - RationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun Polynomial.plus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun Polynomial.minus(other: RationalFunction): RationalFunction = - RationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun Polynomial.times(other: RationalFunction): RationalFunction = - RationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun RationalFunction.plus(other: Polynomial): RationalFunction = - RationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun RationalFunction.minus(other: Polynomial): RationalFunction = - RationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun RationalFunction.times(other: Polynomial): RationalFunction = - RationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun RationalFunction.unaryMinus(): RationalFunction = RationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun RationalFunction.plus(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun RationalFunction.minus(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun RationalFunction.times(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) + override fun constructRationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = + RationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). @@ -251,16 +68,6 @@ public class RationalFunctionSpace> ( */ public override val one: RationalFunction = RationalFunction(polynomialOne, polynomialOne) - /** - * Checks equality of the rational functions. - */ - public override infix fun RationalFunction.equalsTo(other: RationalFunction): Boolean = - when { - this === other -> true - numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false - else -> numerator * other.denominator equalsTo other.numerator * denominator - } - // TODO: Разобрать public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = From 51b0d232b561ecc57fe6d6660c9a9d104a447dd2 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 23:21:55 +0300 Subject: [PATCH 045/174] Renamed `AbstractPolynomialFractionsSpace` to `PolynomialSpaceOfFractions` --- .../kscience/kmath/functions/AbstractRationalFunction.kt | 5 ++--- .../kscience/kmath/functions/LabeledRationalFunction.kt | 2 +- .../kscience/kmath/functions/NumberedRationalFunction.kt | 2 +- .../space/kscience/kmath/functions/RationalFunction.kt | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) 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 7feab3dfb..c9c0b3920 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 @@ -867,8 +867,7 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and - * polynomial-wise operations. + * [C]. It also assumes that there is provided constructor * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -876,7 +875,7 @@ public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ // TODO: Add support of field @Suppress("INAPPLICABLE_JVM_NAME") -public abstract class AbstractPolynomialFractionsSpace< +public abstract class PolynomialSpaceOfFractions< C, P: AbstractPolynomial, R: AbstractRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 09b0b25ae..92bd344ac 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -71,7 +71,7 @@ public class LabeledRationalFunctionSpace>( LabeledRationalFunction, LabeledPolynomialSpace, >, - AbstractPolynomialFractionsSpace< + PolynomialSpaceOfFractions< C, LabeledPolynomial, LabeledRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 4927460fb..4da715e3f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -67,7 +67,7 @@ public class NumberedRationalFunctionSpace> ( NumberedRationalFunction, NumberedPolynomialSpace, >, - AbstractPolynomialFractionsSpace< + PolynomialSpaceOfFractions< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 506aa4004..51c1e2f80 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -49,7 +49,7 @@ public class RationalFunctionSpace> ( RationalFunction, PolynomialSpace, >, - AbstractPolynomialFractionsSpace< + PolynomialSpaceOfFractions< C, Polynomial, RationalFunction, From c6d1068df465dca4374dde7cb1395cb9dbcff8f9 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 21 Mar 2022 23:47:10 +0300 Subject: [PATCH 046/174] Renamed `Polynomial`, etc. to `ListPolynomial`, etc. and `AbstractPolynomial` to `Polynomial`. As it was advised by @CommanderTvis. --- .../kmath/functions/AbstractPolynomial.kt | 389 ------ .../functions/AbstractRationalFunction.kt | 1085 --------------- .../kmath/functions/LabeledPolynomial.kt | 4 +- .../functions/LabeledRationalFunction.kt | 4 +- .../kmath/functions/ListPolynomial.kt | 491 +++++++ .../kmath/functions/ListRationalFunction.kt | 154 +++ .../kmath/functions/NumberedPolynomial.kt | 4 +- .../functions/NumberedRationalFunction.kt | 4 +- .../kscience/kmath/functions/Piecewise.kt | 22 +- .../kscience/kmath/functions/Polynomial.kt | 644 ++++----- .../kmath/functions/RationalFunction.kt | 1175 +++++++++++++++-- .../functions/labeledRationalFunctionUtil.kt | 2 +- ...olynomialUtil.kt => listPolynomialUtil.kt} | 66 +- ...ionUtil.kt => listRationalFunctionUtil.kt} | 26 +- .../functions/numberedRationalFunctionUtil.kt | 2 +- .../kmath/interpolation/LinearInterpolator.kt | 4 +- .../kmath/interpolation/SplineInterpolator.kt | 4 +- .../kmath/functions/ListPolynomialTest.kt | 705 ++++++++++ .../kmath/functions/ListPolynomialUtilTest.kt | 229 ++++ .../kmath/functions/PolynomialTest.kt | 691 ---------- .../kmath/functions/PolynomialUtilTest.kt | 229 ---- .../kmath/integration/SplineIntegralTest.kt | 4 +- .../kscience/kmath/test/misc/IntModulo.kt | 14 +- 23 files changed, 2983 insertions(+), 2969 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{polynomialUtil.kt => listPolynomialUtil.kt} (72%) rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{rationalFunctionUtil.kt => listRationalFunctionUtil.kt} (88%) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt 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 deleted file mode 100644 index fd1b51fae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.* -import kotlin.js.JsName -import kotlin.jvm.JvmName - - -/** - * Abstraction of polynomials. - */ -public interface AbstractPolynomial - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") -public interface AbstractPolynomialSpace> : Ring

{ - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public operator fun C.plus(other: Int): C - /** - * 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 operator fun C.minus(other: Int): C - /** - * 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 operator fun C.times(other: Int): C - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public operator fun Int.plus(other: C): C - /** - * 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 operator fun Int.minus(other: C): C - /** - * 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 operator fun Int.times(other: C): C - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - 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 = 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 = multiplyBySquaring(this, other) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P = 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 = 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 = multiplyBySquaring(other, this) - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - @JsName("constantPlus") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - @JsName("constantMinus") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @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. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public val constantZero: C - /** - * Instance of unit constant (unit of the underlying ring). - */ - public val constantOne: C - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun C.plus(other: P): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun C.minus(other: P): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun C.times(other: P): P - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun P.plus(other: C): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun P.minus(other: C): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun P.times(other: C): P - - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = this - /** - * Returns negation of the polynomial. - */ - public override operator fun P.unaryMinus(): P - /** - * Returns sum of the polynomials. - */ - public override operator fun P.plus(other: P): P - /** - * Returns difference of the polynomials. - */ - public override operator fun P.minus(other: P): P - /** - * 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. - */ - public fun P.isZero(): Boolean = this equalsTo zero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo one - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -one - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - public override val zero: P - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - public override val one: P - - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val P.degree: Int - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - - override fun add(left: P, right: P): P = left + right - override fun multiply(left: P, right: P): P = left * right -} - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is - * provided [ring] (of type [A]), that provides constant-wise operations. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. - */ -@Suppress("INAPPLICABLE_JVM_NAME") -public interface AbstractPolynomialSpaceOverRing, A: Ring> : AbstractPolynomialSpace { - - public val ring: A - - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { 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 { 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 { multiplyBySquaring(this@times, other) } - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { 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 { 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 { multiplyBySquaring(other, this@times) } - - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @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). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one -} \ No newline at end of file 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 deleted file mode 100644 index c9c0b3920..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/AbstractRationalFunction.kt +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.* -import kotlin.js.JsName -import kotlin.jvm.JvmName - - -/** - * Abstraction of rational function. - */ -public interface AbstractRationalFunction> { - public val numerator: P - public val denominator: P - public operator fun component1(): P = numerator - public operator fun component2(): P = denominator -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") -public interface AbstractRationalFunctionalSpace, R: AbstractRationalFunction> : Ring { - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public operator fun C.plus(other: Int): C - /** - * 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 operator fun C.minus(other: Int): C - /** - * 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 operator fun C.times(other: Int): C - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public operator fun Int.plus(other: C): C - /** - * 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 operator fun Int.minus(other: C): C - /** - * 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 operator fun Int.times(other: C): C - - /** - * Returns sum of the constant and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun P.plus(other: Int): P - /** - * Returns difference between the constant 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 - /** - * Returns product of the constant 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 - - /** - * Returns sum of the integer represented as polynomial and the constant. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P - /** - * Returns difference between the integer represented as polynomial and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: P): P - /** - * Returns product of the integer represented as polynomial and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: P): P - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - 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 = 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 = multiplyBySquaring(this, other) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - 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 = 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 = multiplyBySquaring(other, this) - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - @JsName("constantPlus") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - @JsName("constantMinus") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @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. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public val constantZero: C - /** - * Instance of unit constant (unit of the underlying ring). - */ - public val constantOne: C - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun C.plus(other: P): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun C.minus(other: P): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun C.times(other: P): P - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public operator fun P.plus(other: C): P - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public operator fun P.minus(other: C): P - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public operator fun P.times(other: C): P - - /** - * Returns the same polynomial. - */ - public operator fun P.unaryPlus(): P = this - /** - * Returns negation of the polynomial. - */ - public operator fun P.unaryMinus(): P - /** - * Returns sum of the polynomials. - */ - public operator fun P.plus(other: P): P - /** - * Returns difference of the polynomials. - */ - public operator fun P.minus(other: P): P - /** - * 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. - */ - public fun P.isZero(): Boolean = this equalsTo polynomialZero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo polynomialOne - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - public val polynomialZero: P - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - public val polynomialOne: P - - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public operator fun C.plus(other: R): R - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public operator fun C.minus(other: R): R - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public operator fun C.times(other: R): R - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public operator fun R.plus(other: C): R - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public operator fun R.minus(other: C): R - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public operator fun R.times(other: C): R - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public operator fun P.plus(other: R): R - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public operator fun P.minus(other: R): R - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public operator fun P.times(other: R): R - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public operator fun R.plus(other: P): R - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public operator fun R.minus(other: P): R - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public operator fun R.times(other: P): R - - /** - * Returns the same rational function. - */ - public override operator fun R.unaryPlus(): R = this - /** - * Returns negation of the rational function. - */ - public override operator fun R.unaryMinus(): R - /** - * Returns sum of the rational functions. - */ - public override operator fun R.plus(other: R): R - /** - * Returns difference of the rational functions. - */ - public override operator fun R.minus(other: R): 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. - */ - public fun R.isZero(): Boolean = numerator equalsTo polynomialZero - /** - * Check if the instant is NOT zero rational function. - */ - public fun R.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit rational function. - */ - public fun R.isOne(): Boolean = numerator equalsTo denominator - /** - * Check if the instant is NOT unit rational function. - */ - public fun R.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit rational function. - */ - public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() - /** - * Check if the instant is NOT minus unit rational function. - */ - public fun R.isNotMinusOne(): Boolean = !isMinusOne() - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: R - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: R - - /** - * Checks equality of the rational functions. - */ - public infix fun R.equalsTo(other: R): Boolean = - when { - this === other -> true - numerator.isZero() != other.numerator.isZero() -> false - numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false - else -> numerator * other.denominator equalsTo other.numerator * denominator - } - /** - * Checks NOT equality of the polynomials. - */ - public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val P.degree: Int - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val R.numeratorDegree: Int get() = numerator.degree - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public val R.denominatorDegree: Int get() = denominator.degree - - override fun add(left: R, right: R): R = left + right - override fun multiply(left: R, right: R): R = left * right -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided [ring] (of type [A]), that provides constant-wise operations. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME") -public interface AbstractRationalFunctionalSpaceOverRing, R: AbstractRationalFunction, A: Ring> : AbstractRationalFunctionalSpace { - - public val ring: A - - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { 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 { 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 { multiplyBySquaring(this@times, other) } - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { 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 { 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 { multiplyBySquaring(other, this@times) } - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = ring { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and - * polynomial-wise operations. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME") -public interface AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - P: AbstractPolynomial, - R: AbstractRationalFunction, - AP: AbstractPolynomialSpace, - > : AbstractRationalFunctionalSpace { - - public val polynomialRing: AP - - /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + 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 = polynomialRing { this@minus - 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 = polynomialRing { this@times * other } - - /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } - /** - * 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 = polynomialRing { this@minus - other } - /** - * 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 = polynomialRing { this@times * other } - - /** - * Returns sum of the constant and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } - /** - * Returns difference between the constant and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } - /** - * Returns product of the constant and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } - - /** - * Returns sum of the integer represented as polynomial and the constant. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } - /** - * Returns difference between the integer represented as polynomial and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } - /** - * Returns product of the integer represented as polynomial and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } - - /** - * Returns the same constant. - */ - @JvmName("constantUnaryPlus") - public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } - /** - * Returns negation of the constant. - */ - @JvmName("constantUnaryMinus") - public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("constantPlus") - public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("constantMinus") - public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("constantTimes") - public override operator fun C.times(other: C): C = polynomialRing { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("constantPower") - public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } - - /** - * Check if the instant is zero constant. - */ - public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero constant. - */ - public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit constant. - */ - public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit constant. - */ - public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit constant. - */ - public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit constant. - */ - public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = polynomialRing.constantZero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = polynomialRing.constantOne - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.times(other: P): P = polynomialRing { this@times * other } - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun P.times(other: C): P = polynomialRing { this@times * other } - - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } - /** - * Returns negation of the polynomial. - */ - public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } - /** - * Returns sum of the polynomials. - */ - public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } - /** - * Returns difference of the polynomials. - */ - public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } - /** - * Returns product of the polynomials. - */ - public override operator fun P.times(other: P): P = polynomialRing { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } - - /** - * Check if the instant is zero polynomial. - */ - public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero polynomial. - */ - public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit polynomial. - */ - public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit polynomial. - */ - public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - public override val polynomialZero: P get() = polynomialRing.zero - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - public override val polynomialOne: P get() = polynomialRing.one - - /** - * Checks equality of the polynomials. - */ - public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } - /** - * Checks NOT equality of the polynomials. - */ - public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public override val P.degree: Int get() = polynomialRing { this@degree.degree } - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } -} - -/** - * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. - * @param R the type of rational functions. - * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field -@Suppress("INAPPLICABLE_JVM_NAME") -public abstract class PolynomialSpaceOfFractions< - C, - P: AbstractPolynomial, - R: AbstractRationalFunction, - > : AbstractRationalFunctionalSpace { - protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R - - /** - * Returns sum of the rational function and the integer represented as rational function. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun R.plus(other: Int): R = - constructRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * 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 override operator fun R.minus(other: Int): R = - constructRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * 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 override operator fun R.times(other: Int): R = - constructRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the integer represented as rational function and the rational function. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: R): R = - constructRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.minus(other: R): R = - constructRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * 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 override operator fun Int.times(other: R): R = - constructRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun C.plus(other: R): R = - constructRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the constant represented as polynomial and the rational function. - */ - public override operator fun C.minus(other: R): R = - constructRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the constant represented as polynomial and the rational function. - */ - public override operator fun C.times(other: R): R = - constructRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the constant represented as rational function and the rational function. - */ - public override operator fun R.plus(other: C): R = - constructRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the constant represented as rational function and the rational function. - */ - public override operator fun R.minus(other: C): R = - constructRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the constant represented as rational function and the rational function. - */ - public override operator fun R.times(other: C): R = - constructRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun P.plus(other: R): R = - constructRationalFunction( - other.denominator * this + other.numerator, - other.denominator - ) - /** - * Returns difference between the polynomial represented as polynomial and the rational function. - */ - public override operator fun P.minus(other: R): R = - constructRationalFunction( - other.denominator * this - other.numerator, - other.denominator - ) - /** - * Returns product of the polynomial represented as polynomial and the rational function. - */ - public override operator fun P.times(other: R): R = - constructRationalFunction( - this * other.numerator, - other.denominator - ) - - /** - * Returns sum of the polynomial represented as rational function and the rational function. - */ - public override operator fun R.plus(other: P): R = - constructRationalFunction( - numerator + denominator * other, - denominator - ) - /** - * Returns difference between the polynomial represented as rational function and the rational function. - */ - public override operator fun R.minus(other: P): R = - constructRationalFunction( - numerator - denominator * other, - denominator - ) - /** - * Returns product of the polynomial represented as rational function and the rational function. - */ - public override operator fun R.times(other: P): R = - constructRationalFunction( - numerator * other, - denominator - ) - - /** - * Returns negation of the rational function. - */ - public override operator fun R.unaryMinus(): R = constructRationalFunction(-numerator, denominator) - /** - * Returns sum of the rational functions. - */ - public override operator fun R.plus(other: R): R = - constructRationalFunction( - numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns difference of the rational functions. - */ - public override operator fun R.minus(other: R): R = - constructRationalFunction( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator - ) - /** - * Returns product of the rational functions. - */ - public override operator fun R.times(other: R): R = - constructRationalFunction( - numerator * other.numerator, - denominator * other.denominator - ) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) - - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 76f5fc29c..968f77b20 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -44,7 +44,7 @@ internal constructor( * where `a`, `b` and `c` are corresponding [Symbol] objects. */ public val coefficients: Map, C> -) : AbstractPolynomial { +) : Polynomial { override fun toString(): String = "LabeledPolynomial$coefficients" } @@ -116,7 +116,7 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia */ public class LabeledPolynomialSpace>( public override val ring: A, -) : AbstractPolynomialSpaceOverRing, A> { +) : PolynomialSpaceOverRing, A> { public operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 92bd344ac..f347f9191 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.operations.invoke public class LabeledRationalFunction( public override val numerator: LabeledPolynomial, public override val denominator: LabeledPolynomial -) : AbstractRationalFunction> { +) : RationalFunction> { override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } @@ -65,7 +65,7 @@ public class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, ) : - AbstractRationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionalSpaceOverPolynomialSpace< C, LabeledPolynomial, LabeledRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt new file mode 100644 index 000000000..b97c1e0b4 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -0,0 +1,491 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.experimental.ExperimentalTypeInference +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + +/** + * Polynomial model without fixation on specific context they are applied to. + * + * @param coefficients constant is the leftmost coefficient. + */ +public data class ListPolynomial( + /** + * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients + * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not + * prohibited. + */ + public val coefficients: List +) : Polynomial { + override fun toString(): String = "Polynomial$coefficients" +} + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun C.asPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + +/** + * Space of univariate polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public open class ListPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * 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 override operator fun ListPolynomial.minus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * Returns product of the polynomial and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun ListPolynomial.times(other: Int): ListPolynomial = + if (other == 0) zero + else ListPolynomial( + coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this[deg] * other + } + ) + + /** + * Returns sum of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = + if (this == 0) other + else + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + val result = this@plus + getOrElse(0) { constantZero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * 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 override operator fun Int.minus(other: ListPolynomial): ListPolynomial = + if (this == 0) other + else + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = this@minus - getOrElse(0) { constantZero } + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + /** + * Returns product of the integer represented as polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: ListPolynomial): ListPolynomial = + if (this == 0) zero + else ListPolynomial( + other.coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.plus(other: ListPolynomial): ListPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@plus)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) this@plus else this@plus + get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun C.minus(other: ListPolynomial): ListPolynomial = + if (this.isZero()) other + else with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@minus)) + else ListPolynomial( + toMutableList() + .apply { + forEachIndexed { index, c -> if (index != 0) this[index] = -c } + + val result = if (size == 0) this@minus else this@minus - get(0) + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.times(other: ListPolynomial): ListPolynomial = + if (this.isZero()) other + else ListPolynomial( + other.coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun ListPolynomial.plus(other: C): ListPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) + other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun ListPolynomial.minus(other: C): ListPolynomial = + if (other.isZero()) this + else with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(-other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) - other + val isResultZero = result.isZero() + + when { + size == 0 && !isResultZero -> add(result) + size > 1 || !isResultZero -> this[0] = result + else -> clear() + } + } + ) + } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun ListPolynomial.times(other: C): ListPolynomial = + if (other.isZero()) this + else ListPolynomial( + coefficients + .applyAndRemoveZeros { + for (deg in indices) this[deg] = this[deg] * other + } + ) + + /** + * Returns negation of the polynomial. + */ + public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = + ListPolynomial(coefficients.map { -it }) + /** + * Returns sum of the polynomials. + */ + public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + ) + } + /** + * Returns difference of the polynomials. + */ + public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + Coefficients(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + ) + } + /** + * Returns product of the polynomials. + */ + public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return when { + thisDegree == -1 -> zero + otherDegree == -1 -> zero + else -> + ListPolynomial( + Coefficients(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) + } + } + + /** + * Check if the instant is zero polynomial. + */ + public override fun ListPolynomial.isZero(): Boolean = coefficients.all { it.isZero() } + /** + * Check if the instant is unit polynomial. + */ + public override fun ListPolynomial.isOne(): Boolean = + with(coefficients) { + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } + } + /** + * Check if the instant is minus unit polynomial. + */ + public override fun ListPolynomial.isMinusOne(): Boolean = + with(coefficients) { + isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } + } + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: ListPolynomial = ListPolynomial(emptyList()) + /** + * Instance of unit constant (unit of the underlying ring). + */ + override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) + + /** + * Checks equality of the polynomials. + */ + public override infix fun ListPolynomial.equalsTo(other: ListPolynomial): Boolean = + when { + this === other -> true + this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } + else -> false + } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val ListPolynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } + + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public override fun ListPolynomial.asConstantOrNull(): C? = + with(coefficients) { + when { + isEmpty() -> constantZero + withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() + else -> null + } + } + + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + + /** + * Evaluates the polynomial for the given value [argument]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + + // TODO: Move to other internal utilities with context receiver + @JvmName("applyAndRemoveZerosInternal") + internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + block() + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) + return this + } + internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = + toMutableList().applyAndRemoveZeros(block) + @Suppress("FunctionName") + internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { + val list = ArrayList(size) + repeat(size) { index -> list.add(init(index)) } + with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } + return list + } + @Suppress("FunctionName") + internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList { + builderAction() + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } + @OptIn(ExperimentalTypeInference::class) + internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { + contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } + return buildList(capacity) { + builderAction() + while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) + } + } +} + +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: ListPolynomial, value: Double): ListPolynomial = + ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt new file mode 100644 index 000000000..50ddd3118 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -0,0 +1,154 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring + + +public data class ListRationalFunction internal constructor ( + public override val numerator: ListPolynomial, + public override val denominator: ListPolynomial +) : RationalFunction> { + override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available + +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = +// if (denominator.isZero()) throw ArithmeticException("/ by zero") +// else RationalFunction(numerator, denominator) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), +// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } +// ) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numerator: Polynomial): RationalFunction = +// RationalFunction(numerator, onePolynomial) +//context(RationalFunctionSpace) +//@Suppress("FunctionName") +//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = +// RationalFunction( +// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) +// ) + +public class ListRationalFunctionSpace> ( + public val ring: A, +) : + RationalFunctionalSpaceOverPolynomialSpace< + C, + ListPolynomial, + ListRationalFunction, + ListPolynomialSpace, + >, + PolynomialSpaceOfFractions< + C, + ListPolynomial, + ListRationalFunction, + >() { + + override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) + override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, denominator) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) + + // TODO: Разобрать + + public operator fun ListRationalFunction.div(other: ListRationalFunction): ListRationalFunction = + ListRationalFunction( + numerator * other.denominator, + denominator * other.numerator + ) + + public operator fun ListRationalFunction.div(other: ListPolynomial): ListRationalFunction = + ListRationalFunction( + numerator, + denominator * other + ) + + public operator fun ListRationalFunction.div(other: C): ListRationalFunction = + ListRationalFunction( + numerator, + denominator * other + ) + + public operator fun ListRationalFunction.div(other: Int): ListRationalFunction = + ListRationalFunction( + numerator, + denominator * other + ) + +// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = +// RationalFunction( +// numerator(arg), +// denominator(arg) +// ) +// +// operator fun invoke(arg: RationalFunction): RationalFunction { +// val num = numerator invokeRFTakeNumerator arg +// val den = denominator invokeRFTakeNumerator arg +// val degreeDif = numeratorDegree - denominatorDegree +// return if (degreeDif > 0) +// RationalFunction( +// num, +// multiplyByPower(den, arg.denominator, degreeDif) +// ) +// else +// RationalFunction( +// multiplyByPower(num, arg.denominator, -degreeDif), +// den +// ) +// } +// +// override fun toString(): String = toString(UnivariatePolynomial.variableName) +// +// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toString(withVariableName) +// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" +// } +// +// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) +// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" +// } +// +// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedString(withVariableName) +// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" +// } +// +// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = +// when(true) { +// numerator.isZero() -> "0" +// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) +// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" +// } +// +// fun removeZeros() = +// RationalFunction( +// numerator.removeZeros(), +// denominator.removeZeros() +// ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index c05bc30ec..3b9b907b7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -43,7 +43,7 @@ internal constructor( * contain any zeros on end, but can contain zeros on start or anywhere in middle. */ public val coefficients: Map, C> -) : AbstractPolynomial { +) : Polynomial { override fun toString(): String = "NumberedPolynomial$coefficients" } @@ -112,7 +112,7 @@ public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolyno */ public open class NumberedPolynomialSpace>( public final override val ring: A, -) : AbstractPolynomialSpaceOverRing, A> { +) : PolynomialSpaceOverRing, A> { /** * Returns sum of the polynomial and the integer represented as polynomial. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 4da715e3f..f3b90b5c5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -12,7 +12,7 @@ import kotlin.math.max public class NumberedRationalFunction internal constructor( public override val numerator: NumberedPolynomial, public override val denominator: NumberedPolynomial -) : AbstractRationalFunction> { +) : RationalFunction> { override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } @@ -61,7 +61,7 @@ public class NumberedRationalFunction internal constructor( public class NumberedRationalFunctionSpace> ( public val ring: A, ) : - AbstractRationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionalSpaceOverPolynomialSpace< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index cfd21d552..612b00535 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -27,10 +27,10 @@ public fun interface Piecewise { * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no * "holes" in it. */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, Polynomial>> +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, ListPolynomial>> - override fun findPiece(arg: T): Polynomial? + override fun findPiece(arg: T): ListPolynomial? } /** @@ -38,11 +38,11 @@ public interface PiecewisePolynomial> : Piecewise> PiecewisePolynomial( - pieces: Collection, Polynomial>>, + pieces: Collection, ListPolynomial>>, ): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, Polynomial>> = pieces + override val pieces: Collection, ListPolynomial>> = pieces - override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second + override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second } /** @@ -50,10 +50,10 @@ public fun > PiecewisePolynomial( * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( - override val pieces: List, Polynomial>>, + override val pieces: List, ListPolynomial>>, ) : PiecewisePolynomial { - override fun findPiece(arg: T): Polynomial? { + override fun findPiece(arg: T): ListPolynomial? { val index = pieces.binarySearch { (range, _) -> when { arg >= range.endInclusive -> -1 @@ -74,7 +74,7 @@ private class OrderedPiecewisePolynomial>( */ public class PiecewiseBuilder>(delimiter: T) { private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() + private val pieces: MutableList> = arrayListOf() /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) @@ -82,7 +82,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putRight(right: T, piece: Polynomial) { + public fun putRight(right: T, piece: ListPolynomial) { require(right > delimiters.last()) { "New delimiter should be to the right of old one" } delimiters += right pieces += piece @@ -94,7 +94,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putLeft(left: T, piece: Polynomial) { + public fun putLeft(left: T, piece: ListPolynomial) { require(left < delimiters.first()) { "New delimiter should be to the left of old one" } delimiters.add(0, left) pieces.add(0, piece) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index d6c959fd1..b26a57a34 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 @@ -6,486 +6,384 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference +import kotlin.js.JsName import kotlin.jvm.JvmName -import kotlin.math.max -import kotlin.math.min + /** - * Polynomial model without fixation on specific context they are applied to. - * - * @param coefficients constant is the leftmost coefficient. + * Abstraction of polynomials. */ -public data class Polynomial( +public interface Polynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface PolynomialSpace> : Ring

{ /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not - * prohibited. + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ - public val coefficients: List -) : AbstractPolynomial { - override fun toString(): String = "Polynomial$coefficients" -} + public operator fun C.plus(other: Int): C + /** + * 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 operator fun C.minus(other: Int): C + /** + * 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 operator fun C.times(other: Int): C -/** - * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = - Polynomial(with(coefficients) { if (reverse) reversed() else this }) + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public operator fun Int.plus(other: C): C + /** + * 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 operator fun Int.minus(other: C): C + /** + * 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 operator fun Int.times(other: C): C -/** - * Returns a [Polynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = - Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) - -/** - * Space of univariate polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public open class PolynomialSpace>( - public override val ring: A, -) : AbstractPolynomialSpaceOverRing, A> { /** * Returns sum of the polynomial and the integer represented as polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public override operator fun Polynomial.plus(other: Int): Polynomial = - if (other == 0) this - else - Polynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } + other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + 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 override operator fun Polynomial.minus(other: Int): Polynomial = - if (other == 0) this - else - Polynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } - other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + 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 override operator fun Polynomial.times(other: Int): Polynomial = - if (other == 0) zero - else Polynomial( - coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this[deg] * other - } - ) + public operator fun P.times(other: Int): P = multiplyBySquaring(this, other) /** * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public override operator fun Int.plus(other: Polynomial): Polynomial = - if (this == 0) other - else - Polynomial( - other.coefficients - .toMutableList() - .apply { - val result = this@plus + getOrElse(0) { constantZero } - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + 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 override operator fun Int.minus(other: Polynomial): Polynomial = - if (this == 0) other - else - Polynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = this@minus - getOrElse(0) { constantZero } - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) + 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 override operator fun Int.times(other: Polynomial): Polynomial = - if (this == 0) zero - else Polynomial( - other.coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @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. + */ + public fun C.isZero(): Boolean = this == constantZero + /** + * Check if the instant is NOT zero constant. + */ + public fun C.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit constant. + */ + public fun C.isOne(): Boolean = this == constantOne + /** + * Check if the instant is NOT unit constant. + */ + public fun C.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit constant. + */ + public fun C.isMinusOne(): Boolean = this == -constantOne + /** + * Check if the instant is NOT minus unit constant. + */ + public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C /** * Returns sum of the constant represented as polynomial and the polynomial. */ - public override operator fun C.plus(other: Polynomial): Polynomial = - if (this.isZero()) other - else with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(this@plus)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun C.plus(other: P): P /** * Returns difference between the constant represented as polynomial and the polynomial. */ - public override operator fun C.minus(other: Polynomial): Polynomial = - if (this.isZero()) other - else with(other.coefficients) { - if (isEmpty()) Polynomial(listOf(this@minus)) - else Polynomial( - toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = if (size == 0) this@minus else this@minus - get(0) - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun C.minus(other: P): P /** * Returns product of the constant represented as polynomial and the polynomial. */ - public override operator fun C.times(other: Polynomial): Polynomial = - if (this.isZero()) other - else Polynomial( - other.coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + public operator fun C.times(other: P): P /** * Returns sum of the constant represented as polynomial and the polynomial. */ - public override operator fun Polynomial.plus(other: C): Polynomial = - if (other.isZero()) this - else with(coefficients) { - if (isEmpty()) Polynomial(listOf(other)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun P.plus(other: C): P /** * Returns difference between the constant represented as polynomial and the polynomial. */ - public override operator fun Polynomial.minus(other: C): Polynomial = - if (other.isZero()) this - else with(coefficients) { - if (isEmpty()) Polynomial(listOf(-other)) - else Polynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - val isResultZero = result.isZero() - - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } - } - ) - } + public operator fun P.minus(other: C): P /** * Returns product of the constant represented as polynomial and the polynomial. */ - public override operator fun Polynomial.times(other: C): Polynomial = - if (other.isZero()) this - else Polynomial( - coefficients - .applyAndRemoveZeros { - for (deg in indices) this[deg] = this[deg] * other - } - ) + public operator fun P.times(other: C): P + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ - public override operator fun Polynomial.unaryMinus(): Polynomial = - Polynomial(coefficients.map { -it }) + public override operator fun P.unaryMinus(): P /** * Returns sum of the polynomials. */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } + public override operator fun P.plus(other: P): P /** * Returns difference of the polynomials. */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } + public override operator fun P.minus(other: P): P /** * Returns product of the polynomials. */ - public override operator fun Polynomial.times(other: Polynomial): Polynomial { - val thisDegree = degree - val otherDegree = other.degree - return when { - thisDegree == -1 -> zero - otherDegree == -1 -> zero - else -> - Polynomial( - Coefficients(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } - } + 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. */ - public override fun Polynomial.isZero(): Boolean = coefficients.all { it.isZero() } + public fun P.isZero(): Boolean = this equalsTo zero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = !isZero() /** * Check if the instant is unit polynomial. */ - public override fun Polynomial.isOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } - } + public fun P.isOne(): Boolean = this equalsTo one + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = !isOne() /** * Check if the instant is minus unit polynomial. */ - public override fun Polynomial.isMinusOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } - } + public fun P.isMinusOne(): Boolean = this equalsTo -one + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: Polynomial = Polynomial(emptyList()) + public override val zero: P /** - * Instance of unit constant (unit of the underlying ring). + * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: Polynomial = Polynomial(listOf(constantOne)) + public override val one: P /** * Checks equality of the polynomials. */ - public override infix fun Polynomial.equalsTo(other: Polynomial): Boolean = - when { - this === other -> true - this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } - else -> false - } + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ - public override val Polynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } + public val P.degree: Int + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() /** * If polynomial is a constant polynomial represents and returns it as constant. * Otherwise, (when the polynomial is not constant polynomial) returns `null`. */ - public override fun Polynomial.asConstantOrNull(): C? = - with(coefficients) { - when { - isEmpty() -> constantZero - withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() - else -> null - } - } - - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.substitute(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.substitute(argument: Polynomial): Polynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun Polynomial.asFunctionOnPolynomials(): (Polynomial) -> Polynomial = { this.substitute(ring, it) } - + public fun P.asConstantOrNull(): C? /** - * Evaluates the polynomial for the given value [argument]. + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. */ - @Suppress("NOTHING_TO_INLINE") - public inline operator fun Polynomial.invoke(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline operator fun Polynomial.invoke(argument: Polynomial): Polynomial = this.substitute(ring, argument) + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - return this - } - internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = - toMutableList().applyAndRemoveZeros(block) - @Suppress("FunctionName") - internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { - val list = ArrayList(size) - repeat(size) { index -> list.add(init(index)) } - with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } - return list - } - @Suppress("FunctionName") - internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList(capacity) { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right } /** - * Space of polynomials constructed over ring. + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is + * provided [ring] (of type [A]), that provides constant-wise operations. * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ -public class ScalablePolynomialSpace( - ring: A, -) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(a.coefficients.map { scale(it, value) }) } -} +@Suppress("INAPPLICABLE_JVM_NAME") +public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + + public val ring: A + + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = ring { 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 { 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 { multiplyBySquaring(this@times, other) } + + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = ring { 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 { 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 { multiplyBySquaring(other, this@times) } + + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @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). + */ + public override val constantZero: C get() = ring.zero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = ring.one +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 51c1e2f80..635661b8a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -5,150 +5,1081 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.* +import kotlin.js.JsName +import kotlin.jvm.JvmName -public data class RationalFunction internal constructor ( - public override val numerator: Polynomial, - public override val denominator: Polynomial -) : AbstractRationalFunction> { - override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" +/** + * Abstraction of rational function. + */ +public interface RationalFunction> { + public val numerator: P + public val denominator: P + public operator fun component1(): P = numerator + public operator fun component2(): P = denominator } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +public interface RationalFunctionalSpace, R: RationalFunction> : Ring { + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public operator fun C.plus(other: Int): C + /** + * 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 operator fun C.minus(other: Int): C + /** + * 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 operator fun C.times(other: Int): C -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public operator fun Int.plus(other: C): C + /** + * 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 operator fun Int.minus(other: C): C + /** + * 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 operator fun Int.times(other: C): C -public class RationalFunctionSpace> ( - public val ring: A, -) : - AbstractRationalFunctionalSpaceOverPolynomialSpace< - C, - Polynomial, - RationalFunction, - PolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - Polynomial, - RationalFunction, - >() { + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P + /** + * Returns difference between the constant 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 + /** + * Returns product of the constant 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 - override val polynomialRing : PolynomialSpace = PolynomialSpace(ring) - override fun constructRationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = - RationalFunction(numerator, denominator) + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P + + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + 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 = 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 = multiplyBySquaring(this, other) + + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + 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 = 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 = multiplyBySquaring(other, this) + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + @JsName("constantUnaryPlus") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + @JsName("constantUnaryMinus") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + @JsName("constantPlus") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + @JsName("constantMinus") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @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. + */ + public fun C.isZero(): Boolean = this == constantZero + /** + * Check if the instant is NOT zero constant. + */ + public fun C.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit constant. + */ + public fun C.isOne(): Boolean = this == constantOne + /** + * Check if the instant is NOT unit constant. + */ + public fun C.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit constant. + */ + public fun C.isMinusOne(): Boolean = this == -constantOne + /** + * Check if the instant is NOT minus unit constant. + */ + public fun C.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + + /** + * Returns the same polynomial. + */ + public operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public operator fun P.minus(other: P): P + /** + * 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. + */ + public fun P.isZero(): Boolean = this equalsTo polynomialZero + /** + * Check if the instant is NOT zero polynomial. + */ + public fun P.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit polynomial. + */ + public fun P.isOne(): Boolean = this equalsTo polynomialOne + /** + * Check if the instant is NOT unit polynomial. + */ + public fun P.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit polynomial. + */ + public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne + /** + * Check if the instant is NOT minus unit polynomial. + */ + public fun P.isNotMinusOne(): Boolean = !isMinusOne() + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public val polynomialZero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public val polynomialOne: P + + /** + * Checks equality of the polynomials. + */ + public infix fun P.equalsTo(other: P): Boolean + /** + * Checks NOT equality of the polynomials. + */ + public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun C.plus(other: R): R + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public operator fun C.minus(other: R): R + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public operator fun C.times(other: R): R + + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public operator fun R.plus(other: C): R + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public operator fun R.minus(other: C): R + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public operator fun R.times(other: C): R + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun P.plus(other: R): R + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public operator fun P.minus(other: R): R + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.times(other: R): R + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public operator fun R.plus(other: P): R + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public operator fun R.minus(other: P): R + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public operator fun R.times(other: P): R + + /** + * Returns the same rational function. + */ + public override operator fun R.unaryPlus(): R = this + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): 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. + */ + public fun R.isZero(): Boolean = numerator equalsTo polynomialZero + /** + * Check if the instant is NOT zero rational function. + */ + public fun R.isNotZero(): Boolean = !isZero() + /** + * Check if the instant is unit rational function. + */ + public fun R.isOne(): Boolean = numerator equalsTo denominator + /** + * Check if the instant is NOT unit rational function. + */ + public fun R.isNotOne(): Boolean = !isOne() + /** + * Check if the instant is minus unit rational function. + */ + public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() + /** + * Check if the instant is NOT minus unit rational function. + */ + public fun R.isNotMinusOne(): Boolean = !isMinusOne() /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: RationalFunction = RationalFunction(polynomialZero, polynomialOne) + public override val zero: R /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: RationalFunction = RationalFunction(polynomialOne, polynomialOne) + public override val one: R - // TODO: Разобрать + /** + * Checks equality of the rational functions. + */ + public infix fun R.equalsTo(other: R): Boolean = + when { + this === other -> true + numerator.isZero() != other.numerator.isZero() -> false + numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false + else -> numerator * other.denominator equalsTo other.numerator * denominator + } + /** + * Checks NOT equality of the polynomials. + */ + public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - public operator fun RationalFunction.div(other: RationalFunction): RationalFunction = - RationalFunction( - numerator * other.denominator, - denominator * other.numerator + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isConstant(): Boolean = degree <= 0 + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotConstant(): Boolean = !isConstant() + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNonZeroConstant(): Boolean = degree == 0 + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public fun P.asConstantOrNull(): C? + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val R.numeratorDegree: Int get() = numerator.degree + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val R.denominatorDegree: Int get() = denominator.degree + + override fun add(left: R, right: R): R = left + right + override fun multiply(left: R, right: R): R = left * right +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [ring] (of type [A]), that provides constant-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { + + public val ring: A + + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = ring { 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 { 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 { multiplyBySquaring(this@times, other) } + + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = ring { 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 { 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 { multiplyBySquaring(other, this@times) } + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = ring.zero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = ring.one +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), that provides constant- and + * polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public interface RationalFunctionalSpaceOverPolynomialSpace< + C, + P: Polynomial, + R: RationalFunction, + AP: PolynomialSpace, + > : RationalFunctionalSpace { + + public val polynomialRing: AP + + /** + * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + 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 = polynomialRing { this@minus - 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 = polynomialRing { this@times * other } + + /** + * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } + /** + * 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 = polynomialRing { this@minus - other } + /** + * 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 = polynomialRing { this@times * other } + + /** + * Returns sum of the constant and the integer represented as polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant and the integer represented as polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant and the integer represented as polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } + + /** + * Returns sum of the integer represented as polynomial and the constant. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as polynomial and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as polynomial and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } + + /** + * Returns the same constant. + */ + @JvmName("constantUnaryPlus") + public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the constant. + */ + @JvmName("constantUnaryMinus") + public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("constantPlus") + public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("constantMinus") + public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("constantTimes") + public override operator fun C.times(other: C): C = polynomialRing { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("constantPower") + public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } + + /** + * Check if the instant is zero constant. + */ + public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero constant. + */ + public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit constant. + */ + public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit constant. + */ + public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit constant. + */ + public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit constant. + */ + public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = polynomialRing.constantZero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = polynomialRing.constantOne + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun C.times(other: P): P = polynomialRing { this@times * other } + + /** + * Returns sum of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as polynomial and the polynomial. + */ + public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as polynomial and the polynomial. + */ + public override operator fun P.times(other: C): P = polynomialRing { this@times * other } + + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomials. + */ + public override operator fun P.times(other: P): P = polynomialRing { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } + + /** + * Check if the instant is zero polynomial. + */ + public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } + /** + * Check if the instant is NOT zero polynomial. + */ + public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } + /** + * Check if the instant is unit polynomial. + */ + public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } + /** + * Check if the instant is NOT unit polynomial. + */ + public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } + /** + * Check if the instant is minus unit polynomial. + */ + public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } + /** + * Check if the instant is NOT minus unit polynomial. + */ + public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public override val polynomialZero: P get() = polynomialRing.zero + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public override val polynomialOne: P get() = polynomialRing.one + + /** + * Checks equality of the polynomials. + */ + public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } + /** + * Checks NOT equality of the polynomials. + */ + public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val P.degree: Int get() = polynomialRing { this@degree.degree } + + /** + * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } + /** + * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } + /** + * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } + /** + * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. + */ + public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) returns `null`. + */ + public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } + /** + * If polynomial is a constant polynomial represents and returns it as constant. + * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. + */ + public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } +} + +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type + * [C]. It also assumes that there is provided constructor + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ // TODO: Add support of field +@Suppress("INAPPLICABLE_JVM_NAME") +public abstract class PolynomialSpaceOfFractions< + C, + P: Polynomial, + R: RationalFunction, + > : RationalFunctionalSpace { + protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R + + /** + * Returns sum of the rational function and the integer represented as rational function. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun R.plus(other: Int): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * 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 override operator fun R.minus(other: Int): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * 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 override operator fun R.times(other: Int): R = + constructRationalFunction( + numerator * other, + denominator ) - public operator fun RationalFunction.div(other: Polynomial): RationalFunction = - RationalFunction( - numerator, - denominator * other + /** + * Returns sum of the integer represented as rational function and the rational function. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * 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 override operator fun Int.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator ) - public operator fun RationalFunction.div(other: C): RationalFunction = - RationalFunction( - numerator, - denominator * other + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun C.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the constant represented as polynomial and the rational function. + */ + public override operator fun C.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the constant represented as polynomial and the rational function. + */ + public override operator fun C.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator ) - public operator fun RationalFunction.div(other: Int): RationalFunction = - RationalFunction( - numerator, - denominator * other + /** + * Returns sum of the constant represented as rational function and the rational function. + */ + public override operator fun R.plus(other: C): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the constant represented as rational function and the rational function. + */ + public override operator fun R.minus(other: C): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the constant represented as rational function and the rational function. + */ + public override operator fun R.times(other: C): R = + constructRationalFunction( + numerator * other, + denominator ) -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun P.plus(other: R): R = + constructRationalFunction( + other.denominator * this + other.numerator, + other.denominator + ) + /** + * Returns difference between the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.minus(other: R): R = + constructRationalFunction( + other.denominator * this - other.numerator, + other.denominator + ) + /** + * Returns product of the polynomial represented as polynomial and the rational function. + */ + public override operator fun P.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + /** + * Returns sum of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.plus(other: P): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + /** + * Returns difference between the polynomial represented as rational function and the rational function. + */ + public override operator fun R.minus(other: P): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + /** + * Returns product of the polynomial represented as rational function and the rational function. + */ + public override operator fun R.times(other: P): R = + constructRationalFunction( + numerator * other, + denominator + ) + + /** + * Returns negation of the rational function. + */ + public override operator fun R.unaryMinus(): R = constructRationalFunction(-numerator, denominator) + /** + * Returns sum of the rational functions. + */ + public override operator fun R.plus(other: R): R = + constructRationalFunction( + numerator * other.denominator + denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns difference of the rational functions. + */ + public override operator fun R.minus(other: R): R = + constructRationalFunction( + numerator * other.denominator - denominator * other.numerator, + denominator * other.denominator + ) + /** + * Returns product of the rational functions. + */ + public override operator fun R.times(other: R): R = + constructRationalFunction( + numerator * other.numerator, + denominator * other.denominator + ) + + /** + * Instance of zero rational function (zero of the rational functions ring). + */ + public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) + + /** + * Instance of unit polynomial (unit of the rational functions ring). + */ + public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt index d79e8eda3..583160cf4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt @@ -17,7 +17,7 @@ public fun > A.labeledRationalFunction(): LabeledRationalFunction LabeledRationalFunctionSpace(this) /** - * Creates a [RationalFunctionSpace]'s scope over a received ring. + * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. */ public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt index afaf27a52..df5ba593a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt @@ -22,31 +22,31 @@ import kotlin.math.pow // if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero /** - * Creates a [PolynomialSpace] over a received ring. + * Creates a [ListPolynomialSpace] over a received ring. */ -public fun > A.polynomial(): PolynomialSpace = - PolynomialSpace(this) +public fun > A.listPolynomial(): ListPolynomialSpace = + ListPolynomialSpace(this) /** - * Creates a [PolynomialSpace]'s scope over a received ring. + * Creates a [ListPolynomialSpace]'s scope over a received ring. */ -public inline fun , R> A.polynomial(block: PolynomialSpace.() -> R): R { +public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() + return ListPolynomialSpace(this).block() } /** - * Creates a [ScalablePolynomialSpace] over a received scalable ring. + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. */ -public fun A.scalablePolynomial(): ScalablePolynomialSpace where A : Ring, A : ScaleOperations = - ScalablePolynomialSpace(this) +public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) /** - * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. */ -public inline fun A.scalablePolynomial(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { +public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalablePolynomialSpace(this).block() + return ScalableListPolynomialSpace(this).block() } @Suppress("NOTHING_TO_INLINE") @@ -99,7 +99,7 @@ internal inline fun multiplyAddingTo( /** * Evaluates the value of the given double polynomial for given double argument. */ -public fun Polynomial.substitute(arg: Double): Double = +public fun ListPolynomial.substitute(arg: Double): Double = coefficients.reduceIndexedOrNull { index, acc, c -> acc + c * arg.pow(index) } ?: .0 @@ -109,7 +109,7 @@ public fun Polynomial.substitute(arg: Double): Double = * * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). */ -public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { if (coefficients.isEmpty()) return@ring zero var result: C = coefficients.last() for (j in coefficients.size - 2 downTo 0) { @@ -118,11 +118,11 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { return result } -public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Polynomial = ring { - if (coefficients.isEmpty()) return Polynomial(emptyList()) +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) val thisDegree = coefficients.indexOfLast { it != zero } - if (thisDegree == -1) return Polynomial(emptyList()) + if (thisDegree == -1) return ListPolynomial(emptyList()) val argDegree = arg.coefficients.indexOfLast { it != zero } if (argDegree == -1) return coefficients[0].asPolynomial() val constantZero = zero @@ -145,27 +145,27 @@ public fun Polynomial.substitute(ring: Ring, arg: Polynomial) : Pol } with(resultCoefs) { while (isNotEmpty() && elementAt(lastIndex) == constantZero) removeAt(lastIndex) } - return Polynomial(resultCoefs) + return ListPolynomial(resultCoefs) } /** * Represent the polynomial as a regular context-less function. */ -public fun > Polynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } +public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent the polynomial as a regular context-less function. */ -public fun > Polynomial.asPolynomialFunctionOver(ring: A): (Polynomial) -> Polynomial = { substitute(ring, it) } +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.derivative( +public fun ListPolynomial.derivative( algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial( +): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { + ListPolynomial( buildList(max(0, coefficients.size - 1)) { for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) @@ -177,12 +177,12 @@ public fun Polynomial.derivative( * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.nthDerivative( +public fun ListPolynomial.nthDerivative( algebra: A, order: Int, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { +): ListPolynomial where A : Ring, A : NumericAlgebra = algebra { require(order >= 0) { "Order of derivative must be non-negative" } - Polynomial( + 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) }) @@ -195,10 +195,10 @@ public fun Polynomial.nthDerivative( * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.antiderivative( +public fun ListPolynomial.antiderivative( algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - Polynomial( +): ListPolynomial where A : Field, A : NumericAlgebra = algebra { + ListPolynomial( buildList(coefficients.size + 1) { add(zero) coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } @@ -211,12 +211,12 @@ public fun Polynomial.antiderivative( * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.nthAntiderivative( +public fun ListPolynomial.nthAntiderivative( algebra: A, order: Int, -): Polynomial where A : Field, A : NumericAlgebra = algebra { +): ListPolynomial where A : Field, A : NumericAlgebra = algebra { require(order >= 0) { "Order of antiderivative must be non-negative" } - Polynomial( + ListPolynomial( buildList(coefficients.size + order) { repeat(order) { add(zero) } coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } @@ -229,7 +229,7 @@ public fun Polynomial.nthAntiderivative( * Compute a definite integral of a given polynomial in a [range] */ @UnstableKMathAPI -public fun > Polynomial.integrate( +public fun > ListPolynomial.integrate( algebra: Field, range: ClosedRange, ): C = algebra { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt similarity index 88% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt index 8d2073834..151c7bb8d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/rationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt @@ -14,23 +14,23 @@ import kotlin.math.max /** - * Creates a [RationalFunctionSpace] over a received ring. + * Creates a [ListRationalFunctionSpace] over a received ring. */ -public fun > A.rationalFunction(): RationalFunctionSpace = - RationalFunctionSpace(this) +public fun > A.listRationalFunction(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) /** - * Creates a [RationalFunctionSpace]'s scope over a received ring. + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. */ -public inline fun , R> A.rationalFunction(block: RationalFunctionSpace.() -> R): R { +public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return RationalFunctionSpace(this).block() + return ListRationalFunctionSpace(this).block() } /** * Evaluates the value of the given double polynomial for given double argument. */ -public fun RationalFunction.substitute(arg: Double): Double = +public fun ListRationalFunction.substitute(arg: Double): Double = numerator.substitute(arg) / denominator.substitute(arg) /** @@ -38,7 +38,7 @@ public fun RationalFunction.substitute(arg: Double): Double = * * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). */ -public fun RationalFunction.substitute(ring: Field, arg: C): C = ring { +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { numerator.substitute(ring, arg) / denominator.substitute(ring, arg) } @@ -50,13 +50,13 @@ public fun RationalFunction.substitute(ring: Field, arg: C): C = ring * ``` * is returned. * - * Used in [Polynomial.substitute] and [RationalFunction.substitute] for performance optimisation. + * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать -internal fun Polynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: RationalFunction): Polynomial = ring { - if (coefficients.isEmpty()) return Polynomial(emptyList()) +internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { + if (coefficients.isEmpty()) return ListPolynomial(emptyList()) val thisDegree = coefficients.indexOfLast { it != zero } - if (thisDegree == -1) return Polynomial(emptyList()) + if (thisDegree == -1) return ListPolynomial(emptyList()) val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } @@ -189,7 +189,7 @@ internal fun Polynomial.substituteRationalFunctionTakeNumerator(ring: Rin return levelResultCoefs } - return Polynomial( + return ListPolynomial( processLevelEdged( level = thisDegreeLog2, start = 0, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt index cc725f981..5cd0679ab 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt @@ -17,7 +17,7 @@ public fun > A.numberedRationalFunction(): NumberedRationalFuncti NumberedRationalFunctionSpace(this) /** - * Creates a [RationalFunctionSpace]'s scope over a received ring. + * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. */ public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index 34d7bcf41..b55f16cf2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke @@ -32,7 +32,7 @@ public class LinearInterpolator>(override val algebra: Field>( val x02 = x0 * x0 val x03 = x02 * x0 //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = Polynomial( + val polynomial = ListPolynomial( a - b * x0 + c * x02 - d * x03, b - 2 * c * x0 + 3 * d * x02, c - 3 * d * x0, diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt new file mode 100644 index 000000000..0d2c4b5fc --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -0,0 +1,705 @@ +/* + * 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.test.misc.* +import kotlin.test.* + + +class ListPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(-2)) + 2, + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() + 0, + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(2)) - 2, + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() - 0, + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - 2, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * 27, + "test 1" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(7, 0, 49, 21, 14) * 15, + "test 2" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + 2 + ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + 0 + ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + 1 + ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + 2 + ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + -2 - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + 0 - ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + -1 - ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + -2 - ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() + Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(), + ListPolynomial() - Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * number(27), + "test 1" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(7, 0, 49, 21, 14) * number(15), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + Rational(2) + ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + Rational(0) + ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + Rational(1) + ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + Rational(2) + ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(), + Rational(-2) - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(), + Rational(0) - ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + Rational(-1) - ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + Rational(-2) - ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).listPolynomial { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.listPolynomial { + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.listPolynomial { + // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 + assertEquals( + ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 + assertEquals( + ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + + ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 + assertEquals( + ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.listPolynomial { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - + ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 + assertEquals( + ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - + ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - + ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).listPolynomial { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + ListPolynomial(1, 0, 1, 0, 1), + ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + ListPolynomial(), + ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), + "test 2" + ) + } + } + @Test + fun test_Polynomial_isZero() { + RationalField.listPolynomial { + assertTrue("test 1") { ListPolynomial().isZero() } + assertTrue("test 2") { ListPolynomial(Rational(0)).isZero() } + assertTrue("test 3") { ListPolynomial(Rational(0), Rational(0)).isZero() } + assertTrue("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) + .isZero() } + assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isZero() } + assertFalse("test 6") { ListPolynomial(Rational(3, 5), Rational(0)) + .isZero() } + assertFalse("test 7") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) + .isZero() } + } + } + @Test + fun test_Polynomial_isOne() { + RationalField.listPolynomial { + assertFalse("test 1") { ListPolynomial().isOne() } + assertFalse("test 2") { ListPolynomial(Rational(0)).isOne() } + assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isOne() } + assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) + .isOne() } + assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isOne() } + assertTrue("test 6") { ListPolynomial(Rational(5, 5)).isOne() } + assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isOne() } + assertTrue("test 8") { ListPolynomial(Rational(3, 3), Rational(0)).isOne() } + assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) + .isOne() } + assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, 5), Rational(0)) + .isOne() } + assertFalse("test 11") { ListPolynomial(Rational(1), Rational(3, 5), Rational(0)) + .isOne() } + assertFalse("test 12") { ListPolynomial(Rational(1), Rational(5, 5), Rational(0)) + .isOne() } + } + } + @Test + fun test_Polynomial_isMinusOne() { + RationalField.listPolynomial { + assertFalse("test 1") { ListPolynomial().isMinusOne() } + assertFalse("test 2") { ListPolynomial(Rational(0)).isMinusOne() } + assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isMinusOne() } + assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) + .isMinusOne() } + assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isMinusOne() } + assertTrue("test 6") { ListPolynomial(Rational(-5, 5)).isMinusOne() } + assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isMinusOne() } + assertTrue("test 8") { ListPolynomial(Rational(-3, 3), Rational(0)).isMinusOne() } + assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) + .isMinusOne() } + assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, -5), Rational(0)) + .isMinusOne() } + assertFalse("test 11") { ListPolynomial(Rational(-1), Rational(3, 5), Rational(0)) + .isMinusOne() } + assertFalse("test 12") { ListPolynomial(Rational(-1), Rational(5, -5), Rational(0)) + .isMinusOne() } + } + } + @Test + fun test_Polynomial_Polynomial_equalsTo() { + RationalField.listPolynomial { + assertTrue("test 1") { + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertTrue("test 2") { + ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertTrue("test 3") { + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)) + } + assertFalse("test 4") { + ListPolynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + } + assertFalse("test 5") { + ListPolynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo + ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) + } + assertFalse("test 6") { + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo + ListPolynomial(Rational(0), Rational(0), Rational(8, 7)) + } + } + } + @Test + fun test_Polynomial_degree() { + RationalField.listPolynomial { + assertEquals( + 2, + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, + "test 1" + ) + assertEquals( + -1, + ListPolynomial().degree, + "test 2" + ) + assertEquals( + -1, + ListPolynomial(Rational(0)).degree, + "test 3" + ) + assertEquals( + -1, + ListPolynomial(Rational(0), Rational(0)).degree, + "test 4" + ) + assertEquals( + -1, + ListPolynomial(Rational(0), Rational(0), Rational(0)).degree, + "test 5" + ) + assertEquals( + 0, + ListPolynomial(Rational(5, 9)).degree, + "test 6" + ) + assertEquals( + 0, + ListPolynomial(Rational(5, 9), Rational(0)).degree, + "test 7" + ) + assertEquals( + 0, + ListPolynomial(Rational(5, 9), Rational(0), Rational(0)).degree, + "test 8" + ) + assertEquals( + 2, + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, + "test 9" + ) + assertEquals( + 2, + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 10" + ) + assertEquals( + 2, + ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, + "test 11" + ) + } + } + @Test + fun test_Polynomial_asConstantOrNull() { + RationalField.listPolynomial { + assertEquals( + Rational(0), + ListPolynomial().asConstantOrNull(), + "test 1" + ) + assertEquals( + Rational(0), + ListPolynomial(Rational(0)).asConstantOrNull(), + "test 2" + ) + assertEquals( + Rational(0), + ListPolynomial(Rational(0), Rational(0)).asConstantOrNull(), + "test 3" + ) + assertEquals( + Rational(0), + ListPolynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), + "test 4" + ) + assertEquals( + Rational(-7, 9), + ListPolynomial(Rational(-7, 9)).asConstantOrNull(), + "test 5" + ) + assertEquals( + Rational(-7, 9), + ListPolynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 6" + ) + assertEquals( + Rational(-7, 9), + ListPolynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), + "test 7" + ) + assertEquals( + null, + ListPolynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 8" + ) + assertEquals( + null, + ListPolynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), + "test 9" + ) + assertEquals( + null, + ListPolynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 10" + ) + assertEquals( + null, + ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), + "test 11" + ) + assertEquals( + null, + ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)) + .asConstantOrNull(), + "test 12" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt new file mode 100644 index 000000000..bec46c034 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -0,0 +1,229 @@ +/* + * 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.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + + +class ListPolynomialUtilTest { + @Test + fun test_substitute_Double() { + val polynomial = ListPolynomial(1.0, -2.0, 1.0) + assertEquals(0.0, polynomial.substitute(1.0), 0.001) + } + @Test + fun test_substitute_Constant() { + assertEquals( + Rational(0), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + ListPolynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(89, 54)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), + "test 6" + ) + } + @Test + fun test_derivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthDerivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), + "test 9" + ) + } + @Test + fun test_antiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } + @Test + fun test_nthAntiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), + "test 1" + ) + assertFailsWith("test2") { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), + "test 9" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt deleted file mode 100644 index 141bdd436..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ /dev/null @@ -1,691 +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.test.misc.* -import kotlin.test.* - - -class PolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(-2)) + 2, - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() + 0, - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Polynomial(Rational(-2)) + 1, - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial() + 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(2)) - 2, - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() - 0, - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Polynomial(Rational(2)) - 1, - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Polynomial() - 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - Polynomial(22, 26, 13, 15, 26) * 27, - "test 1" - ) - assertEquals( - Polynomial(), - Polynomial(7, 0, 49, 21, 14) * 15, - "test 2" - ) - } - } - @Test - fun test_Int_Polynomial_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - -3 + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - 2 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - 2 + Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - 0 + Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - 1 + Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - 2 + Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - -2 - Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - 0 - Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - -1 - Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - -2 - Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - 27 * Polynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - Polynomial(), - 15 * Polynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Constant_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() + Rational(0), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Polynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - Polynomial(), - Polynomial() - Rational(0), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Polynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Polynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - Polynomial(22, 26, 13, 15, 26) * number(27), - "test 1" - ) - assertEquals( - Polynomial(), - Polynomial(7, 0, 49, 21, 14) * number(15), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - Rational(2) + Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - Rational(0) + Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(-1)), - Rational(1) + Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(2)), - Rational(2) + Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - Polynomial(), - Rational(-2) - Polynomial(Rational(-2)), - "test 3" - ) - assertEquals( - Polynomial(), - Rational(0) - Polynomial(), - "test 4" - ) - assertEquals( - Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - Polynomial(Rational(1)), - Rational(-1) - Polynomial(Rational(-2)), - "test 6" - ) - assertEquals( - Polynomial(Rational(-2)), - Rational(-2) - Polynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).polynomial { - assertEquals( - Polynomial(34, 2, 1, 20, 2), - 27 * Polynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - Polynomial(), - 15 * Polynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.polynomial { - assertEquals( - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Polynomial_plus() { - RationalField.polynomial { - // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 - assertEquals( - Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + - Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 - assertEquals( - Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), - Polynomial(Rational(-2, 9), Rational(-8, 3)) + - Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 - assertEquals( - Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), - Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + - Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 - assertEquals( - Polynomial(), - Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + - Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_minus() { - RationalField.polynomial { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - - Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 - assertEquals( - Polynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), - Polynomial(Rational(-2, 9), Rational(-8, 3)) - - Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)), - Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - - Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 - assertEquals( - Polynomial(), - Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - - Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).polynomial { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - Polynomial(1, 0, 1, 0, 1), - Polynomial(1, -1, 1) * Polynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - Polynomial(), - Polynomial(5, -25, 10) * Polynomial(21, 14, -7), - "test 2" - ) - } - } - @Test - fun test_Polynomial_isZero() { - RationalField.polynomial { - assertTrue("test 1") { Polynomial().isZero() } - assertTrue("test 2") { Polynomial(Rational(0)).isZero() } - assertTrue("test 3") { Polynomial(Rational(0), Rational(0)).isZero() } - assertTrue("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isZero() } - assertFalse("test 5") { Polynomial(Rational(3, 5)).isZero() } - assertFalse("test 6") { Polynomial(Rational(3, 5), Rational(0)).isZero() } - assertFalse("test 7") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isZero() } - } - } - @Test - fun test_Polynomial_isOne() { - RationalField.polynomial { - assertFalse("test 1") { Polynomial().isOne() } - assertFalse("test 2") { Polynomial(Rational(0)).isOne() } - assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isOne() } - assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isOne() } - assertFalse("test 5") { Polynomial(Rational(3, 5)).isOne() } - assertTrue("test 6") { Polynomial(Rational(5, 5)).isOne() } - assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isOne() } - assertTrue("test 8") { Polynomial(Rational(3, 3), Rational(0)).isOne() } - assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isOne() } - assertFalse("test 10") { Polynomial(Rational(0), Rational(5, 5), Rational(0)).isOne() } - assertFalse("test 11") { Polynomial(Rational(1), Rational(3, 5), Rational(0)).isOne() } - assertFalse("test 12") { Polynomial(Rational(1), Rational(5, 5), Rational(0)).isOne() } - } - } - @Test - fun test_Polynomial_isMinusOne() { - RationalField.polynomial { - assertFalse("test 1") { Polynomial().isMinusOne() } - assertFalse("test 2") { Polynomial(Rational(0)).isMinusOne() } - assertFalse("test 3") { Polynomial(Rational(0), Rational(0)).isMinusOne() } - assertFalse("test 4") { Polynomial(Rational(0), Rational(0), Rational(0)).isMinusOne() } - assertFalse("test 5") { Polynomial(Rational(3, 5)).isMinusOne() } - assertTrue("test 6") { Polynomial(Rational(-5, 5)).isMinusOne() } - assertFalse("test 7") { Polynomial(Rational(3, 5), Rational(0)).isMinusOne() } - assertTrue("test 8") { Polynomial(Rational(-3, 3), Rational(0)).isMinusOne() } - assertFalse("test 9") { Polynomial(Rational(0), Rational(3, 5), Rational(0)).isMinusOne() } - assertFalse("test 10") { Polynomial(Rational(0), Rational(5, -5), Rational(0)).isMinusOne() } - assertFalse("test 11") { Polynomial(Rational(-1), Rational(3, 5), Rational(0)).isMinusOne() } - assertFalse("test 12") { Polynomial(Rational(-1), Rational(5, -5), Rational(0)).isMinusOne() } - } - } - @Test - fun test_Polynomial_equalsTo() { - RationalField.polynomial { - assertTrue("test 1") { - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertTrue("test 2") { - Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertTrue("test 3") { - Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - Polynomial(Rational(0), Rational(0), Rational(-8, 7)) - } - assertFalse("test 4") { - Polynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertFalse("test 5") { - Polynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo - Polynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertFalse("test 6") { - Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - Polynomial(Rational(0), Rational(0), Rational(8, 7)) - } - } - } - @Test - fun test_Polynomial_degree() { - RationalField.polynomial { - assertEquals( - 2, - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, - "test 1" - ) - assertEquals( - -1, - Polynomial().degree, - "test 2" - ) - assertEquals( - -1, - Polynomial(Rational(0)).degree, - "test 3" - ) - assertEquals( - -1, - Polynomial(Rational(0), Rational(0)).degree, - "test 4" - ) - assertEquals( - -1, - Polynomial(Rational(0), Rational(0), Rational(0)).degree, - "test 5" - ) - assertEquals( - 0, - Polynomial(Rational(5, 9)).degree, - "test 6" - ) - assertEquals( - 0, - Polynomial(Rational(5, 9), Rational(0)).degree, - "test 7" - ) - assertEquals( - 0, - Polynomial(Rational(5, 9), Rational(0), Rational(0)).degree, - "test 8" - ) - assertEquals( - 2, - Polynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, - "test 9" - ) - assertEquals( - 2, - Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 10" - ) - assertEquals( - 2, - Polynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 11" - ) - } - } - @Test - fun test_Polynomial_asConstantOrNull() { - RationalField.polynomial { - assertEquals( - Rational(0), - Polynomial().asConstantOrNull(), - "test 1" - ) - assertEquals( - Rational(0), - Polynomial(Rational(0)).asConstantOrNull(), - "test 2" - ) - assertEquals( - Rational(0), - Polynomial(Rational(0), Rational(0)).asConstantOrNull(), - "test 3" - ) - assertEquals( - Rational(0), - Polynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), - "test 4" - ) - assertEquals( - Rational(-7, 9), - Polynomial(Rational(-7, 9)).asConstantOrNull(), - "test 5" - ) - assertEquals( - Rational(-7, 9), - Polynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 6" - ) - assertEquals( - Rational(-7, 9), - Polynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), - "test 7" - ) - assertEquals( - null, - Polynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 8" - ) - assertEquals( - null, - Polynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 9" - ) - assertEquals( - null, - Polynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 10" - ) - assertEquals( - null, - Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 11" - ) - assertEquals( - null, - Polynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 12" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt deleted file mode 100644 index 21c5436d3..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ /dev/null @@ -1,229 +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.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - - -class PolynomialUtilTest { - @Test - fun test_substitute_Double() { - val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.substitute(1.0), 0.001) - } - @Test - fun test_substitute_Constant() { - assertEquals( - Rational(0), - Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - Polynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - Polynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_substitute_Polynomial() { - assertEquals( - Polynomial(), - Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Polynomial(Rational(1))), - "test 1" - ) - assertEquals( - Polynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - Polynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - Polynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), - Polynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - Polynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - Polynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - Polynomial(Rational(89, 54)), - Polynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, Polynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - fun test_derivative() { - assertEquals( - Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), - "test 1" - ) - assertEquals( - Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 2" - ) - assertEquals( - Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 3" - ) - assertEquals( - Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthDerivative() { - assertEquals( - Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - Polynomial(Rational(1), Rational(-2), Rational(1)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - Polynomial(Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - Polynomial(), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - Polynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - Polynomial(Rational(8, 9), Rational(30, 7)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test - fun test_antiderivative() { - assertEquals( - Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), - "test 1" - ) - assertEquals( - Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 2" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 3" - ) - assertEquals( - Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthAntiderivative() { - assertEquals( - Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) - } - assertEquals( - Polynomial(Rational(1), Rational(-2), Rational(1)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), - "test 3" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), - "test 4" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), - "test 5" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), - Polynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), - "test 6" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 7" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 8" - ) - assertEquals( - Polynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), - "test 9" - ) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index afeba0be4..aae0ad017 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.integrate import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField @@ -19,7 +19,7 @@ class SplineIntegralTest { @Test fun integratePolynomial(){ - val polynomial = Polynomial(1.0, 2.0, 3.0) + val polynomial = ListPolynomial(1.0, 2.0, 3.0) val integral = polynomial.integrate(DoubleField,1.0..2.0) assertEquals(11.0, integral, 0.001) } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index a8a8a09bc..535a42846 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.test.misc -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.PolynomialSpace +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -134,9 +134,9 @@ class IntModuloRing : Ring { inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg } -fun PolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) +fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) -fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = - Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = - Polynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file From 98b9a708937213eda5160805638e9d851869c7cc Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 02:37:26 +0300 Subject: [PATCH 047/174] Enhanced tests of Double substitution. --- .../kmath/functions/ListPolynomialUtilTest.kt | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index bec46c034..50ae18260 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -15,8 +15,36 @@ import kotlin.test.assertFailsWith class ListPolynomialUtilTest { @Test fun test_substitute_Double() { - val polynomial = ListPolynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.substitute(1.0), 0.001) + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 1.1931904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 2" + ) + assertEquals( + 0.5681904761904762, + ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 3" + ) + assertEquals( + 1.1811904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + 0.001, + "test 4" + ) + assertEquals( + 1.1703333333333332, + ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + 0.001, + "test 5" + ) } @Test fun test_substitute_Constant() { From 09868f090b7507ae9ecb8ad17cc5dad75899c5b3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 02:39:43 +0300 Subject: [PATCH 048/174] Enhanced tests of Double substitution. --- .../kmath/functions/LabeledPolynomial.kt | 10 +++++- .../kmath/functions/ListPolynomial.kt | 12 ++++++- .../kmath/functions/NumberedPolynomial.kt | 10 +++++- .../kscience/kmath/functions/Polynomial.kt | 10 ++++++ .../kmath/functions/RationalFunction.kt | 31 +++++++++++++++++-- 5 files changed, 67 insertions(+), 6 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 968f77b20..3b4971d9c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -6,7 +6,8 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference @@ -269,6 +270,13 @@ public class LabeledPolynomialSpace>( } ) + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): LabeledPolynomial = + if (value == 0) zero + else LabeledPolynomial(mapOf(emptyMap() to constantNumber(value))) + public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index b97c1e0b4..f886ca19f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -5,7 +5,9 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference @@ -13,6 +15,7 @@ import kotlin.jvm.JvmName import kotlin.math.max import kotlin.math.min + /** * Polynomial model without fixation on specific context they are applied to. * @@ -193,6 +196,13 @@ public open class ListPolynomialSpace>( } ) + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): ListPolynomial = + if (value == 0) zero + else ListPolynomial(constantNumber(value)) + /** * Returns sum of the constant represented as polynomial and the polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 3b9b907b7..387b6841d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.experimental.ExperimentalTypeInference @@ -221,6 +222,13 @@ public open class NumberedPolynomialSpace>( } ) + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): NumberedPolynomial = + if (value == 0) zero + else NumberedPolynomial(mapOf(emptyList() to constantNumber(value))) + /** * Returns sum of the constant represented as polynomial and the polynomial. */ 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 b26a57a34..dc46c868a 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 @@ -61,6 +61,11 @@ public interface PolynomialSpace> : Ring

{ */ public operator fun Int.times(other: C): C + /** + * Converts the integer [value] to constant. + */ + public fun constantNumber(value: Int): C = constantOne * value + /** * Returns sum of the polynomial and the integer represented as polynomial. * @@ -99,6 +104,11 @@ public interface PolynomialSpace> : Ring

{ */ public operator fun Int.times(other: P): P = multiplyBySquaring(other, this) + /** + * Converts the integer [value] to polynomial. + */ + public fun number(value: Int): P = one * value + /** * Returns the same constant. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 635661b8a..724d88963 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -68,6 +68,11 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun Int.times(other: C): C + /** + * Converts the integer [value] to constant. + */ + public fun constantNumber(value: Int): C = constantOne * value + /** * Returns sum of the constant and the integer represented as polynomial. * @@ -106,6 +111,11 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun Int.times(other: P): P + /** + * Converts the integer [value] to polynomial. + */ + public fun polynomialNumber(value: Int): P = polynomialOne * value + /** * Returns sum of the rational function and the integer represented as rational function. * @@ -144,6 +154,11 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) + /** + * Converts the integer [value] to rational function. + */ + public fun number(value: Int): R = one * value + /** * Returns the same constant. */ @@ -672,6 +687,11 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } + /** + * Converts the integer [value] to polynomial. + */ + public override fun polynomialNumber(value: Int): P = polynomialRing { number(value) } + /** * Returns the same constant. */ @@ -880,7 +900,7 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { - protected abstract fun constructRationalFunction(numerator: P, denominator: P) : R + protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** * Returns sum of the rational function and the integer represented as rational function. @@ -944,6 +964,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + /** + * Converts the integer [value] to rational function. + */ + public override fun number(value: Int): R = constructRationalFunction(polynomialNumber(value)) + /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -1076,10 +1101,10 @@ public abstract class PolynomialSpaceOfFractions< /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: R get() = constructRationalFunction(polynomialZero, polynomialOne) + public override val zero: R get() = constructRationalFunction(polynomialZero) /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: R get() = constructRationalFunction(polynomialOne, polynomialOne) + public override val one: R get() = constructRationalFunction(polynomialOne) } \ No newline at end of file From 2f9e5043577d798f1330c20da497bb44eb66c617 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 13:58:29 +0300 Subject: [PATCH 049/174] Added division to RFs' Spaces. Added conversion to polynomial and RFs' spaces. Added requirements for RFs' denominators' changes for case of non-integral domain. Added requirements for non-zero divisor to RFs' divisions. --- .../kmath/functions/LabeledPolynomial.kt | 11 +- .../functions/LabeledRationalFunction.kt | 18 -- .../kmath/functions/ListPolynomial.kt | 13 +- .../kmath/functions/ListRationalFunction.kt | 24 -- .../kmath/functions/NumberedPolynomial.kt | 11 +- .../kscience/kmath/functions/Polynomial.kt | 17 ++ .../kmath/functions/RationalFunction.kt | 217 +++++++++++++++++- 7 files changed, 250 insertions(+), 61 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 3b4971d9c..e0b92a712 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -273,9 +273,7 @@ public class LabeledPolynomialSpace>( /** * Converts the integer [value] to polynomial. */ - public override fun number(value: Int): LabeledPolynomial = - if (value == 0) zero - else LabeledPolynomial(mapOf(emptyMap() to constantNumber(value))) + public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) public operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( @@ -425,6 +423,13 @@ public class LabeledPolynomialSpace>( } ) + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): LabeledPolynomial = + if (value == 0) zero + else LabeledPolynomial(mapOf(emptyMap() to value)) + public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index f347f9191..735e04a48 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -144,24 +144,6 @@ public class LabeledRationalFunctionSpace>( // TODO: Разобрать - public operator fun LabeledRationalFunction.div(other: LabeledRationalFunction): LabeledRationalFunction = - LabeledRationalFunction( - numerator * other.denominator, - denominator * other.numerator - ) - - public operator fun LabeledRationalFunction.div(other: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction( - numerator, - denominator * other - ) - - public operator fun LabeledRationalFunction.div(other: C): LabeledRationalFunction = - LabeledRationalFunction( - numerator, - denominator * other - ) - // operator fun invoke(arg: Map): LabeledRationalFunction = // LabeledRationalFunction( // numerator(arg), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index f886ca19f..90e9cde69 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -66,7 +66,7 @@ public fun ListPolynomial(coefficients: List, reverse: Boolean = false): public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) -public fun C.asPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) /** * Space of univariate polynomials constructed over ring. @@ -199,9 +199,7 @@ public open class ListPolynomialSpace>( /** * Converts the integer [value] to polynomial. */ - public override fun number(value: Int): ListPolynomial = - if (value == 0) zero - else ListPolynomial(constantNumber(value)) + public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) /** * Returns sum of the constant represented as polynomial and the polynomial. @@ -313,6 +311,13 @@ public open class ListPolynomialSpace>( } ) + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): ListPolynomial = + if (value.isZero()) zero + else ListPolynomial(value) + /** * Returns negation of the polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 50ddd3118..8bd925c46 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -70,30 +70,6 @@ public class ListRationalFunctionSpace> ( // TODO: Разобрать - public operator fun ListRationalFunction.div(other: ListRationalFunction): ListRationalFunction = - ListRationalFunction( - numerator * other.denominator, - denominator * other.numerator - ) - - public operator fun ListRationalFunction.div(other: ListPolynomial): ListRationalFunction = - ListRationalFunction( - numerator, - denominator * other - ) - - public operator fun ListRationalFunction.div(other: C): ListRationalFunction = - ListRationalFunction( - numerator, - denominator * other - ) - - public operator fun ListRationalFunction.div(other: Int): ListRationalFunction = - ListRationalFunction( - numerator, - denominator * other - ) - // operator fun invoke(arg: UnivariatePolynomial): RationalFunction = // RationalFunction( // numerator(arg), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 387b6841d..1f37a1c2b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -225,9 +225,7 @@ public open class NumberedPolynomialSpace>( /** * Converts the integer [value] to polynomial. */ - public override fun number(value: Int): NumberedPolynomial = - if (value == 0) zero - else NumberedPolynomial(mapOf(emptyList() to constantNumber(value))) + public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) /** * Returns sum of the constant represented as polynomial and the polynomial. @@ -331,6 +329,13 @@ public open class NumberedPolynomialSpace>( } ) + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): NumberedPolynomial = + if (value == 0) zero + else NumberedPolynomial(mapOf(emptyList() to value)) + /** * Returns negation of the polynomial. */ 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 dc46c868a..f8d7d5a36 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 @@ -65,6 +65,10 @@ public interface PolynomialSpace> : Ring

{ * Converts the integer [value] to constant. */ public fun constantNumber(value: Int): C = constantOne * value + /** + * Converts the integer to constant. + */ + public fun Int.asConstant(): C = constantNumber(this) /** * Returns sum of the polynomial and the integer represented as polynomial. @@ -108,6 +112,10 @@ public interface PolynomialSpace> : Ring

{ * Converts the integer [value] to polynomial. */ public fun number(value: Int): P = one * value + /** + * Converts the integer to polynomial. + */ + public fun Int.asPolynomial(): P = number(this) /** * Returns the same constant. @@ -206,6 +214,15 @@ public interface PolynomialSpace> : Ring

{ */ public operator fun P.times(other: C): P + /** + * Converts the constant [value] to polynomial. + */ + public fun number(value: C): P = one * value + /** + * Converts the constant to polynomial. + */ + public fun C.asPolynomial(): P = number(this) + /** * Returns the same polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 724d88963..90e3bdbb1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -72,6 +72,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Converts the integer [value] to constant. */ public fun constantNumber(value: Int): C = constantOne * value + /** + * Converts the integer to constant. + */ + public fun Int.asConstant(): C = constantNumber(this) /** * Returns sum of the constant and the integer represented as polynomial. @@ -115,6 +119,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Converts the integer [value] to polynomial. */ public fun polynomialNumber(value: Int): P = polynomialOne * value + /** + * Converts the integer to polynomial. + */ + public fun Int.asPolynomial(): P = polynomialNumber(this) /** * Returns sum of the rational function and the integer represented as rational function. @@ -134,6 +142,13 @@ public interface RationalFunctionalSpace, R: RationalFunctio * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyBySquaring(this, other) + /** + * Returns quotient of the rational function and the integer represented as rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ + public operator fun R.div(other: Int): R = this / multiplyBySquaring(one, other) /** * Returns sum of the integer represented as rational function and the rational function. @@ -153,11 +168,22 @@ public interface RationalFunctionalSpace, R: RationalFunctio * The operation is equivalent to sum of [this] copies of [other]. */ public operator fun Int.times(other: R): R = multiplyBySquaring(other, this) + /** + * Returns quotient of the integer represented as rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ + public operator fun Int.div(other: R): R = multiplyBySquaring(one / other, this) /** * Converts the integer [value] to rational function. */ public fun number(value: Int): R = one * value + /** + * Converts the integer to rational function. + */ + public fun Int.asRationalFunction(): R = number(this) /** * Returns the same constant. @@ -256,6 +282,15 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public operator fun P.times(other: C): P + /** + * Converts the constant [value] to polynomial. + */ + public fun polynomialNumber(value: C): P = polynomialOne * value + /** + * Converts the constant to polynomial. + */ + public fun C.asPolynomial(): P = polynomialNumber(this) + /** * Returns the same polynomial. */ @@ -276,6 +311,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the polynomials. */ public operator fun P.times(other: P): P + /** + * Returns quotient of the polynomials as rational function. + */ + public operator fun P.div(other: P): R /** * Raises [arg] to the integer power [exponent]. */ @@ -336,19 +375,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the constant represented as polynomial and the rational function. */ public operator fun C.times(other: R): R + /** + * Returns quotient of the constant represented as polynomial and the rational function. + */ + public operator fun C.div(other: R): R /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the rational function and the constant represented as rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the rational function and the constant represented as rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the rational function and the constant represented as rational function. */ public operator fun R.times(other: C): R + /** + * Returns quotient of the rational function and the constant represented as rational function. + */ + public operator fun R.div(other: C): R + + /** + * Converts the constant [value] to rational function. + */ + public fun number(value: C): R = one * value + /** + * Converts the constant to rational function. + */ + public fun C.asRationalFunction(): R = number(this) /** * Returns sum of the polynomial represented as rational function and the rational function. @@ -362,19 +418,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the polynomial represented as polynomial and the rational function. */ public operator fun P.times(other: R): R + /** + * Returns quotient of the polynomial represented as polynomial and the rational function. + */ + public operator fun P.div(other: R): R /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the rational function and the polynomial represented as rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the rational function and the polynomial represented as rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the rational function and the polynomial represented as rational function. */ public operator fun R.times(other: P): R + /** + * Returns quotient of the rational function and the polynomial represented as rational function. + */ + public operator fun R.div(other: P): R + + /** + * Converts the polynomial [value] to rational function. + */ + public fun number(value: P): R = one * value + /** + * Converts the polynomial to rational function. + */ + public fun P.asRationalFunction(): R = number(this) /** * Returns the same rational function. @@ -396,6 +469,10 @@ public interface RationalFunctionalSpace, R: RationalFunctio * Returns product of the rational functions. */ public override operator fun R.times(other: R): R + /** + * Returns quotient of the rational functions. + */ + public operator fun R.div(other: R): R /** * Raises [arg] to the integer power [exponent]. */ @@ -649,6 +726,15 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } + /** + * Converts the integer [value] to constant. + */ + public override fun constantNumber(value: Int): C = polynomialRing { constantNumber(value) } + /** + * Converts the integer to constant. + */ + override fun Int.asConstant(): C = polynomialRing { asConstant() } + /** * Returns sum of the constant and the integer represented as polynomial. * @@ -691,6 +777,10 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< * Converts the integer [value] to polynomial. */ public override fun polynomialNumber(value: Int): P = polynomialRing { number(value) } + /** + * Converts the integer to polynomial. + */ + public override fun Int.asPolynomial(): P = polynomialRing { asPolynomial() } /** * Returns the same constant. @@ -783,6 +873,15 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override operator fun P.times(other: C): P = polynomialRing { this@times * other } + /** + * Converts the constant [value] to polynomial. + */ + public override fun polynomialNumber(value: C): P = polynomialRing { number(value) } + /** + * Converts the constant to polynomial. + */ + public override fun C.asPolynomial(): P = polynomialRing { asPolynomial() } + /** * Returns the same polynomial. */ @@ -933,6 +1032,19 @@ public abstract class PolynomialSpaceOfFractions< denominator ) + public override operator fun R.div(other: Int): R { + val otherAsConstant = constantNumber(other) + require(otherAsConstant.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator, + (denominator * other).also { + check(it.isNotZero()) { + "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + /** * Returns sum of the integer represented as rational function and the rational function. * @@ -964,11 +1076,24 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + public override operator fun Int.div(other: R): R { + require(other.numerator.isNotZero()) { "/ by zero." } + return constructRationalFunction( + this * other.denominator, + other.numerator + ) + } + /** * Converts the integer [value] to rational function. */ public override fun number(value: Int): R = constructRationalFunction(polynomialNumber(value)) + /** + * Returns quotient of the polynomials as rational function. + */ + public override operator fun P.div(other: P): R = constructRationalFunction(this, other) + /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -994,6 +1119,14 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + public override operator fun C.div(other: R): R { + require(other.numerator.isNotZero()) { "/ by zero." } + return constructRationalFunction( + this * other.denominator, + other.numerator + ) + } + /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -1019,6 +1152,23 @@ public abstract class PolynomialSpaceOfFractions< denominator ) + public override operator fun R.div(other: C): R { + require(other.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator, + (denominator * other).also { + check(it.isNotZero()) { + "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + + /** + * Converts the constant [value] to rational function. + */ + public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) + /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -1044,6 +1194,14 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) + public override operator fun P.div(other: R): R { + require(other.numerator.isNotZero()) { "/ by zero." } + return constructRationalFunction( + this * other.denominator, + other.numerator + ) + } + /** * Returns sum of the polynomial represented as rational function and the rational function. */ @@ -1069,6 +1227,23 @@ public abstract class PolynomialSpaceOfFractions< denominator ) + public override operator fun R.div(other: P): R { + require(other.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator, + (denominator * other).also { + require(it.isNotZero()) { + "Got zero denominator during division of rational functions to polynomial. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + + /** + * Converts the polynomial [value] to rational function. + */ + public override fun number(value: P): R = constructRationalFunction(value) + /** * Returns negation of the rational function. */ @@ -1079,7 +1254,11 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.plus(other: R): R = constructRationalFunction( numerator * other.denominator + denominator * other.numerator, - denominator * other.denominator + (denominator * other.denominator).also { + check(it.isNotZero()) { + "Got zero denominator during addition of rational functions. It means underlying ring of polynomials is not integral domain." + } + } ) /** * Returns difference of the rational functions. @@ -1087,7 +1266,11 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.minus(other: R): R = constructRationalFunction( numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator + (denominator * other.denominator).also { + check(it.isNotZero()) { + "Got zero denominator during subtraction of rational functions. It means underlying ring of polynomials is not integral domain." + } + } ) /** * Returns product of the rational functions. @@ -1095,9 +1278,25 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.times(other: R): R = constructRationalFunction( numerator * other.numerator, - denominator * other.denominator + (denominator * other.denominator).also { + check(it.isNotZero()) { + "Got zero denominator during multiplication of rational functions. It means underlying ring of polynomials is not integral domain." + } + } ) + public override operator fun R.div(other: R): R { + require(other.isNotZero()) { "/ by zero." } + return constructRationalFunction( + numerator * other.denominator, + (denominator * other.numerator).also { + check(it.isNotZero()) { + "Got zero denominator during division of rational functions. It means underlying ring of polynomials is not integral domain." + } + } + ) + } + /** * Instance of zero rational function (zero of the rational functions ring). */ From 39ce855075662461892ff70f2c52c630d9e70d66 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 14:25:09 +0300 Subject: [PATCH 050/174] Added constructors for RFs' spaces --- .../functions/LabeledRationalFunction.kt | 82 +++++++------- .../kmath/functions/ListRationalFunction.kt | 62 +++++++---- .../functions/NumberedRationalFunction.kt | 100 ++++++++---------- 3 files changed, 122 insertions(+), 122 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 735e04a48..599660b52 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -19,48 +19,46 @@ public class LabeledRationalFunction( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) - -// TODO: Rewrite former constructors as fabrics -//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( -//LabeledPolynomial(numeratorCoefficients), -//LabeledPolynomial(denominatorCoefficients) -//) -// -//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( -//LabeledPolynomial(numeratorCoefficients), -//LabeledPolynomial(denominatorCoefficients) -//) -// -//constructor(numerator: LabeledPolynomial) : this(numerator, numerator.getOne()) -//constructor(numeratorCoefficients: Map, C>) : this( -//LabeledPolynomial(numeratorCoefficients) -//) -// -//constructor(numeratorCoefficients: Collection, C>>) : this( -//LabeledPolynomial(numeratorCoefficients) -//) +@Suppress("FunctionName") +internal fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = + if (denominator.isZero()) throw ArithmeticException("/ by zero") + else LabeledRationalFunction(numerator, denominator) +@Suppress("FunctionName") +internal fun > A.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = + if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else LabeledRationalFunction(numerator, denominator) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(mapOf(emptyMap() to one)) + ) public class LabeledRationalFunctionSpace>( public val ring: A, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 8bd925c46..67c7e9fa2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -17,28 +17,46 @@ public data class ListRationalFunction internal constructor ( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) +@Suppress("FunctionName") +internal fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = + if (denominator.isZero()) throw ArithmeticException("/ by zero") + else ListRationalFunction(numerator, denominator) +@Suppress("FunctionName") +internal fun > A.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = + if (denominator.coefficients.all { it == zero }) throw ArithmeticException("/ by zero") + else ListRationalFunction(numerator, denominator) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") + else ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") + else ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) public class ListRationalFunctionSpace> ( public val ring: A, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index f3b90b5c5..b32f01f2a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.math.max @@ -18,45 +19,46 @@ public class NumberedRationalFunction internal constructor( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//internal fun > RationalFunction(numerator: Polynomial, denominator: Polynomial): RationalFunction = -// if (denominator.isZero()) throw ArithmeticException("/ by zero") -// else RationalFunction(numerator, denominator) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), -// Polynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ).also { if (it.isZero()) } -// ) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numerator: Polynomial): RationalFunction = -// RationalFunction(numerator, onePolynomial) -//context(RationalFunctionSpace) -//@Suppress("FunctionName") -//public fun > RationalFunction(numeratorCoefficients: List, reverse: Boolean = false): RationalFunction = -// RationalFunction( -// Polynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ) -// ) - -// TODO: Rewrite former constructors as fabrics -//constructor(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>) : this( -//Polynomial(numeratorCoefficients), -//Polynomial(denominatorCoefficients) -//) -//constructor(numeratorCoefficients: Collection, C>>, denominatorCoefficients: Collection, C>>) : this( -//Polynomial(numeratorCoefficients), -//Polynomial(denominatorCoefficients) -//) -//constructor(numerator: Polynomial) : this(numerator, numerator.getOne()) -//constructor(numeratorCoefficients: Map, C>) : this( -//Polynomial(numeratorCoefficients) -//) -//constructor(numeratorCoefficients: Collection, C>>) : this( -//Polynomial(numeratorCoefficients) -//) +@Suppress("FunctionName") +internal fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = + if (denominator.isZero()) throw ArithmeticException("/ by zero") + else NumberedRationalFunction(numerator, denominator) +@Suppress("FunctionName") +internal fun > A.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = + if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else NumberedRationalFunction(numerator, denominator) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") + else NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(mapOf(emptyList() to one)) + ) public class NumberedRationalFunctionSpace> ( public val ring: A, @@ -156,24 +158,6 @@ public class NumberedRationalFunctionSpace> ( // TODO: Разобрать - public operator fun NumberedRationalFunction.div(other: NumberedRationalFunction): NumberedRationalFunction = - NumberedRationalFunction( - numerator * other.denominator, - denominator * other.numerator - ) - - public operator fun NumberedRationalFunction.div(other: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction( - numerator, - denominator * other - ) - - public operator fun NumberedRationalFunction.div(other: C): NumberedRationalFunction = - NumberedRationalFunction( - numerator, - denominator * other - ) - // operator fun invoke(arg: Map): NumberedRationalFunction = // NumberedRationalFunction( // numerator(arg), From b44c99c265d0d8a43679c694135585047a489813 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:28:34 +0300 Subject: [PATCH 051/174] Added multivariate abstractions. --- .../kmath/functions/LabeledPolynomial.kt | 68 +++--- .../functions/LabeledRationalFunction.kt | 33 +-- .../kscience/kmath/functions/Polynomial.kt | 60 +++++- .../kmath/functions/RationalFunction.kt | 197 ++++++++++++++++++ 4 files changed, 303 insertions(+), 55 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index e0b92a712..29aeb6bb0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -117,8 +117,8 @@ public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomia */ public class LabeledPolynomialSpace>( public override val ring: A, -) : PolynomialSpaceOverRing, A> { - public operator fun Symbol.plus(other: Int): LabeledPolynomial = +) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { + public override operator fun Symbol.plus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) @@ -126,7 +126,7 @@ public class LabeledPolynomialSpace>( mapOf(this@plus to 1U) to constantOne, emptyMap() to constantOne * other, )) - public operator fun Symbol.minus(other: Int): LabeledPolynomial = + public override operator fun Symbol.minus(other: Int): LabeledPolynomial = if (other == 0) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) @@ -134,13 +134,13 @@ public class LabeledPolynomialSpace>( mapOf(this@minus to 1U) to -constantOne, emptyMap() to constantOne * other, )) - public operator fun Symbol.times(other: Int): LabeledPolynomial = + public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * other, )) - public operator fun Int.plus(other: Symbol): LabeledPolynomial = + public override operator fun Int.plus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) @@ -148,7 +148,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to constantOne, emptyMap() to constantOne * this@plus, )) - public operator fun Int.minus(other: Symbol): LabeledPolynomial = + public override operator fun Int.minus(other: Symbol): LabeledPolynomial = if (this == 0) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) @@ -156,7 +156,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to -constantOne, emptyMap() to constantOne * this@minus, )) - public operator fun Int.times(other: Symbol): LabeledPolynomial = + public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne * this@times, @@ -275,7 +275,7 @@ public class LabeledPolynomialSpace>( */ public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - public operator fun C.plus(other: Symbol): LabeledPolynomial = + public override operator fun C.plus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, )) @@ -283,7 +283,7 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) - public operator fun C.minus(other: Symbol): LabeledPolynomial = + public override operator fun C.minus(other: Symbol): LabeledPolynomial = if (isZero()) LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, )) @@ -291,13 +291,13 @@ public class LabeledPolynomialSpace>( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) - public operator fun C.times(other: Symbol): LabeledPolynomial = + public override operator fun C.times(other: Symbol): LabeledPolynomial = if (isZero()) zero else LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) - public operator fun Symbol.plus(other: C): LabeledPolynomial = + public override operator fun Symbol.plus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, )) @@ -305,7 +305,7 @@ public class LabeledPolynomialSpace>( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) - public operator fun Symbol.minus(other: C): LabeledPolynomial = + public override operator fun Symbol.minus(other: C): LabeledPolynomial = if (other.isZero()) LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, )) @@ -313,7 +313,7 @@ public class LabeledPolynomialSpace>( mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) - public operator fun Symbol.times(other: C): LabeledPolynomial = + public override operator fun Symbol.times(other: C): LabeledPolynomial = if (other.isZero()) zero else LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, @@ -430,7 +430,15 @@ public class LabeledPolynomialSpace>( if (value == 0) zero else LabeledPolynomial(mapOf(emptyMap() to value)) - public operator fun Symbol.plus(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.unaryPlus(): LabeledPolynomial = + LabeledPolynomial(mapOf( + mapOf(this to 1U) to constantOne, + )) + public override operator fun Symbol.unaryMinus(): LabeledPolynomial = + LabeledPolynomial(mapOf( + mapOf(this to 1U) to -constantOne, + )) + public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne * 2 )) @@ -438,13 +446,13 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, )) - public operator fun Symbol.minus(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero else LabeledPolynomial(mapOf( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, )) - public operator fun Symbol.times(other: Symbol): LabeledPolynomial = + public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = if (this == other) LabeledPolynomial(mapOf( mapOf(this to 2U) to constantOne )) @@ -452,7 +460,7 @@ public class LabeledPolynomialSpace>( mapOf(this to 1U, other to 1U) to constantOne, )) - public operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) else LabeledPolynomial( @@ -467,7 +475,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) else LabeledPolynomial( @@ -484,13 +492,13 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = + public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( other.coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } ) - public operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -505,7 +513,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) else LabeledPolynomial( @@ -520,7 +528,7 @@ public class LabeledPolynomialSpace>( } ) } - public operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = + public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomial( coefficients .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } @@ -604,7 +612,7 @@ public class LabeledPolynomialSpace>( * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. * And keys of the map is the same as in [variables]. */ - public val LabeledPolynomial.degrees: Map + public override val LabeledPolynomial.degrees: Map get() = buildMap { coefficients.entries.forEach { (degs, c) -> @@ -613,10 +621,20 @@ public class LabeledPolynomialSpace>( } } } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.filterKeys { it in variables }.values.sum() } ?: 0u /** * Set of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.variables: Set + public override val LabeledPolynomial.variables: Set get() = buildSet { coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } @@ -624,7 +642,7 @@ public class LabeledPolynomialSpace>( /** * Count of all variables that appear in the polynomial in positive exponents. */ - public val LabeledPolynomial.countOfVariables: Int get() = variables.size + public override val LabeledPolynomial.countOfVariables: Int get() = variables.size /** * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 599660b52..00dd3bb47 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -63,14 +63,16 @@ public fun > A.LabeledRationalFunction(numeratorCoefficients: Map< public class LabeledRationalFunctionSpace>( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, + Symbol, LabeledPolynomial, LabeledRationalFunction, LabeledPolynomialSpace, >, - PolynomialSpaceOfFractions< + MultivariatePolynomialSpaceOfFractions< C, + Symbol, LabeledPolynomial, LabeledRationalFunction, >() { @@ -113,33 +115,6 @@ public class LabeledRationalFunctionSpace>( return numerator * other.denominator equalsTo other.numerator * denominator } - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public val LabeledPolynomial.degrees: Map get() = polynomialRing { degrees } - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledPolynomial.variables: Set get() = polynomialRing { variables } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledRationalFunction.variables: Set - get() = numerator.variables union denominator.variables - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val LabeledRationalFunction.countOfVariables: Int get() = variables.size - // TODO: Разобрать // operator fun invoke(arg: Map): LabeledRationalFunction = 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 f8d7d5a36..224e18832 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 @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.js.JsName import kotlin.jvm.JvmName @@ -413,4 +414,61 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly * Instance of unit constant (unit of the underlying ring). */ public override val constantOne: C get() = ring.one +} + +public interface MultivariatePolynomialSpace>: PolynomialSpace { + public operator fun V.plus(other: Int): P + public operator fun V.minus(other: Int): P + public operator fun V.times(other: Int): P + + public operator fun Int.plus(other: V): P + public operator fun Int.minus(other: V): P + public operator fun Int.times(other: V): P + + public operator fun C.plus(other: V): P + public operator fun C.minus(other: V): P + public operator fun C.times(other: V): P + + public operator fun V.plus(other: C): P + public operator fun V.minus(other: C): P + public operator fun V.times(other: C): P + + public operator fun V.unaryPlus(): P + public operator fun V.unaryMinus(): P + public operator fun V.plus(other: V): P + public operator fun V.minus(other: V): P + public operator fun V.times(other: V): P + + public operator fun V.plus(other: P): P + public operator fun V.minus(other: P): P + public operator fun V.times(other: P): P + + public operator fun P.plus(other: V): P + public operator fun P.minus(other: V): P + public operator fun P.times(other: V): P + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 90e3bdbb1..c5fcde8ed 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1306,4 +1306,201 @@ public abstract class PolynomialSpaceOfFractions< * Instance of unit polynomial (unit of the rational functions ring). */ public override val one: R get() = constructRationalFunction(polynomialOne) +} + +public interface MultivariateRationalFunctionalSpace< + C, + V, + P: Polynomial, + R: RationalFunction + >: RationalFunctionalSpace { + public operator fun V.plus(other: Int): P + public operator fun V.minus(other: Int): P + public operator fun V.times(other: Int): P + + public operator fun Int.plus(other: V): P + public operator fun Int.minus(other: V): P + public operator fun Int.times(other: V): P + + public operator fun C.plus(other: V): P + public operator fun C.minus(other: V): P + public operator fun C.times(other: V): P + + public operator fun V.plus(other: C): P + public operator fun V.minus(other: C): P + public operator fun V.times(other: C): P + + public operator fun V.unaryPlus(): P + public operator fun V.unaryMinus(): P + public operator fun V.plus(other: V): P + public operator fun V.minus(other: V): P + public operator fun V.times(other: V): P + + public operator fun V.plus(other: P): P + public operator fun V.minus(other: P): P + public operator fun V.times(other: P): P + + public operator fun P.plus(other: V): P + public operator fun P.minus(other: V): P + public operator fun P.times(other: V): P + + public operator fun V.plus(other: R): R + public operator fun V.minus(other: R): R + public operator fun V.times(other: R): R + + public operator fun R.plus(other: V): R + public operator fun R.minus(other: V): R + public operator fun R.times(other: V): R + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size + + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val R.variables: Set get() = numerator.variables union denominator.variables + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val R.countOfVariables: Int get() = variables.size +} + +public interface MultivariateRationalFunctionalSpaceOverRing< + C, + V, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace + +public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< + C, + V, + P: Polynomial, + R: RationalFunction, + AP: PolynomialSpace, + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace + +public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + C, + V, + P: Polynomial, + R: RationalFunction, + AP: MultivariatePolynomialSpace, + > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + + public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + + public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + + public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + + public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + public override operator fun P.times(other: V): P = polynomialRing { this@times * other } + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public override val P.degrees: Map get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun P.degreeBy(variable: V): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun P.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public override val P.variables: Set get() = polynomialRing { variables } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } +} + +public abstract class MultivariatePolynomialSpaceOfFractions< + C, + V, + P: Polynomial, + R: RationalFunction, + > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + public override operator fun V.plus(other: R): R = + constructRationalFunction( + this * other.denominator + other.numerator, + other.denominator + ) + public override operator fun V.minus(other: R): R = + constructRationalFunction( + this * other.denominator - other.numerator, + other.denominator + ) + public override operator fun V.times(other: R): R = + constructRationalFunction( + this * other.numerator, + other.denominator + ) + + public override operator fun R.plus(other: V): R = + constructRationalFunction( + numerator + denominator * other, + denominator + ) + public override operator fun R.minus(other: V): R = + constructRationalFunction( + numerator - denominator * other, + denominator + ) + public override operator fun R.times(other: V): R = + constructRationalFunction( + numerator * other, + denominator + ) } \ No newline at end of file From 5b8d6b601e54526c0148bd391e380d305ad4496a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 15:37:19 +0300 Subject: [PATCH 052/174] Added `degreeBy` to `Numbered...`. --- .../kscience/kmath/functions/NumberedPolynomial.kt | 12 ++++++++++++ .../kmath/functions/NumberedRationalFunction.kt | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 1f37a1c2b..570ccce8e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -471,6 +471,18 @@ public open class NumberedPolynomialSpace>( } } } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, c) -> + if (c.isZero()) 0u else degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, * the result is `0`. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index b32f01f2a..2a4d942a6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -126,6 +126,14 @@ public class NumberedRationalFunctionSpace> ( * And last index of the list is [lastVariable]. */ public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, * the result is `0`. From d75a41482d09a7b97c049924df60b370ee14497c Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:09:33 +0300 Subject: [PATCH 053/174] Added fabrics for `LabeledPolynomial` and `NumberedPolynomial`. --- .../kmath/functions/LabeledPolynomial.kt | 131 ++++++++------ .../kmath/functions/NumberedPolynomial.kt | 171 ++++++++---------- 2 files changed, 158 insertions(+), 144 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 29aeb6bb0..3d1b91f7b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -54,59 +54,86 @@ internal constructor( */ internal fun Map.cleanUp() = filterValues { it > 0U } -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(coefs) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : LabeledPolynomial { -// if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return LabeledPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//// TODO: Do not know how to make it without context receivers -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//public fun LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -// -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//public fun LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -// -//context(LabeledPolynomialSpace>) -//@Suppress("FunctionName") -//public fun LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toList(), toCheckInput = true) -// -//context(LabeledPolynomialSpace>) -//public fun Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) + +//context(A) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +//context(LabeledPolynomialSpace) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) /** * Space of polynomials. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 570ccce8e..411409e39 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -53,56 +53,86 @@ internal constructor( */ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(coefs) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in coefs) { -// val key = entry.key.cleanUp() -// val value = entry.value -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { -// if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) -// -// val fixedCoefs = mutableMapOf, C>() -// -// for (entry in pairs) { -// val key = entry.first.cleanUp() -// val value = entry.second -// fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value -// } -// -// return NumberedPolynomial( -// fixedCoefs.filterValues { it.isNotZero() } -// ) -//} -// -//// TODO: Do not know how to make it without context receivers -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -// -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -// -//context(NumberedPolynomialSpace>) -//@Suppress("FunctionName") -//public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) +// Waiting for context receivers :( TODO: Replace with context receivers when they will be available -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial( + fixedCoefs.filterValues { it != zero } + ) +} + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) + +//context(A) +//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to one)) +//context(NumberedPolynomialSpace) +//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) /** * Space of polynomials. @@ -574,47 +604,4 @@ public open class NumberedPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } - - @Suppress("FunctionName") - internal fun NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = false) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial( - fixedCoefs.filterValues { it.isNotZero() } - ) - } - - @Suppress("FunctionName") - internal fun NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = false) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial( - fixedCoefs.filterValues { it.isNotZero() } - ) - } - - @Suppress("FunctionName") - public fun NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - - @Suppress("FunctionName") - public fun NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - - @Suppress("FunctionName") - public fun NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toList(), toCheckInput = true) } \ No newline at end of file From 0a5122a974b1e6a6d888115e36bbe3118db931f3 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 19:40:55 +0300 Subject: [PATCH 054/174] Prototyped DSL-like constructor for `NumberedPolynomial`. --- .../kmath/functions/NumberedPolynomial.kt | 58 ++++++++++++++++++- .../kmath/functions/labeledPolynomialUtil.kt | 47 --------------- .../kmath/functions/listPolynomialUtil.kt | 2 +- 3 files changed, 58 insertions(+), 49 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 411409e39..80998d6bf 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import kotlin.contracts.InvocationKind @@ -132,7 +133,59 @@ public fun > NumberedPolynomialSpace.NumberedPolynomial(vara //context(NumberedPolynomialSpace) //public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) +//context(A) +//public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +@DslMarker +internal annotation class NumberedPolynomialConstructorDSL + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + private val signature: MutableList = ArrayList() + public fun build(): List = signature + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] = deg + } + } + public infix fun Int.to(deg: UInt): Unit = this inPowerOf deg +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } + } +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } + } +} + +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() /** * Space of polynomials. @@ -604,4 +657,7 @@ public open class NumberedPolynomialSpace>( for ((degs, c) in this) if (c.isZero()) this.remove(degs) } } + + // TODO: Move to other constructors with context receiver + public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) } \ 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 27fdd7d7b..88d357413 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 @@ -17,53 +17,6 @@ import kotlin.contracts.contract // TODO: Docs -//// TODO: Reuse underlying ring extensions -// -//context(LabeledPolynomialSpace) -//@Suppress("NOTHING_TO_INLINE") -//fun > numberConstant(value: Int): C = ring { number(value) } -// -//context(LabeledPolynomialSpace) -//fun > power(arg: C, pow: UInt): C = ring { power(arg, pow) } -// -//context(LabeledPolynomialSpace) -//fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } -// - -// -//context(LabeledPolynomialSpace) -//fun > power(arg: Symbol, pow: UInt): LabeledPolynomial = -// if (pow == 0U) one -// else LabeledPolynomial(mapOf( -// mapOf(arg to pow) to constantOne -// )) -// - -// -//context(LabeledPolynomialSpace) -//fun > number(value: Int): LabeledPolynomial = ring { LabeledPolynomial(mapOf(emptyMap() to number(value))) } -// -//context(LabeledPolynomialSpace) -//fun > multiplyWithPower(base: LabeledPolynomial, arg: LabeledPolynomial, pow: UInt): LabeledPolynomial = -// when { -// arg.isZero() && pow > 0U -> base -// arg.isOne() -> base -// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base -// else -> multiplyWithPowerInternalLogic(base, arg, pow) -// } -// -//// Trivial but very slow -//context(LabeledPolynomialSpace) -//internal tailrec fun > multiplyWithPowerInternalLogic(base: LabeledPolynomial, arg: LabeledPolynomial, exponent: UInt): LabeledPolynomial = -// when { -// exponent == 0U -> base -// exponent == 1U -> base * arg -// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) -// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) -// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") -// } -// - /** * Creates a [LabeledPolynomialSpace] over a received ring. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt index df5ba593a..35155d09d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt @@ -124,7 +124,7 @@ public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial = MutableList(thisDegree * argDegree + 1) { constantZero } resultCoefs[0] = coefficients[thisDegree] From 420bf05b22fa107ad33cf2bb5b05795c8b22b96e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 22 Mar 2022 19:42:59 +0300 Subject: [PATCH 055/174] Fixed annoying JVM clashes :expressionless: --- .../kscience/kmath/functions/Polynomial.kt | 24 ++++++++ .../kmath/functions/RationalFunction.kt | 61 +++++++++++++++++++ 2 files changed, 85 insertions(+) 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 224e18832..d44c47dd6 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 @@ -416,35 +416,59 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +@Suppress("INAPPLICABLE_JVM_NAME") public interface MultivariatePolynomialSpace>: PolynomialSpace { + @JvmName("VariableIntPlus") public operator fun V.plus(other: Int): P + @JvmName("VariableIntMinus") public operator fun V.minus(other: Int): P + @JvmName("VariableIntMinusTimes") public operator fun V.times(other: Int): P + @JvmName("IntVariablePlus") public operator fun Int.plus(other: V): P + @JvmName("IntVariableMinus") public operator fun Int.minus(other: V): P + @JvmName("IntVariableTimes") public operator fun Int.times(other: V): P + @JvmName("ConstantVariablePlus") public operator fun C.plus(other: V): P + @JvmName("ConstantVariableMinus") public operator fun C.minus(other: V): P + @JvmName("ConstantVariableTimes") public operator fun C.times(other: V): P + @JvmName("VariableConstantPlus") public operator fun V.plus(other: C): P + @JvmName("VariableConstantMinus") public operator fun V.minus(other: C): P + @JvmName("VariableConstantTimes") public operator fun V.times(other: C): P + @JvmName("VariableUnaryPlus") public operator fun V.unaryPlus(): P + @JvmName("VariableUnaryMinus") public operator fun V.unaryMinus(): P + @JvmName("VariablePlus") public operator fun V.plus(other: V): P + @JvmName("VariableMinus") public operator fun V.minus(other: V): P + @JvmName("VariableTimes") public operator fun V.times(other: V): P + @JvmName("VariablePolynomialPlus") public operator fun V.plus(other: P): P + @JvmName("VariablePolynomialMinus") public operator fun V.minus(other: P): P + @JvmName("VariablePolynomialTimes") public operator fun V.times(other: P): P + @JvmName("PolynomialVariablePlus") public operator fun P.plus(other: V): P + @JvmName("PolynomialVariableMinus") public operator fun P.minus(other: V): P + @JvmName("PolynomialVariableTimes") public operator fun P.times(other: V): P /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index c5fcde8ed..9c0263c4c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1308,48 +1308,78 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } +@Suppress("INAPPLICABLE_JVM_NAME") public interface MultivariateRationalFunctionalSpace< C, V, P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + @JvmName("VariableIntPlus") public operator fun V.plus(other: Int): P + @JvmName("VariableIntMinus") public operator fun V.minus(other: Int): P + @JvmName("VariableIntMinusTimes") public operator fun V.times(other: Int): P + @JvmName("IntVariablePlus") public operator fun Int.plus(other: V): P + @JvmName("IntVariableMinus") public operator fun Int.minus(other: V): P + @JvmName("IntVariableTimes") public operator fun Int.times(other: V): P + @JvmName("ConstantVariablePlus") public operator fun C.plus(other: V): P + @JvmName("ConstantVariableMinus") public operator fun C.minus(other: V): P + @JvmName("ConstantVariableTimes") public operator fun C.times(other: V): P + @JvmName("VariableConstantPlus") public operator fun V.plus(other: C): P + @JvmName("VariableConstantMinus") public operator fun V.minus(other: C): P + @JvmName("VariableConstantTimes") public operator fun V.times(other: C): P + @JvmName("VariableUnaryPlus") public operator fun V.unaryPlus(): P + @JvmName("VariableUnaryMinus") public operator fun V.unaryMinus(): P + @JvmName("VariablePlus") public operator fun V.plus(other: V): P + @JvmName("VariableMinus") public operator fun V.minus(other: V): P + @JvmName("VariableTimes") public operator fun V.times(other: V): P + @JvmName("VariablePolynomialPlus") public operator fun V.plus(other: P): P + @JvmName("VariablePolynomialMinus") public operator fun V.minus(other: P): P + @JvmName("VariablePolynomialTimes") public operator fun V.times(other: P): P + @JvmName("PolynomialVariablePlus") public operator fun P.plus(other: V): P + @JvmName("PolynomialVariableMinus") public operator fun P.minus(other: V): P + @JvmName("PolynomialVariableTimes") public operator fun P.times(other: V): P + @JvmName("VariableRationalFunctionPlus") public operator fun V.plus(other: R): R + @JvmName("VariableRationalFunctionMinus") public operator fun V.minus(other: R): R + @JvmName("VariableRationalFunctionTimes") public operator fun V.times(other: R): R + @JvmName("RationalFunctionVariablePlus") public operator fun R.plus(other: V): R + @JvmName("RationalFunctionVariableMinus") public operator fun R.minus(other: V): R + @JvmName("RationalFunctionVariableTimes") public operator fun R.times(other: V): R /** @@ -1403,6 +1433,7 @@ public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace +@Suppress("INAPPLICABLE_JVM_NAME") public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, V, @@ -1410,34 +1441,57 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp R: RationalFunction, AP: MultivariatePolynomialSpace, > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + @JvmName("VariableIntPlus") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + @JvmName("VariableIntMinus") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + @JvmName("VariableIntMinusTimes") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + @JvmName("IntVariablePlus") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("IntVariableMinus") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("IntVariableTimes") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } + @JvmName("ConstantVariablePlus") public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("ConstantVariableMinus") public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("ConstantVariableTimes") public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + @JvmName("VariableConstantPlus") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + @JvmName("VariableConstantMinus") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + @JvmName("VariableConstantTimes") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + @JvmName("VariableUnaryPlus") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + @JvmName("VariableUnaryMinus") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + @JvmName("VariablePlus") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("VariableMinus") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("VariableTimes") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + @JvmName("VariablePolynomialPlus") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + @JvmName("VariablePolynomialMinus") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + @JvmName("VariablePolynomialTimes") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + @JvmName("PolynomialVariablePlus") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + @JvmName("PolynomialVariableMinus") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + @JvmName("PolynomialVariableTimes") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } /** @@ -1466,38 +1520,45 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +@Suppress("INAPPLICABLE_JVM_NAME") public abstract class MultivariatePolynomialSpaceOfFractions< C, V, P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + @JvmName("VariableRationalFunctionPlus") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + @JvmName("VariableRationalFunctionMinus") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + @JvmName("VariableRationalFunctionTimes") public override operator fun V.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) + @JvmName("RationalFunctionVariablePlus") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + @JvmName("RationalFunctionVariableMinus") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + @JvmName("RationalFunctionVariableTimes") public override operator fun R.times(other: V): R = constructRationalFunction( numerator * other, From 060f0ee35dfdfe510b70c55550a379f47d6106d7 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 00:57:32 +0300 Subject: [PATCH 056/174] Removed comparability feature. --- .../kmath/functions/LabeledPolynomial.kt | 286 +++++------------ .../functions/LabeledRationalFunction.kt | 58 +--- .../kmath/functions/ListPolynomial.kt | 203 +++--------- .../kmath/functions/ListRationalFunction.kt | 16 +- .../kmath/functions/NumberedPolynomial.kt | 246 ++++----------- .../functions/NumberedRationalFunction.kt | 60 +--- .../kscience/kmath/functions/Polynomial.kt | 86 ----- .../kmath/functions/RationalFunction.kt | 297 ++---------------- .../kmath/functions/listPolynomialUtil.kt | 9 +- .../functions/listRationalFunctionUtil.kt | 6 +- .../kmath/functions/ListPolynomialTest.kt | 156 +-------- .../kmath/functions/ListPolynomialUtilTest.kt | 2 +- 12 files changed, 242 insertions(+), 1183 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 3d1b91f7b..908e89534 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -58,6 +58,8 @@ internal fun Map.cleanUp() = filterValues { it > 0U } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) @Suppress("FunctionName") internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { if (!toCheckInput) return LabeledPolynomial(coefs) @@ -70,13 +72,13 @@ internal fun > A.LabeledPolynomial(coefs: Map, C fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value } - return LabeledPolynomial( - fixedCoefs.filterValues { it != zero } - ) + return LabeledPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) @Suppress("FunctionName") internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) @@ -89,13 +91,13 @@ internal fun > A.LabeledPolynomial(pairs: Collection( - fixedCoefs.filterValues { it != zero } - ) + return LabeledPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) @Suppress("FunctionName") internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) @@ -108,25 +110,29 @@ internal fun > A.LabeledPolynomial(vararg pairs: Pair( - fixedCoefs.filterValues { it != zero } - ) + return LabeledPolynomial(fixedCoefs) } @Suppress("FunctionName") public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) @Suppress("FunctionName") public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) //context(A) //public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) @@ -196,19 +202,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = if (other == 0) this - else - LabeledPolynomial( - coefficients - .toMutableMap() + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) + } /** * Returns difference between the polynomial and the integer represented as polynomial. * @@ -216,19 +220,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = if (other == 0) this - else - LabeledPolynomial( - coefficients - .toMutableMap() + else with(coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) + } /** * Returns product of the polynomial and the integer represented as polynomial. * @@ -238,7 +240,8 @@ public class LabeledPolynomialSpace>( if (other == 0) zero else LabeledPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -250,19 +253,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other - else - LabeledPolynomial( - other.coefficients - .toMutableMap() + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) + } /** * Returns difference between the integer represented as polynomial and the polynomial. * @@ -270,19 +271,17 @@ public class LabeledPolynomialSpace>( */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other - else - LabeledPolynomial( - other.coefficients - .toMutableMap() + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) + else LabeledPolynomial( + toMutableMap() .apply { val degs = emptyMap() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) + } /** * Returns product of the integer represented as polynomial and the polynomial. * @@ -292,7 +291,8 @@ public class LabeledPolynomialSpace>( if (this == 0) zero else LabeledPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -303,46 +303,32 @@ public class LabeledPolynomialSpace>( public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) public override operator fun C.plus(other: Symbol): LabeledPolynomial = - if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, )) public override operator fun C.minus(other: Symbol): LabeledPolynomial = - if (isZero()) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, )) public override operator fun C.times(other: Symbol): LabeledPolynomial = - if (isZero()) zero - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(other to 1U) to this@times, )) public override operator fun Symbol.plus(other: C): LabeledPolynomial = - if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, )) public override operator fun Symbol.minus(other: C): LabeledPolynomial = - if (other.isZero()) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(this@minus to 1U) to -constantOne, emptyMap() to other, )) public override operator fun Symbol.times(other: C): LabeledPolynomial = - if (other.isZero()) zero - else LabeledPolynomial(mapOf( + LabeledPolynomial(mapOf( mapOf(this@times to 1U) to other, )) @@ -350,18 +336,14 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) else LabeledPolynomial( toMutableMap() .apply { val degs = emptyMap() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) } @@ -369,8 +351,7 @@ public class LabeledPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) else LabeledPolynomial( toMutableMap() @@ -379,10 +360,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) } @@ -390,10 +368,10 @@ public class LabeledPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - if (this.isZero()) zero - else LabeledPolynomial( + LabeledPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -402,18 +380,14 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() .apply { val degs = emptyMap() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) } @@ -421,8 +395,7 @@ public class LabeledPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) else LabeledPolynomial( toMutableMap() @@ -431,10 +404,7 @@ public class LabeledPolynomialSpace>( val degs = emptyMap() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) } @@ -442,10 +412,10 @@ public class LabeledPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - if (other.isZero()) zero - else LabeledPolynomial( + LabeledPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -454,8 +424,7 @@ public class LabeledPolynomialSpace>( * Converts the constant [value] to polynomial. */ public override fun number(value: C): LabeledPolynomial = - if (value == 0) zero - else LabeledPolynomial(mapOf(emptyMap() to value)) + LabeledPolynomial(mapOf(emptyMap() to value)) public override operator fun Symbol.unaryPlus(): LabeledPolynomial = LabeledPolynomial(mapOf( @@ -495,10 +464,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = mapOf(this@plus to 1U) - val result = constantOne + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne + getOrElse(degs) { constantZero } } ) } @@ -512,10 +478,7 @@ public class LabeledPolynomialSpace>( val degs = mapOf(this@minus to 1U) - val result = constantOne - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne - getOrElse(degs) { constantZero } } ) } @@ -533,10 +496,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = mapOf(other to 1U) - val result = constantOne + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne + getOrElse(degs) { constantZero } } ) } @@ -548,10 +508,7 @@ public class LabeledPolynomialSpace>( .apply { val degs = mapOf(other to 1U) - val result = constantOne - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = constantOne - getOrElse(degs) { constantZero } } ) } @@ -573,7 +530,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } @@ -583,7 +540,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } @@ -592,20 +549,16 @@ public class LabeledPolynomialSpace>( * Returns product of the polynomials. */ override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - when { - isZero() -> zero - other.isZero() -> zero - else -> LabeledPolynomial( - buildCoefficients(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } + LabeledPolynomial( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c } - ) - } + } + ) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -616,22 +569,12 @@ public class LabeledPolynomialSpace>( */ override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - /** - * Checks equality of the polynomials. - */ - override infix fun LabeledPolynomial.equalsTo(other: LabeledPolynomial): Boolean = - when { - this === other -> true - else -> coefficients.size == other.coefficients.size && - coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } - } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.values.sum().toInt() } ?: -1 + get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 /** * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents * in which they are appeared in the polynomial. @@ -642,8 +585,8 @@ public class LabeledPolynomialSpace>( public override val LabeledPolynomial.degrees: Map get() = buildMap { - coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.mapValuesTo(this) { (variable, deg) -> + coefficients.entries.forEach { (degs, _) -> + degs.mapValuesTo(this) { (variable, deg) -> max(getOrElse(variable) { 0u }, deg) } } @@ -652,55 +595,25 @@ public class LabeledPolynomialSpace>( * Counts degree of the polynomial by the specified [variable]. */ public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u /** * Counts degree of the polynomial by the specified [variables]. */ public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.filterKeys { it in variables }.values.sum() } ?: 0u + coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u /** * Set of all variables that appear in the polynomial in positive exponents. */ public override val LabeledPolynomial.variables: Set get() = buildSet { - coefficients.entries.forEach { (degs, c) -> if (c.isNotZero()) addAll(degs.keys) } + coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } } /** * Count of all variables that appear in the polynomial in positive exponents. */ public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - override fun LabeledPolynomial.isConstant(): Boolean = - coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - override fun LabeledPolynomial.isNonZeroConstant(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsNotZero = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isZero()) return@with false - else foundAbsoluteTermAndItIsNotZero = true - } - } - foundAbsoluteTermAndItIsNotZero - } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - override fun LabeledPolynomial.asConstantOrNull(): C? = - with(coefficients) { - if(isConstant()) getOrElse(emptyMap()) { constantZero } - else null - } - // @Suppress("NOTHING_TO_INLINE") // public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) // @Suppress("NOTHING_TO_INLINE") @@ -719,33 +632,4 @@ public class LabeledPolynomialSpace>( // @Suppress("NOTHING_TO_INLINE") // @JvmName("invokePolynomial") // public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) - - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - return this - } - internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = - toMutableMap().applyAndRemoveZeros(block) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap(capacity) { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 00dd3bb47..0f46520dc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -19,45 +19,35 @@ public class LabeledRationalFunction( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -@Suppress("FunctionName") -internal fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = - if (denominator.isZero()) throw ArithmeticException("/ by zero") - else LabeledRationalFunction(numerator, denominator) -@Suppress("FunctionName") -internal fun > A.LabeledRationalFunction(numerator: LabeledPolynomial, denominator: LabeledPolynomial): LabeledRationalFunction = - if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else LabeledRationalFunction(numerator, denominator) @Suppress("FunctionName") public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), - LabeledPolynomial(denominatorCoefficients) + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), - LabeledPolynomial(denominatorCoefficients) + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = LabeledRationalFunction(numerator, polynomialOne) @Suppress("FunctionName") public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) @Suppress("FunctionName") public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), polynomialOne ) @Suppress("FunctionName") public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients), - LabeledPolynomial(mapOf(emptyMap() to one)) + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) ) public class LabeledRationalFunctionSpace>( @@ -82,38 +72,16 @@ public class LabeledRationalFunctionSpace>( numerator: LabeledPolynomial, denominator: LabeledPolynomial ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) + LabeledRationalFunction(numerator, denominator) /** * Instance of zero rational function (zero of the rational functions ring). */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) + public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) /** * Instance of unit polynomial (unit of the rational functions ring). */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - /** - * Checks equality of the rational functions. - */ - public override infix fun LabeledRationalFunction.equalsTo(other: LabeledRationalFunction): Boolean { - if (this === other) return true - - if (numerator.isZero() != other.numerator.isZero()) return false - - val variables = this.variables union other.variables - val thisNumeratorDegrees = this.numerator.degrees - val thisDenominatorDegrees = this.denominator.degrees - val otherNumeratorDegrees = other.numerator.degrees - val otherDenominatorDegrees = other.denominator.degrees - for (variable in variables) - if ( - thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } - != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } - ) return false - - return numerator * other.denominator equalsTo other.numerator * denominator - } + public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) // TODO: Разобрать diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 90e9cde69..711d2bb49 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -91,13 +91,9 @@ public open class ListPolynomialSpace>( .toMutableList() .apply { val result = getOrElse(0) { constantZero } + other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -113,13 +109,9 @@ public open class ListPolynomialSpace>( .toMutableList() .apply { val result = getOrElse(0) { constantZero } - other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -131,7 +123,8 @@ public open class ListPolynomialSpace>( if (other == 0) zero else ListPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this[deg] * other } ) @@ -149,13 +142,9 @@ public open class ListPolynomialSpace>( .toMutableList() .apply { val result = this@plus + getOrElse(0) { constantZero } - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -173,13 +162,9 @@ public open class ListPolynomialSpace>( forEachIndexed { index, c -> if (index != 0) this[index] = -c } val result = this@minus - getOrElse(0) { constantZero } - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) /** @@ -191,7 +176,8 @@ public open class ListPolynomialSpace>( if (this == 0) zero else ListPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -205,20 +191,15 @@ public open class ListPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ public override operator fun C.plus(other: ListPolynomial): ListPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) ListPolynomial(listOf(this@plus)) else ListPolynomial( toMutableList() .apply { val result = if (size == 0) this@plus else this@plus + get(0) - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -226,8 +207,7 @@ public open class ListPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ public override operator fun C.minus(other: ListPolynomial): ListPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) ListPolynomial(listOf(this@minus)) else ListPolynomial( toMutableList() @@ -235,13 +215,9 @@ public open class ListPolynomialSpace>( forEachIndexed { index, c -> if (index != 0) this[index] = -c } val result = if (size == 0) this@minus else this@minus - get(0) - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -249,10 +225,10 @@ public open class ListPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ public override operator fun C.times(other: ListPolynomial): ListPolynomial = - if (this.isZero()) other - else ListPolynomial( + ListPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this@times * this[deg] } ) @@ -261,20 +237,15 @@ public open class ListPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ public override operator fun ListPolynomial.plus(other: C): ListPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) ListPolynomial(listOf(other)) else ListPolynomial( toMutableList() .apply { val result = if (size == 0) other else get(0) + other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -282,20 +253,15 @@ public open class ListPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ public override operator fun ListPolynomial.minus(other: C): ListPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) ListPolynomial(listOf(-other)) else ListPolynomial( toMutableList() .apply { val result = if (size == 0) other else get(0) - other - val isResultZero = result.isZero() - when { - size == 0 && !isResultZero -> add(result) - size > 1 || !isResultZero -> this[0] = result - else -> clear() - } + if(size == 0) add(result) + else this[0] = result } ) } @@ -303,10 +269,10 @@ public open class ListPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ public override operator fun ListPolynomial.times(other: C): ListPolynomial = - if (other.isZero()) this - else ListPolynomial( + ListPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableList() + .apply { for (deg in indices) this[deg] = this[deg] * other } ) @@ -314,9 +280,7 @@ public open class ListPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): ListPolynomial = - if (value.isZero()) zero - else ListPolynomial(value) + public override fun number(value: C): ListPolynomial = ListPolynomial(value) /** * Returns negation of the polynomial. @@ -330,7 +294,7 @@ public open class ListPolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return ListPolynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { + List(max(thisDegree, otherDegree) + 1) { when { it > thisDegree -> other.coefficients[it] it > otherDegree -> coefficients[it] @@ -346,7 +310,7 @@ public open class ListPolynomialSpace>( val thisDegree = degree val otherDegree = other.degree return ListPolynomial( - Coefficients(max(thisDegree, otherDegree) + 1) { + List(max(thisDegree, otherDegree) + 1) { when { it > thisDegree -> -other.coefficients[it] it > otherDegree -> coefficients[it] @@ -361,39 +325,15 @@ public open class ListPolynomialSpace>( public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { val thisDegree = degree val otherDegree = other.degree - return when { - thisDegree == -1 -> zero - otherDegree == -1 -> zero - else -> - ListPolynomial( - Coefficients(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } + return ListPolynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } - /** - * Check if the instant is zero polynomial. - */ - public override fun ListPolynomial.isZero(): Boolean = coefficients.all { it.isZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun ListPolynomial.isOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isOne() else c.isZero() } - } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun ListPolynomial.isMinusOne(): Boolean = - with(coefficients) { - isNotEmpty() && withIndex().all { (index, c) -> if (index == 0) c.isMinusOne() else c.isZero() } - } - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -403,34 +343,11 @@ public open class ListPolynomialSpace>( */ override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) - /** - * Checks equality of the polynomials. - */ - public override infix fun ListPolynomial.equalsTo(other: ListPolynomial): Boolean = - when { - this === other -> true - this.degree == other.degree -> (0..degree).all { coefficients[it] == other.coefficients[it] } - else -> false - } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ - public override val ListPolynomial.degree: Int get() = coefficients.indexOfLast { it != constantZero } - - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public override fun ListPolynomial.asConstantOrNull(): C? = - with(coefficients) { - when { - isEmpty() -> constantZero - withIndex().all { (index, c) -> index == 0 || c.isZero() } -> first() - else -> null - } - } + public override val ListPolynomial.degree: Int get() = coefficients.lastIndex @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) @@ -451,44 +368,6 @@ public open class ListPolynomialSpace>( public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) - - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal inline fun MutableList.applyAndRemoveZeros(block: MutableList.() -> Unit) : MutableList { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - return this - } - internal inline fun List.applyAndRemoveZeros(block: MutableList.() -> Unit) : List = - toMutableList().applyAndRemoveZeros(block) - @Suppress("FunctionName") - internal inline fun MutableCoefficients(size: Int, init: (index: Int) -> C): MutableList { - val list = ArrayList(size) - repeat(size) { index -> list.add(init(index)) } - with(list) { while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) } - return list - } - @Suppress("FunctionName") - internal inline fun Coefficients(size: Int, init: (index: Int) -> C): List = MutableCoefficients(size, init) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableList.() -> Unit): List { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildList(capacity) { - builderAction() - while (isNotEmpty() && elementAt(lastIndex).isZero()) removeAt(lastIndex) - } - } } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 67c7e9fa2..f62d1857f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring -public data class ListRationalFunction internal constructor ( +public data class ListRationalFunction( public override val numerator: ListPolynomial, public override val denominator: ListPolynomial ) : RationalFunction> { @@ -17,25 +17,15 @@ public data class ListRationalFunction internal constructor ( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -@Suppress("FunctionName") -internal fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = - if (denominator.isZero()) throw ArithmeticException("/ by zero") - else ListRationalFunction(numerator, denominator) -@Suppress("FunctionName") -internal fun > A.ListRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = - if (denominator.coefficients.all { it == zero }) throw ArithmeticException("/ by zero") - else ListRationalFunction(numerator, denominator) @Suppress("FunctionName") public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") - else ListRationalFunction( + ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - if (denominatorCoefficients.all { it == zero }) throw ArithmeticException("/ by zero") - else ListRationalFunction( + ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 80998d6bf..51f316c5d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -58,6 +58,8 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) @Suppress("FunctionName") internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { if (!toCheckInput) return NumberedPolynomial(coefs) @@ -70,13 +72,13 @@ internal fun > A.NumberedPolynomial(coefs: Map, C>, toC fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value } - return NumberedPolynomial( - fixedCoefs.filterValues { it != zero } - ) + return NumberedPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) @Suppress("FunctionName") internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) @@ -89,13 +91,13 @@ internal fun > A.NumberedPolynomial(pairs: Collection( - fixedCoefs.filterValues { it != zero } - ) + return NumberedPolynomial(fixedCoefs) } @Suppress("FunctionName", "NOTHING_TO_INLINE") internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) @Suppress("FunctionName") internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) @@ -108,25 +110,29 @@ internal fun > A.NumberedPolynomial(vararg pairs: Pair, fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value } - return NumberedPolynomial( - fixedCoefs.filterValues { it != zero } - ) + return NumberedPolynomial(fixedCoefs) } @Suppress("FunctionName") public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) @Suppress("FunctionName") public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) @Suppress("FunctionName") public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) @Suppress("FunctionName") public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) //context(A) //public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to one)) @@ -211,10 +217,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) /** @@ -231,10 +234,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) /** @@ -246,7 +246,8 @@ public open class NumberedPolynomialSpace>( if (other == 0) zero else NumberedPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -265,10 +266,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) /** @@ -285,10 +283,7 @@ public open class NumberedPolynomialSpace>( .apply { val degs = emptyList() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) /** @@ -300,7 +295,8 @@ public open class NumberedPolynomialSpace>( if (this == 0) zero else NumberedPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -314,18 +310,14 @@ public open class NumberedPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this.isZero()) other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) else NumberedPolynomial( toMutableMap() .apply { val degs = emptyList() - val result = this@plus + getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@plus + getOrElse(degs) { constantZero } } ) } @@ -333,8 +325,7 @@ public open class NumberedPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this.isZero()) -other - else with(other.coefficients) { + with(other.coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) else NumberedPolynomial( toMutableMap() @@ -343,10 +334,7 @@ public open class NumberedPolynomialSpace>( val degs = emptyList() - val result = this@minus - getOrElse(degs) { constantZero } - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = this@minus - getOrElse(degs) { constantZero } } ) } @@ -354,10 +342,10 @@ public open class NumberedPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - if (this.isZero()) zero - else NumberedPolynomial( + NumberedPolynomial( other.coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this@times * this[degs]!! } ) @@ -366,18 +354,14 @@ public open class NumberedPolynomialSpace>( * Returns sum of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } + other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } + other } ) } @@ -385,18 +369,14 @@ public open class NumberedPolynomialSpace>( * Returns difference between the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - if (other.isZero()) this - else with(coefficients) { + with(coefficients) { if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) else NumberedPolynomial( toMutableMap() .apply { val degs = emptyList() - val result = getOrElse(degs) { constantZero } - other - - if (result.isZero()) remove(degs) - else this[degs] = result + this[degs] = getOrElse(degs) { constantZero } - other } ) } @@ -404,10 +384,10 @@ public open class NumberedPolynomialSpace>( * Returns product of the constant represented as polynomial and the polynomial. */ override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - if (other.isZero()) zero - else NumberedPolynomial( + NumberedPolynomial( coefficients - .applyAndRemoveZeros { + .toMutableMap() + .apply { for (degs in keys) this[degs] = this[degs]!! * other } ) @@ -416,8 +396,7 @@ public open class NumberedPolynomialSpace>( * Converts the constant [value] to polynomial. */ public override fun number(value: C): NumberedPolynomial = - if (value == 0) zero - else NumberedPolynomial(mapOf(emptyList() to value)) + NumberedPolynomial(mapOf(emptyList() to value)) /** * Returns negation of the polynomial. @@ -431,7 +410,7 @@ public open class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } @@ -441,7 +420,7 @@ public open class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomial( - buildCoefficients(coefficients.size + other.coefficients.size) { + buildMap(coefficients.size + other.coefficients.size) { other.coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } @@ -450,57 +429,17 @@ public open class NumberedPolynomialSpace>( * Returns product of the polynomials. */ override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - when { - isZero() -> zero - other.isZero() -> zero - else -> - NumberedPolynomial( - buildCoefficients(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - } - - /** - * Check if the instant is zero polynomial. - */ - public override fun NumberedPolynomial.isZero(): Boolean = coefficients.values.all { it.isZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun NumberedPolynomial.isOne(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsOne = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isNotOne()) return@with false - else foundAbsoluteTermAndItIsOne = true + NumberedPolynomial( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c } } - foundAbsoluteTermAndItIsOne - } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun NumberedPolynomial.isMinusOne(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsMinusOne = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isNotMinusOne()) return@with false - else foundAbsoluteTermAndItIsMinusOne = true - } - } - foundAbsoluteTermAndItIsMinusOne - } + ) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -516,28 +455,18 @@ public open class NumberedPolynomialSpace>( ) ) - /** - * Checks equality of the polynomials. - */ - override infix fun NumberedPolynomial.equalsTo(other: NumberedPolynomial): Boolean = - when { - this === other -> true - else -> coefficients.size == other.coefficients.size && - coefficients.all { (key, value) -> with(other.coefficients) { key in this && this[key] == value } } - } - /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, * the result is `-1`. */ public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.lastIndex } ?: -1 + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) -1 else degs.sum().toInt() } ?: -1 + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 /** * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most * exponents in which the variables are appeared in the polynomial. @@ -548,8 +477,8 @@ public open class NumberedPolynomialSpace>( public val NumberedPolynomial.degrees: List get() = MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> this[index] = max(this[index], deg) } } @@ -558,13 +487,13 @@ public open class NumberedPolynomialSpace>( * Counts degree of the polynomial by the specified [variable]. */ public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> if (c.isZero()) 0u else degs.getOrElse(variable) { 0u } } ?: 0u + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u /** * Counts degree of the polynomial by the specified [variables]. */ public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, c) -> - if (c.isZero()) 0u else degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + coefficients.entries.maxOfOrNull { (degs, _) -> + degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, @@ -573,43 +502,13 @@ public open class NumberedPolynomialSpace>( public val NumberedPolynomial.countOfVariables: Int get() = MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> if (deg != 0u) this[index] = true } } }.count { it } - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - override fun NumberedPolynomial.isConstant(): Boolean = - coefficients.all { (degs, c) -> degs.isEmpty() || c.isZero() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - override fun NumberedPolynomial.isNonZeroConstant(): Boolean = - with(coefficients) { - var foundAbsoluteTermAndItIsNotZero = false - for ((degs, c) in this) { - if (degs.isNotEmpty()) if (c.isNotZero()) return@with false - else { - if (c.isZero()) return@with false - else foundAbsoluteTermAndItIsNotZero = true - } - } - foundAbsoluteTermAndItIsNotZero - } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - override fun NumberedPolynomial.asConstantOrNull(): C? = - with(coefficients) { - if(isConstant()) getOrElse(emptyList()) { constantZero } - else null - } - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) @Suppress("NOTHING_TO_INLINE") @@ -629,35 +528,6 @@ public open class NumberedPolynomialSpace>( @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - // TODO: Move to other internal utilities with context receiver - @JvmName("applyAndRemoveZerosInternal") - internal fun MutableMap, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : MutableMap, C> { - contract { - callsInPlace(block, InvocationKind.EXACTLY_ONCE) - } - block() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - return this - } - internal fun Map, C>.applyAndRemoveZeros(block: MutableMap, C>.() -> Unit) : Map, C> = - toMutableMap().applyAndRemoveZeros(block) - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(@BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } - @OptIn(ExperimentalTypeInference::class) - internal inline fun buildCoefficients(capacity: Int, @BuilderInference builderAction: MutableMap, C>.() -> Unit): Map, C> { - contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) } - return buildMap(capacity) { - builderAction() - for ((degs, c) in this) if (c.isZero()) this.remove(degs) - } - } - // TODO: Move to other constructors with context receiver public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 2a4d942a6..b4d9f1d91 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -19,45 +19,35 @@ public class NumberedRationalFunction internal constructor( // Waiting for context receivers :( TODO: Replace with context receivers when they will be available -@Suppress("FunctionName") -internal fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = - if (denominator.isZero()) throw ArithmeticException("/ by zero") - else NumberedRationalFunction(numerator, denominator) -@Suppress("FunctionName") -internal fun > A.NumberedRationalFunction(numerator: NumberedPolynomial, denominator: NumberedPolynomial): NumberedRationalFunction = - if (denominator.coefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else NumberedRationalFunction(numerator, denominator) @Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), - NumberedPolynomial(denominatorCoefficients) + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - if (denominatorCoefficients.values.all { it == zero }) throw ArithmeticException("/ by zero") - else NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), - NumberedPolynomial(denominatorCoefficients) + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) ) @Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, polynomialOne) @Suppress("FunctionName") public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) @Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), polynomialOne ) @Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients), - NumberedPolynomial(mapOf(emptyList() to one)) + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) ) public class NumberedRationalFunctionSpace> ( @@ -91,28 +81,6 @@ public class NumberedRationalFunctionSpace> ( */ public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - /** - * Checks equality of the rational functions. - */ - public override infix fun NumberedRationalFunction.equalsTo(other: NumberedRationalFunction): Boolean { - if (this === other) return true - - if (numerator.isZero() != other.numerator.isZero()) return false - - val countOfVariables = max(this.lastVariable, other.lastVariable) - val thisNumeratorDegrees = this.numerator.degrees - val thisDenominatorDegrees = this.denominator.degrees - val otherNumeratorDegrees = other.numerator.degrees - val otherDenominatorDegrees = other.denominator.degrees - for (variable in 0 .. countOfVariables) - if ( - thisNumeratorDegrees.getOrElse(variable) { 0u } + otherDenominatorDegrees.getOrElse(variable) { 0u } - != thisDenominatorDegrees.getOrElse(variable) { 0u } + otherNumeratorDegrees.getOrElse(variable) { 0u } - ) return false - - return numerator * other.denominator equalsTo other.numerator * denominator - } - /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, * the result is `-1`. @@ -152,13 +120,13 @@ public class NumberedRationalFunctionSpace> ( public val NumberedRationalFunction.countOfVariables: Int get() = MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + numerator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> if (deg != 0u) this[index] = true } } - denominator.coefficients.entries.forEach { (degs, c) -> - if (c.isNotZero()) degs.forEachIndexed { index, deg -> + denominator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> if (deg != 0u) this[index] = true } } 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 d44c47dd6..96e860550 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 @@ -155,31 +155,6 @@ public interface PolynomialSpace> : Ring

{ @JsName("constantPower") public fun power(arg: C, exponent: UInt) : C - /** - * Check if the instant is zero constant. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero constant (zero of the underlying ring). */ @@ -249,31 +224,6 @@ public interface PolynomialSpace> : Ring

{ */ public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) - /** - * Check if the instant is zero polynomial. - */ - public fun P.isZero(): Boolean = this equalsTo zero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo one - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -one - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -283,48 +233,12 @@ public interface PolynomialSpace> : Ring

{ */ public override val one: P - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ public val P.degree: Int - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - override fun add(left: P, right: P): P = left + right override fun multiply(left: P, right: P): P = left * right } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 9c0263c4c..374f4a936 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -222,31 +222,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio @JsName("constantPower") public fun power(arg: C, exponent: UInt) : C - /** - * Check if the instant is zero constant. - */ - public fun C.isZero(): Boolean = this == constantZero - /** - * Check if the instant is NOT zero constant. - */ - public fun C.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit constant. - */ - public fun C.isOne(): Boolean = this == constantOne - /** - * Check if the instant is NOT unit constant. - */ - public fun C.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit constant. - */ - public fun C.isMinusOne(): Boolean = this == -constantOne - /** - * Check if the instant is NOT minus unit constant. - */ - public fun C.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero constant (zero of the underlying ring). */ @@ -320,31 +295,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public fun power(arg: P, exponent: UInt) : P - /** - * Check if the instant is zero polynomial. - */ - public fun P.isZero(): Boolean = this equalsTo polynomialZero - /** - * Check if the instant is NOT zero polynomial. - */ - public fun P.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit polynomial. - */ - public fun P.isOne(): Boolean = this equalsTo polynomialOne - /** - * Check if the instant is NOT unit polynomial. - */ - public fun P.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit polynomial. - */ - public fun P.isMinusOne(): Boolean = this equalsTo -polynomialOne - /** - * Check if the instant is NOT minus unit polynomial. - */ - public fun P.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -354,15 +304,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public val polynomialOne: P - /** - * Checks equality of the polynomials. - */ - public infix fun P.equalsTo(other: P): Boolean - /** - * Checks NOT equality of the polynomials. - */ - public infix fun P.notEqualsTo(other: P): Boolean = !(this equalsTo other) - /** * Returns sum of the constant represented as rational function and the rational function. */ @@ -478,31 +419,6 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) - /** - * Check if the instant is zero rational function. - */ - public fun R.isZero(): Boolean = numerator equalsTo polynomialZero - /** - * Check if the instant is NOT zero rational function. - */ - public fun R.isNotZero(): Boolean = !isZero() - /** - * Check if the instant is unit rational function. - */ - public fun R.isOne(): Boolean = numerator equalsTo denominator - /** - * Check if the instant is NOT unit rational function. - */ - public fun R.isNotOne(): Boolean = !isOne() - /** - * Check if the instant is minus unit rational function. - */ - public fun R.isMinusOne(): Boolean = (numerator + denominator).isZero() - /** - * Check if the instant is NOT minus unit rational function. - */ - public fun R.isNotMinusOne(): Boolean = !isMinusOne() - /** * Instance of zero rational function (zero of the rational functions ring). */ @@ -512,54 +428,12 @@ public interface RationalFunctionalSpace, R: RationalFunctio */ public override val one: R - /** - * Checks equality of the rational functions. - */ - public infix fun R.equalsTo(other: R): Boolean = - when { - this === other -> true - numerator.isZero() != other.numerator.isZero() -> false - numeratorDegree - denominatorDegree != with(other) { numeratorDegree - denominatorDegree } -> false - else -> numerator * other.denominator equalsTo other.numerator * denominator - } - /** - * Checks NOT equality of the polynomials. - */ - public infix fun R.notEqualsTo(other: R): Boolean = !(this equalsTo other) - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ public val P.degree: Int - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isConstant(): Boolean = degree <= 0 - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotConstant(): Boolean = !isConstant() - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNonZeroConstant(): Boolean = degree == 0 - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public fun P.isNotNonZeroConstant(): Boolean = !isNonZeroConstant() - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public fun P.asConstantOrNull(): C? - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public fun P.asConstant(): C = requireNotNull(asConstantOrNull()) { "Can not represent non-constant polynomial as a constant" } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. @@ -813,31 +687,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< @JvmName("constantPower") public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } - /** - * Check if the instant is zero constant. - */ - public override fun C.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero constant. - */ - public override fun C.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit constant. - */ - public override fun C.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit constant. - */ - public override fun C.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit constant. - */ - public override fun C.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit constant. - */ - public override fun C.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - /** * Instance of zero constant (zero of the underlying ring). */ @@ -907,31 +756,6 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } - /** - * Check if the instant is zero polynomial. - */ - public override fun P.isZero(): Boolean = polynomialRing { this@isZero.isZero() } - /** - * Check if the instant is NOT zero polynomial. - */ - public override fun P.isNotZero(): Boolean = polynomialRing { this@isNotZero.isNotZero() } - /** - * Check if the instant is unit polynomial. - */ - public override fun P.isOne(): Boolean = polynomialRing { this@isOne.isOne() } - /** - * Check if the instant is NOT unit polynomial. - */ - public override fun P.isNotOne(): Boolean = polynomialRing { this@isNotOne.isNotOne() } - /** - * Check if the instant is minus unit polynomial. - */ - public override fun P.isMinusOne(): Boolean = polynomialRing { this@isMinusOne.isMinusOne() } - /** - * Check if the instant is NOT minus unit polynomial. - */ - public override fun P.isNotMinusOne(): Boolean = polynomialRing { this@isNotMinusOne.isNotMinusOne() } - /** * Instance of zero polynomial (zero of the polynomial ring). */ @@ -941,47 +765,11 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< */ public override val polynomialOne: P get() = polynomialRing.one - /** - * Checks equality of the polynomials. - */ - public override infix fun P.equalsTo(other: P): Boolean = polynomialRing { this@equalsTo equalsTo other } - /** - * Checks NOT equality of the polynomials. - */ - public override infix fun P.notEqualsTo(other: P): Boolean = polynomialRing { this@notEqualsTo notEqualsTo other } - /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ public override val P.degree: Int get() = polynomialRing { this@degree.degree } - - /** - * Checks if the instant is constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isConstant(): Boolean = polynomialRing { this@isConstant.isConstant() } - /** - * Checks if the instant is **not** constant polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotConstant(): Boolean = polynomialRing { this@isNotConstant.isNotConstant() } - /** - * Checks if the instant is constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNonZeroConstant(): Boolean = polynomialRing { this@isNonZeroConstant.isNonZeroConstant() } - /** - * Checks if the instant is **not** constant non-zero polynomial (of degree no more than 0) over considered ring. - */ - public override fun P.isNotNonZeroConstant(): Boolean = polynomialRing { this@isNotNonZeroConstant.isNotNonZeroConstant() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) returns `null`. - */ - public override fun P.asConstantOrNull(): C? = polynomialRing { this@asConstantOrNull.asConstantOrNull() } - /** - * If polynomial is a constant polynomial represents and returns it as constant. - * Otherwise, (when the polynomial is not constant polynomial) raises corresponding exception. - */ - public override fun P.asConstant(): C = polynomialRing { this@asConstant.asConstant() } } /** @@ -1032,18 +820,11 @@ public abstract class PolynomialSpaceOfFractions< denominator ) - public override operator fun R.div(other: Int): R { - val otherAsConstant = constantNumber(other) - require(otherAsConstant.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: Int): R = + constructRationalFunction( numerator, - (denominator * other).also { - check(it.isNotZero()) { - "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other ) - } /** * Returns sum of the integer represented as rational function and the rational function. @@ -1076,13 +857,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) - public override operator fun Int.div(other: R): R { - require(other.numerator.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun Int.div(other: R): R = + constructRationalFunction( this * other.denominator, other.numerator ) - } /** * Converts the integer [value] to rational function. @@ -1119,13 +898,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) - public override operator fun C.div(other: R): R { - require(other.numerator.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun C.div(other: R): R = + constructRationalFunction( this * other.denominator, other.numerator ) - } /** * Returns sum of the constant represented as rational function and the rational function. @@ -1152,17 +929,11 @@ public abstract class PolynomialSpaceOfFractions< denominator ) - public override operator fun R.div(other: C): R { - require(other.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: C): R = + constructRationalFunction( numerator, - (denominator * other).also { - check(it.isNotZero()) { - "Got zero denominator during division of rational functions to constant. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other ) - } /** * Converts the constant [value] to rational function. @@ -1194,13 +965,11 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) - public override operator fun P.div(other: R): R { - require(other.numerator.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun P.div(other: R): R = + constructRationalFunction( this * other.denominator, other.numerator ) - } /** * Returns sum of the polynomial represented as rational function and the rational function. @@ -1227,17 +996,11 @@ public abstract class PolynomialSpaceOfFractions< denominator ) - public override operator fun R.div(other: P): R { - require(other.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: P): R = + constructRationalFunction( numerator, - (denominator * other).also { - require(it.isNotZero()) { - "Got zero denominator during division of rational functions to polynomial. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other ) - } /** * Converts the polynomial [value] to rational function. @@ -1254,11 +1017,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.plus(other: R): R = constructRationalFunction( numerator * other.denominator + denominator * other.numerator, - (denominator * other.denominator).also { - check(it.isNotZero()) { - "Got zero denominator during addition of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.denominator ) /** * Returns difference of the rational functions. @@ -1266,11 +1025,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.minus(other: R): R = constructRationalFunction( numerator * other.denominator - denominator * other.numerator, - (denominator * other.denominator).also { - check(it.isNotZero()) { - "Got zero denominator during subtraction of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.denominator ) /** * Returns product of the rational functions. @@ -1278,24 +1033,14 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun R.times(other: R): R = constructRationalFunction( numerator * other.numerator, - (denominator * other.denominator).also { - check(it.isNotZero()) { - "Got zero denominator during multiplication of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.denominator ) - public override operator fun R.div(other: R): R { - require(other.isNotZero()) { "/ by zero." } - return constructRationalFunction( + public override operator fun R.div(other: R): R = + constructRationalFunction( numerator * other.denominator, - (denominator * other.numerator).also { - check(it.isNotZero()) { - "Got zero denominator during division of rational functions. It means underlying ring of polynomials is not integral domain." - } - } + denominator * other.numerator ) - } /** * Instance of zero rational function (zero of the rational functions ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt index 35155d09d..50313cab9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt @@ -121,9 +121,9 @@ public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - val thisDegree = coefficients.indexOfLast { it != zero } + val thisDegree = coefficients.lastIndex if (thisDegree == -1) return ListPolynomial(emptyList()) - val argDegree = arg.coefficients.indexOfLast { it != zero } + val argDegree = arg.coefficients.lastIndex if (argDegree == -1) return coefficients[0].asListPolynomial() val constantZero = zero val resultCoefs: MutableList = MutableList(thisDegree * argDegree + 1) { constantZero } @@ -144,7 +144,6 @@ public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial(resultCoefs) } @@ -168,7 +167,6 @@ public fun ListPolynomial.derivative( ListPolynomial( buildList(max(0, coefficients.size - 1)) { for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } @@ -186,7 +184,6 @@ public fun ListPolynomial.nthDerivative( 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) }) - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } @@ -202,7 +199,6 @@ public fun ListPolynomial.antiderivative( buildList(coefficients.size + 1) { add(zero) coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } @@ -220,7 +216,6 @@ public fun ListPolynomial.nthAntiderivative( buildList(coefficients.size + order) { repeat(order) { add(zero) } coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - while (isNotEmpty() && elementAt(lastIndex) == algebra.zero) removeAt(lastIndex) } ) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt index 151c7bb8d..367212588 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt @@ -55,11 +55,11 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - val thisDegree = coefficients.indexOfLast { it != zero } + val thisDegree = coefficients.lastIndex if (thisDegree == -1) return ListPolynomial(emptyList()) val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() - val numeratorDegree = arg.numerator.coefficients.indexOfLast { it != zero } - val denominatorDegree = arg.denominator.coefficients.indexOfLast { it != zero } + val numeratorDegree = arg.numerator.coefficients.lastIndex + val denominatorDegree = arg.denominator.coefficients.lastIndex val argDegree = max(numeratorDegree, denominatorDegree) val constantZero = zero val powersOf2 = buildList(thisDegreeLog2 + 1) { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 0d2c4b5fc..ac2647592 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.test.misc.* import kotlin.test.* -class ListPolynomialTest { +class ListPolynomialTest { // TODO: Adapt tests to changes @Test fun test_Polynomial_Int_plus() { RationalField.listPolynomial { @@ -489,94 +489,6 @@ class ListPolynomialTest { } } @Test - fun test_Polynomial_isZero() { - RationalField.listPolynomial { - assertTrue("test 1") { ListPolynomial().isZero() } - assertTrue("test 2") { ListPolynomial(Rational(0)).isZero() } - assertTrue("test 3") { ListPolynomial(Rational(0), Rational(0)).isZero() } - assertTrue("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) - .isZero() } - assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isZero() } - assertFalse("test 6") { ListPolynomial(Rational(3, 5), Rational(0)) - .isZero() } - assertFalse("test 7") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) - .isZero() } - } - } - @Test - fun test_Polynomial_isOne() { - RationalField.listPolynomial { - assertFalse("test 1") { ListPolynomial().isOne() } - assertFalse("test 2") { ListPolynomial(Rational(0)).isOne() } - assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isOne() } - assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) - .isOne() } - assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isOne() } - assertTrue("test 6") { ListPolynomial(Rational(5, 5)).isOne() } - assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isOne() } - assertTrue("test 8") { ListPolynomial(Rational(3, 3), Rational(0)).isOne() } - assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) - .isOne() } - assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, 5), Rational(0)) - .isOne() } - assertFalse("test 11") { ListPolynomial(Rational(1), Rational(3, 5), Rational(0)) - .isOne() } - assertFalse("test 12") { ListPolynomial(Rational(1), Rational(5, 5), Rational(0)) - .isOne() } - } - } - @Test - fun test_Polynomial_isMinusOne() { - RationalField.listPolynomial { - assertFalse("test 1") { ListPolynomial().isMinusOne() } - assertFalse("test 2") { ListPolynomial(Rational(0)).isMinusOne() } - assertFalse("test 3") { ListPolynomial(Rational(0), Rational(0)).isMinusOne() } - assertFalse("test 4") { ListPolynomial(Rational(0), Rational(0), Rational(0)) - .isMinusOne() } - assertFalse("test 5") { ListPolynomial(Rational(3, 5)).isMinusOne() } - assertTrue("test 6") { ListPolynomial(Rational(-5, 5)).isMinusOne() } - assertFalse("test 7") { ListPolynomial(Rational(3, 5), Rational(0)).isMinusOne() } - assertTrue("test 8") { ListPolynomial(Rational(-3, 3), Rational(0)).isMinusOne() } - assertFalse("test 9") { ListPolynomial(Rational(0), Rational(3, 5), Rational(0)) - .isMinusOne() } - assertFalse("test 10") { ListPolynomial(Rational(0), Rational(5, -5), Rational(0)) - .isMinusOne() } - assertFalse("test 11") { ListPolynomial(Rational(-1), Rational(3, 5), Rational(0)) - .isMinusOne() } - assertFalse("test 12") { ListPolynomial(Rational(-1), Rational(5, -5), Rational(0)) - .isMinusOne() } - } - } - @Test - fun test_Polynomial_Polynomial_equalsTo() { - RationalField.listPolynomial { - assertTrue("test 1") { - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertTrue("test 2") { - ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertTrue("test 3") { - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)) - } - assertFalse("test 4") { - ListPolynomial(Rational(5, 9), Rational(5, 7), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - } - assertFalse("test 5") { - ListPolynomial(Rational(8, 3), Rational(0), Rational(-8, 7)) equalsTo - ListPolynomial(Rational(5, 9), Rational(0), Rational(-8, 7)) - } - assertFalse("test 6") { - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)) equalsTo - ListPolynomial(Rational(0), Rational(0), Rational(8, 7)) - } - } - } - @Test fun test_Polynomial_degree() { RationalField.listPolynomial { assertEquals( @@ -636,70 +548,4 @@ class ListPolynomialTest { ) } } - @Test - fun test_Polynomial_asConstantOrNull() { - RationalField.listPolynomial { - assertEquals( - Rational(0), - ListPolynomial().asConstantOrNull(), - "test 1" - ) - assertEquals( - Rational(0), - ListPolynomial(Rational(0)).asConstantOrNull(), - "test 2" - ) - assertEquals( - Rational(0), - ListPolynomial(Rational(0), Rational(0)).asConstantOrNull(), - "test 3" - ) - assertEquals( - Rational(0), - ListPolynomial(Rational(0), Rational(0), Rational(0)).asConstantOrNull(), - "test 4" - ) - assertEquals( - Rational(-7, 9), - ListPolynomial(Rational(-7, 9)).asConstantOrNull(), - "test 5" - ) - assertEquals( - Rational(-7, 9), - ListPolynomial(Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 6" - ) - assertEquals( - Rational(-7, 9), - ListPolynomial(Rational(-7, 9), Rational(0), Rational(0)).asConstantOrNull(), - "test 7" - ) - assertEquals( - null, - ListPolynomial(Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 8" - ) - assertEquals( - null, - ListPolynomial(Rational(0), Rational(-7, 9), Rational(0)).asConstantOrNull(), - "test 9" - ) - assertEquals( - null, - ListPolynomial(Rational(0), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 10" - ) - assertEquals( - null, - ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9)).asConstantOrNull(), - "test 11" - ) - assertEquals( - null, - ListPolynomial(Rational(4, 15), Rational(0), Rational(-7, 9), Rational(0)) - .asConstantOrNull(), - "test 12" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 50ae18260..c4f07d957 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -12,7 +12,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -class ListPolynomialUtilTest { +class ListPolynomialUtilTest { // TODO: Adapt tests to changes @Test fun test_substitute_Double() { assertEquals( From 7e328a5dbf936256a4612f582b5802b3d8e5a9aa Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 00:59:48 +0300 Subject: [PATCH 057/174] Enhanced DSL constructor a bit. --- .../space/kscience/kmath/functions/NumberedPolynomial.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 51f316c5d..f931e8e7e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -157,7 +157,8 @@ public class NumberedPolynomialTermSignatureBuilder { signature[this] = deg } } - public infix fun Int.to(deg: UInt): Unit = this inPowerOf deg + public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg } @NumberedPolynomialConstructorDSL @@ -168,6 +169,7 @@ public class NumberedPolynomialBuilderOverRing internal constructor(internal val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } } + public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) } @NumberedPolynomialConstructorDSL From f7286d33d27f9312f163106ef7f137cf594f1ff0 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 17:18:56 +0300 Subject: [PATCH 058/174] Moved constructors to separate files. Replaced some TODOs with FIXMEs. --- .../kmath/functions/LabeledPolynomial.kt | 96 --------- .../functions/LabeledRationalFunction.kt | 33 --- .../kmath/functions/ListPolynomial.kt | 18 -- .../kmath/functions/ListRationalFunction.kt | 33 --- .../kmath/functions/NumberedPolynomial.kt | 148 +------------- .../functions/NumberedRationalFunction.kt | 33 --- .../kmath/functions/RationalFunction.kt | 9 +- .../kscience/kmath/functions/algebraicStub.kt | 16 +- .../kmath/functions/labeledConstructors.kt | 147 ++++++++++++++ .../kmath/functions/listConstructors.kt | 60 ++++++ .../kmath/functions/numberedConstructors.kt | 188 ++++++++++++++++++ .../kmath/functions/numberedPolynomialUtil.kt | 33 --- 12 files changed, 408 insertions(+), 406 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 908e89534..b904f7331 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -8,10 +8,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName import kotlin.math.max @@ -49,98 +45,6 @@ internal constructor( override fun toString(): String = "LabeledPolynomial$coefficients" } -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - /** * Space of polynomials. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 0f46520dc..76c6874f5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -17,39 +17,6 @@ public class LabeledRationalFunction( override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - public class LabeledRationalFunctionSpace>( public val ring: A, ) : diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 711d2bb49..585da95ea 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -50,24 +50,6 @@ public data class ListPolynomial( override fun toString(): String = "Polynomial$coefficients" } -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) - /** * Space of univariate polynomials constructed over ring. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index f62d1857f..7b6c23ac3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -15,39 +15,6 @@ public data class ListRationalFunction( override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial(listOf(one)) - ) - public class ListRationalFunctionSpace> ( public val ring: A, ) : diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index f931e8e7e..e75373819 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -49,152 +49,6 @@ internal constructor( override fun toString(): String = "NumberedPolynomial$coefficients" } -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(NumberedPolynomialSpace) -//public fun > Symbol.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -//context(A) -//public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -internal annotation class NumberedPolynomialConstructorDSL - -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } - } - public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) -} - -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } - } -} - -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() - /** * Space of polynomials. * @@ -530,6 +384,6 @@ public open class NumberedPolynomialSpace>( @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - // TODO: Move to other constructors with context receiver + // FIXME: Move to other constructors with context receiver public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index b4d9f1d91..30c7f0188 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -17,39 +17,6 @@ public class NumberedRationalFunction internal constructor( override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" } -// Waiting for context receivers :( TODO: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - public class NumberedRationalFunctionSpace> ( public val ring: A, ) : diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 374f4a936..eede543ee 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -27,7 +27,7 @@ public interface RationalFunction> { * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** @@ -457,7 +457,7 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. * @param A the type of algebraic structure (precisely, of ring) provided for constants. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME") public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { @@ -551,7 +551,7 @@ public interface RationalFunctionalSpaceOverRing, R: Rationa * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME") public interface RationalFunctionalSpaceOverPolynomialSpace< C, @@ -779,8 +779,7 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. - * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. - */ // TODO: Add support of field + */ @Suppress("INAPPLICABLE_JVM_NAME") public abstract class PolynomialSpaceOfFractions< C, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index ca93e4259..fa97d6a6c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.* // TODO: All of this should be moved to algebraic structures' place for utilities -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Returns product of [arg] and integer [multiplier]. * @@ -22,7 +22,7 @@ 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 +// FIXME: Move receiver to context receiver /** * Adds product of [arg] and [multiplier] to [base]. * @@ -36,7 +36,7 @@ internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier if (multiplier >= 0) addMultipliedBySquaring(base, arg, multiplier.toUInt()) else addMultipliedBySquaring(base, -arg, (-multiplier).toUInt()) -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Returns product of [arg] and integer [multiplier]. * @@ -56,7 +56,7 @@ internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): 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 +// FIXME: Move receiver to context receiver /** * Adds product of [arg] and [multiplier] to [base]. * @@ -77,7 +77,7 @@ internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, mu 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 +// FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. * @@ -90,7 +90,7 @@ 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 +// FIXME: Move receiver to context receiver /** * Multiplies [base] and [arg] raised to the integer power [exponent]. * @@ -104,7 +104,7 @@ internal fun Field.multiplyExponentiationBySquaring(base: C, arg: C, expo if (exponent >= 0) multiplyExponentiationBySquaring(base, arg, exponent.toUInt()) else multiplyExponentiationBySquaring(base, one / arg, (-exponent).toUInt()) -// TODO: Move receiver to context receiver +// FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. * @@ -124,7 +124,7 @@ internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt 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 +// FIXME: Move receiver to context receiver /** * Multiplies [base] and [arg] raised to the integer power [exponent]. * diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt new file mode 100644 index 000000000..12688a865 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -0,0 +1,147 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(coefs) + + val fixedCoefs = LinkedHashMap, C>(coefs.size) + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = LinkedHashMap, C>(pairs.size) + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { + if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) + + val fixedCoefs = LinkedHashMap, C>(pairs.size) + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return LabeledPolynomial(fixedCoefs) +} + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) + +//context(A) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +//context(LabeledPolynomialSpace) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) +@Suppress("FunctionName") +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients, toCheckInput = true), + LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) + ) + +//context(A) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) + +//context(A) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) +//context(LabeledRationalFunctionSpace) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt new file mode 100644 index 000000000..9498c77ca --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring + + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) + +//context(A) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +//context(ListRationalFunctionSpace) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt new file mode 100644 index 000000000..e4b79b0b2 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -0,0 +1,188 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke + + +/** + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(coefs) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial(fixedCoefs) +} + +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName", "NOTHING_TO_INLINE") +internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) +@Suppress("FunctionName") +internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { + if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) + + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value + } + + return NumberedPolynomial(fixedCoefs) +} + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) + +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) + +public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) + +@DslMarker +internal annotation class NumberedPolynomialConstructorDSL + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + private val signature: MutableList = ArrayList() + public fun build(): List = signature + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] = deg + } + } + public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } + } + public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) +} + +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { + val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } + } +} + +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() +@NumberedPolynomialConstructorDSL +@Suppress("FunctionName") +public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(denominatorCoefficients, toCheckInput = true) + ) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients, toCheckInput = true), + NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) + ) + +//context(A) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) +//context(NumberedRationalFunctionSpace) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file 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 d544ca93c..ee85b0f56 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 @@ -9,38 +9,6 @@ import kotlin.math.max // TODO: Docs -//// TODO: Reuse underlying ring extensions -// -//context(NumberedPolynomialSpace) -//@Suppress("NOTHING_TO_INLINE") -//public fun > numberConstant(value: Int): C = ring { number(value) } -// -//context(NumberedPolynomialSpace) -//public fun > multiplyWithPower(base: C, arg: C, pow: UInt): C = ring { multiplyWithPower(base, arg, pow) } - -//context(NumberedPolynomialSpace) -//public fun > number(value: Int): NumberedPolynomial = ring { NumberedPolynomial(mapOf(emptyList() to number(value))) } -// -//context(NumberedPolynomialSpace) -//public fun > multiplyWithPower(base: NumberedPolynomial, arg: NumberedPolynomial, pow: UInt): NumberedPolynomial = -// when { -// arg.isZero() && pow > 0U -> base -// arg.isOne() -> base -// arg.isMinusOne() -> if (pow % 2U == 0U) base else -base -// else -> multiplyWithPowerInternalLogic(base, arg, pow) -// } -// -//// Trivial but very slow -//context(NumberedPolynomialSpace) -//internal tailrec fun > multiplyWithPowerInternalLogic(base: NumberedPolynomial, arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = -// when { -// exponent == 0U -> base -// exponent == 1U -> base * arg -// exponent % 2U == 0U -> multiplyWithPowerInternalLogic(base, arg * arg, exponent / 2U) -// exponent % 2U == 1U -> multiplyWithPowerInternalLogic(base * arg, arg * arg, exponent / 2U) -// else -> error("Error in raising ring instant by unsigned integer: got reminder by division by 2 different from 0 and 1") -// } - /** * Creates a [NumberedPolynomialSpace] over a received ring. */ @@ -271,7 +239,6 @@ public inline fun , R> A.numberedPolynomial(block: NumberedPolyno // toCheckInput = false // ) -// TODO: May be apply Horner's method too? /** * Evaluates the value of the given double polynomial for given double argument. */ From b3087c245fc0da2631e9e53211e97dd47e1d1983 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 25 Mar 2022 17:46:13 +0300 Subject: [PATCH 059/174] Fixed tests. --- .../kmath/functions/ListPolynomialTest.kt | 108 ++++-------------- .../kmath/functions/ListPolynomialUtilTest.kt | 16 +-- .../kscience/kmath/test/misc/IntModulo.kt | 2 +- 3 files changed, 33 insertions(+), 93 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index ac2647592..5401be707 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.test.misc.* import kotlin.test.* -class ListPolynomialTest { // TODO: Adapt tests to changes +class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { RationalField.listPolynomial { @@ -24,7 +24,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(-2)) + 2, "test 3" ) @@ -64,7 +64,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(2)) - 2, "test 3" ) @@ -99,7 +99,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 1" ) assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), ListPolynomial(7, 0, 49, 21, 14) * 15, "test 2" ) @@ -119,7 +119,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), 2 + ListPolynomial(Rational(-2)), "test 3" ) @@ -159,7 +159,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), -2 - ListPolynomial(Rational(-2)), "test 3" ) @@ -194,7 +194,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 1" ) assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) @@ -214,12 +214,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(-2)) + Rational(2), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial() + Rational(0), "test 4" ) @@ -254,12 +254,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(2)) - Rational(2), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial() - Rational(0), "test 4" ) @@ -285,12 +285,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes IntModuloRing(35).listPolynomial { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * number(27), + ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), "test 1" ) assertEquals( - ListPolynomial(), - ListPolynomial(7, 0, 49, 21, 14) * number(15), + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), "test 2" ) } @@ -309,12 +309,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(2) + ListPolynomial(Rational(-2)), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(0) + ListPolynomial(), "test 4" ) @@ -349,12 +349,12 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 2" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(-2) - ListPolynomial(Rational(-2)), "test 3" ) assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), Rational(0) - ListPolynomial(), "test 4" ) @@ -384,7 +384,7 @@ class ListPolynomialTest { // TODO: Adapt tests to changes "test 1" ) assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) @@ -424,14 +424,14 @@ class ListPolynomialTest { // TODO: Adapt tests to changes ) // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 assertEquals( - ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3)), + ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), "test 3" ) // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), "test 4" @@ -457,14 +457,14 @@ class ListPolynomialTest { // TODO: Adapt tests to changes ) // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 assertEquals( - ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3)), + ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), "test 3" ) // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), "test 4" @@ -482,70 +482,10 @@ class ListPolynomialTest { // TODO: Adapt tests to changes ) // Spoiler: 5 * 7 = 0 assertEquals( - ListPolynomial(), + ListPolynomial(0, 0, 0, 0, 0), ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), "test 2" ) } } - @Test - fun test_Polynomial_degree() { - RationalField.listPolynomial { - assertEquals( - 2, - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)).degree, - "test 1" - ) - assertEquals( - -1, - ListPolynomial().degree, - "test 2" - ) - assertEquals( - -1, - ListPolynomial(Rational(0)).degree, - "test 3" - ) - assertEquals( - -1, - ListPolynomial(Rational(0), Rational(0)).degree, - "test 4" - ) - assertEquals( - -1, - ListPolynomial(Rational(0), Rational(0), Rational(0)).degree, - "test 5" - ) - assertEquals( - 0, - ListPolynomial(Rational(5, 9)).degree, - "test 6" - ) - assertEquals( - 0, - ListPolynomial(Rational(5, 9), Rational(0)).degree, - "test 7" - ) - assertEquals( - 0, - ListPolynomial(Rational(5, 9), Rational(0), Rational(0)).degree, - "test 8" - ) - assertEquals( - 2, - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7)).degree, - "test 9" - ) - assertEquals( - 2, - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 10" - ) - assertEquals( - 2, - ListPolynomial(Rational(0), Rational(0), Rational(-8, 7), Rational(0), Rational(0)).degree, - "test 11" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c4f07d957..c5eb8fb81 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -12,7 +12,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -class ListPolynomialUtilTest { // TODO: Adapt tests to changes +class ListPolynomialUtilTest { @Test fun test_substitute_Double() { assertEquals( @@ -81,7 +81,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes @Test fun test_substitute_Polynomial() { assertEquals( - ListPolynomial(), + ListPolynomial(Rational(0)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), "test 1" ) @@ -98,7 +98,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 3" ) assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75)), + ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), "test 4" @@ -110,7 +110,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 5" ) assertEquals( - ListPolynomial(Rational(89, 54)), + ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), "test 6" @@ -134,7 +134,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 3" ) assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7)), + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), "test 4" ) @@ -180,7 +180,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 8" ) assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7)), + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), "test 9" ) @@ -203,7 +203,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 3" ) assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28)), + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), "test 4" ) @@ -249,7 +249,7 @@ class ListPolynomialUtilTest { // TODO: Adapt tests to changes "test 8" ) assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28)), + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), "test 9" ) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 535a42846..2353beee6 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -120,7 +120,7 @@ class IntModuloRing : Ring { } override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) From 7f7b55067422589bc9266f2d7ebc0e8af5b8e402 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 3 Apr 2022 11:44:42 +0300 Subject: [PATCH 060/174] Simplified polynomial builders. --- .../kmath/functions/labeledConstructors.kt | 56 +++++++++++++++++++ .../kmath/functions/numberedConstructors.kt | 47 +++++++++------- 2 files changed, 83 insertions(+), 20 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 12688a865..e81a9388e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -103,6 +104,61 @@ public fun > LabeledRationalFunctionSpace.LabeledPolynomial( public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialConstructorDSL + +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +public class LabeledPolynomialTermSignatureBuilder { + private val signature: MutableMap = LinkedHashMap() + public fun build(): Map = signature + public infix fun Symbol.inPowerOf(deg: UInt) { + signature[this] = deg + } + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg +} + +@UnstableKMathAPI +public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { + private val coefficients: MutableMap, C> = LinkedHashMap(capacity) + public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { + val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() + coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) + } + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + @Suppress("NOTHING_TO_INLINE") + public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) + @Suppress("NOTHING_TO_INLINE") + public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +@Suppress("FunctionName") +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() + // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @Suppress("FunctionName") diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index e4b79b0b2..dca8a0cff 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -5,8 +5,8 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke /** @@ -97,8 +97,10 @@ public fun > NumberedRationalFunctionSpace.NumberedPolynomia public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) @DslMarker +@UnstableKMathAPI internal annotation class NumberedPolynomialConstructorDSL +@UnstableKMathAPI @NumberedPolynomialConstructorDSL public class NumberedPolynomialTermSignatureBuilder { private val signature: MutableList = ArrayList() @@ -111,43 +113,48 @@ public class NumberedPolynomialTermSignatureBuilder { signature[this] = deg } } - public infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - public infix fun Int.of(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg } -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverRing internal constructor(internal val context: Ring, capacity: Int = 0) { +@UnstableKMathAPI +public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { private val coefficients: MutableMap, C> = LinkedHashMap(capacity) public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { zero } + this@invoke } + coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) } - public infix fun C.with(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + @Suppress("NOTHING_TO_INLINE") + public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) + @Suppress("NOTHING_TO_INLINE") + public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block } -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilderOverPolynomialSpace internal constructor(internal val context: NumberedPolynomialSpace, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = context { coefficients.getOrElse(signature) { constantZero } + this@invoke } - } -} +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > A.NumberedPolynomial(block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this).apply(block).build() +public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverRing.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverRing(this, capacity).apply(block).build() +public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() +@UnstableKMathAPI @NumberedPolynomialConstructorDSL @Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilderOverPolynomialSpace.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilderOverPolynomialSpace(this, capacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available From 5a36c3e03c60ffe02b7e7ea5609843b6f3a4155d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 13 Apr 2022 11:20:11 +0300 Subject: [PATCH 061/174] Remove metaspace memory allocation key --- gradle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 80108737e..4923364d8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,5 +9,4 @@ kotlin.native.ignoreDisabledTargets=true #kotlin.incremental.js.ir=true org.gradle.configureondemand=true -org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G org.gradle.parallel=true From c28be8322697c72237544522d8a8c143f688979d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 8 Jun 2022 09:00:37 +0300 Subject: [PATCH 062/174] LazyStructire::deferred -> async --- CHANGELOG.md | 2 ++ build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 1 + buildSrc/gradle.properties | 2 +- .../kscience/kmath/nd/VirtualStructureND.kt | 16 ++++++++++++++++ .../kscience/kmath/structures/LazyStructureND.kt | 10 +++++----- 6 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 75833602c..c4b8c06cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Added ### Changed +- Kotlin 1.7 +- `LazyStructure` `deffered` -> `async` to comply with coroutines code style ### Deprecated diff --git a/build.gradle.kts b/build.gradle.kts index 10f2385f5..9fa012fb2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ allprojects { } group = "space.kscience" - version = "0.3.0" + version = "0.3.1" } subprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index fa5142538..dcb39d448 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + kotlin("jvm") version "1.7.0-RC" `kotlin-dsl` `version-catalog` alias(miptNpmLibs.plugins.kotlin.plugin.serialization) diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties index a0b05e812..751caec36 100644 --- a/buildSrc/gradle.properties +++ b/buildSrc/gradle.properties @@ -4,4 +4,4 @@ # kotlin.code.style=official -toolsVersion=0.11.2-kotlin-1.6.10 +toolsVersion=0.11.5-kotlin-1.7.0-RC diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt new file mode 100644 index 000000000..799d14b3d --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt @@ -0,0 +1,16 @@ +/* + * 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.nd + +public open class VirtualStructureND( + override val shape: Shape, + public val producer: (IntArray) -> T, +) : StructureND { + override fun get(index: IntArray): T { + require(check that index is in the shape boundaries) + return producer(index) + } +} \ No newline at end of file diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt index ac9eb773a..2b9265843 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt @@ -18,12 +18,12 @@ public class LazyStructureND( ) : StructureND { private val cache: MutableMap> = HashMap() - public fun deferred(index: IntArray): Deferred = cache.getOrPut(index) { + public fun async(index: IntArray): Deferred = cache.getOrPut(index) { scope.async(context = Dispatchers.Math) { function(index) } } - public suspend fun await(index: IntArray): T = deferred(index).await() - override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } + public suspend fun await(index: IntArray): T = async(index).await() + override operator fun get(index: IntArray): T = runBlocking { async(index).await() } @OptIn(PerformancePitfall::class) override fun elements(): Sequence> { @@ -33,8 +33,8 @@ public class LazyStructureND( } } -public fun StructureND.deferred(index: IntArray): Deferred = - if (this is LazyStructureND) deferred(index) else CompletableDeferred(get(index)) +public fun StructureND.async(index: IntArray): Deferred = + if (this is LazyStructureND) this@async.async(index) else CompletableDeferred(get(index)) public suspend fun StructureND.await(index: IntArray): T = if (this is LazyStructureND) await(index) else get(index) From de9f3cc8df4ebb0c05ee81d6a77922174e8d532c Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 10 Jun 2022 23:37:50 +0300 Subject: [PATCH 063/174] Inlined LaTeX formula. Now GitHub supports MathJax! --- kmath-ast/README.md | 5 +---- kmath-ast/docs/README-TEMPLATE.md | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 5d5630f46..cc5f5b764 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -199,10 +199,7 @@ public fun main() { Result LaTeX: -

- -![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) -
+$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\,x\right)}{2\times10^{10}%2Bx^{3}}}{12}+x^{2/3}$$ Result MathML (can be used with MathJax or other renderers): diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index e9e22f4d4..1f14deaba 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -170,10 +170,7 @@ public fun main() { Result LaTeX: -
- -![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) -
+$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\,x\right)}{2\times10^{10}%2Bx^{3}}}{12}+x^{2/3}$$ Result MathML (can be used with MathJax or other renderers): From b92ef23f5d3ec2c2578abc6f8734a12cd837bbf9 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 00:06:45 +0300 Subject: [PATCH 064/174] Some fixes --- kmath-ast/README.md | 2 +- kmath-ast/docs/README-TEMPLATE.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index cc5f5b764..553c60bb3 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -199,7 +199,7 @@ public fun main() { Result LaTeX: -$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\,x\right)}{2\times10^{10}%2Bx^{3}}}{12}+x^{2/3}$$ +$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$ Result MathML (can be used with MathJax or other renderers): diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index 1f14deaba..96bbfbf5a 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -170,7 +170,7 @@ public fun main() { Result LaTeX: -$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\,x\right)}{2\times10^{10}%2Bx^{3}}}{12}+x^{2/3}$$ +$$\operatorname{exp}\\,\left(\sqrt{x}\right)-\frac{\frac{\operatorname{arcsin}\\,\left(2\\,x\right)}{2\times10^{10}+x^{3}}}{12}+x^{2/3}$$ Result MathML (can be used with MathJax or other renderers): From 89cdbf4d71f188105f12bb9029dc3c0f40a87360 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 15:58:25 +0300 Subject: [PATCH 065/174] Changed names of algebraic stub. Added FIXMEs about KT-31420. Changed JVM/JS names style. --- .../kscience/kmath/functions/Polynomial.kt | 112 +++++----- .../kmath/functions/RationalFunction.kt | 208 +++++++++--------- .../kscience/kmath/functions/algebraicStub.kt | 48 ++-- .../kmath/functions/labeledPolynomialUtil.kt | 16 +- .../kmath/functions/numberedPolynomialUtil.kt | 16 +- .../kmath/functions/AlgebraicStubTest.kt | 208 +++++++++--------- 6 files changed, 304 insertions(+), 304 deletions(-) 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 96e860550..e201f1f6e 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 @@ -22,7 +22,7 @@ public interface Polynomial * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). @@ -76,38 +76,38 @@ public interface PolynomialSpace> : Ring

{ * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun P.plus(other: Int): P = addMultipliedBySquaring(this, one, other) + public operator fun P.plus(other: Int): P = addMultipliedByDoubling(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 = addMultipliedBySquaring(this, one, -other) + public operator fun P.minus(other: Int): P = addMultipliedByDoubling(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 = multiplyBySquaring(this, other) + public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** * Returns sum of the integer represented as polynomial and the polynomial. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: P): P = addMultipliedBySquaring(other, one, this) + public operator fun Int.plus(other: P): P = addMultipliedByDoubling(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 = addMultipliedBySquaring(-other, one, this) + public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-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 = multiplyBySquaring(other, this) + public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) /** * Converts the integer [value] to polynomial. @@ -121,38 +121,38 @@ public interface PolynomialSpace> : Ring

{ /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") + @JvmName("unaryPlusConstant") + @JsName("unaryPlusConstant") public operator fun C.unaryPlus(): C = this /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") + @JvmName("unaryMinusConstant") + @JsName("unaryMinusConstant") public operator fun C.unaryMinus(): C /** * Returns sum of the constants. */ - @JvmName("constantPlus") - @JsName("constantPlus") + @JvmName("plusConstantConstant") + @JsName("plusConstantConstant") public operator fun C.plus(other: C): C /** * Returns difference of the constants. */ - @JvmName("constantMinus") - @JsName("constantMinus") + @JvmName("minusConstantConstant") + @JsName("minusConstantConstant") public operator fun C.minus(other: C): C /** * Returns product of the constants. */ - @JvmName("constantTimes") - @JsName("constantTimes") + @JvmName("timesConstantConstant") + @JsName("timesConstantConstant") public operator fun C.times(other: C): C /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") - @JsName("constantPower") + @JvmName("powerConstant") + @JsName("powerConstant") public fun power(arg: C, exponent: UInt) : C /** @@ -222,7 +222,7 @@ public interface PolynomialSpace> : Ring

{ /** * Raises [arg] to the integer power [exponent]. */ - public override fun power(arg: P, exponent: UInt) : P = exponentiationBySquaring(arg, exponent) + public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -251,7 +251,7 @@ public interface PolynomialSpace> : Ring

{ * @param P the type of polynomials. * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { public val ring: A @@ -261,63 +261,63 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly * * 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 { addMultipliedBySquaring(this@plus, one, other) } + public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as 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 { addMultipliedBySquaring(this@minus, one, -other) } + public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as 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 { multiplyBySquaring(this@times, other) } + public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } + public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(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 { addMultipliedBySquaring(-other, one, this@minus) } + public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-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 { multiplyBySquaring(other, this@times) } + public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") + @JvmName("unaryMinusConstant") public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } /** * Returns sum of the constants. */ - @JvmName("constantPlus") + @JvmName("plusConstantConstant") public override operator fun C.plus(other: C): C = ring { this@plus + other } /** * Returns difference of the constants. */ - @JvmName("constantMinus") + @JvmName("minusConstantConstant") public override operator fun C.minus(other: C): C = ring { this@minus - other } /** * Returns product of the constants. */ - @JvmName("constantTimes") + @JvmName("timesConstantConstant") public override operator fun C.times(other: C): C = ring { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") + @JvmName("powerConstant") override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } /** @@ -330,59 +330,59 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { - @JvmName("VariableIntPlus") + @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P - @JvmName("VariableIntMinus") + @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P - @JvmName("VariableIntMinusTimes") + @JvmName("timesVariableInt") public operator fun V.times(other: Int): P - @JvmName("IntVariablePlus") + @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P - @JvmName("IntVariableMinus") + @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P - @JvmName("IntVariableTimes") + @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("ConstantVariablePlus") + @JvmName("plusConstantVariable") public operator fun C.plus(other: V): P - @JvmName("ConstantVariableMinus") + @JvmName("minusConstantVariable") public operator fun C.minus(other: V): P - @JvmName("ConstantVariableTimes") + @JvmName("timesConstantVariable") public operator fun C.times(other: V): P - @JvmName("VariableConstantPlus") + @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P - @JvmName("VariableConstantMinus") + @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P - @JvmName("VariableConstantTimes") + @JvmName("timesVariableConstant") public operator fun V.times(other: C): P - @JvmName("VariableUnaryPlus") + @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P - @JvmName("VariableUnaryMinus") + @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P - @JvmName("VariablePlus") + @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P - @JvmName("VariableMinus") + @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P - @JvmName("VariableTimes") + @JvmName("timesVariableVariable") public operator fun V.times(other: V): P - @JvmName("VariablePolynomialPlus") + @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P - @JvmName("VariablePolynomialMinus") + @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P - @JvmName("VariablePolynomialTimes") + @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P - @JvmName("PolynomialVariablePlus") + @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P - @JvmName("PolynomialVariableMinus") + @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P - @JvmName("PolynomialVariableTimes") + @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index eede543ee..dfec126f3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -28,7 +28,7 @@ public interface RationalFunction> { * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** * Returns sum of the constant and the integer represented as constant (member of underlying ring). @@ -129,52 +129,52 @@ public interface RationalFunctionalSpace, R: RationalFunctio * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ - public operator fun R.plus(other: Int): R = addMultipliedBySquaring(this, one, other) + public operator fun R.plus(other: Int): R = addMultipliedByDoubling(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 = addMultipliedBySquaring(this, one, -other) + public operator fun R.minus(other: Int): R = addMultipliedByDoubling(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 = multiplyBySquaring(this, other) + public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** * Returns quotient of the rational function and the integer represented as rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. */ - public operator fun R.div(other: Int): R = this / multiplyBySquaring(one, other) + public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** * Returns sum of the integer represented as rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ - public operator fun Int.plus(other: R): R = addMultipliedBySquaring(other, one, this) + public operator fun Int.plus(other: R): R = addMultipliedByDoubling(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 = addMultipliedBySquaring(-other, one, this) + public operator fun Int.minus(other: R): R = addMultipliedByDoubling(-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 = multiplyBySquaring(other, this) + public operator fun Int.times(other: R): R = multiplyByDoubling(other, this) /** * Returns quotient of the integer represented as rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. */ - public operator fun Int.div(other: R): R = multiplyBySquaring(one / other, this) + public operator fun Int.div(other: R): R = multiplyByDoubling(one / other, this) /** * Converts the integer [value] to rational function. @@ -188,38 +188,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") - @JsName("constantUnaryPlus") + @JvmName("unaryPlusConstant") + @JsName("unaryPlusConstant") public operator fun C.unaryPlus(): C = this /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") - @JsName("constantUnaryMinus") + @JvmName("unaryMinusConstant") + @JsName("unaryMinusConstant") public operator fun C.unaryMinus(): C /** * Returns sum of the constants. */ - @JvmName("constantPlus") - @JsName("constantPlus") + @JvmName("plusConstantConstant") + @JsName("plusConstantConstant") public operator fun C.plus(other: C): C /** * Returns difference of the constants. */ - @JvmName("constantMinus") - @JsName("constantMinus") + @JvmName("minusConstantConstant") + @JsName("minusConstantConstant") public operator fun C.minus(other: C): C /** * Returns product of the constants. */ - @JvmName("constantTimes") - @JsName("constantTimes") + @JvmName("timesConstantConstant") + @JsName("timesConstantConstant") public operator fun C.times(other: C): C /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") - @JsName("constantPower") + @JvmName("powerConstant") + @JsName("powerConstant") public fun power(arg: C, exponent: UInt) : C /** @@ -417,7 +417,7 @@ public interface RationalFunctionalSpace, R: RationalFunctio /** * Raises [arg] to the integer power [exponent]. */ - public override fun power(arg: R, exponent: UInt) : R = exponentiationBySquaring(arg, exponent) + public override fun power(arg: R, exponent: UInt) : R = exponentiateBySquaring(arg, exponent) /** * Instance of zero rational function (zero of the rational functions ring). @@ -458,7 +458,7 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param R the type of rational functions. * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { public val ring: A @@ -468,68 +468,68 @@ public interface RationalFunctionalSpaceOverRing, R: Rationa * * 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 { addMultipliedBySquaring(this@plus, one, other) } + public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as 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 { addMultipliedBySquaring(this@minus, one, -other) } + public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as 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 { multiplyBySquaring(this@times, other) } + public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** * Returns sum of the integer represented as constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedBySquaring(other, one, this@plus) } + public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(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 { addMultipliedBySquaring(-other, one, this@minus) } + public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-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 { multiplyBySquaring(other, this@times) } + public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") + @JvmName("unaryPlusConstant") public override operator fun C.unaryPlus(): C = ring { +this@unaryPlus } /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") + @JvmName("unaryMinusConstant") public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } /** * Returns sum of the constants. */ - @JvmName("constantPlus") + @JvmName("plusConstantConstant") public override operator fun C.plus(other: C): C = ring { this@plus + other } /** * Returns difference of the constants. */ - @JvmName("constantMinus") + @JvmName("minusConstantConstant") public override operator fun C.minus(other: C): C = ring { this@minus - other } /** * Returns product of the constants. */ - @JvmName("constantTimes") + @JvmName("timesConstantConstant") public override operator fun C.times(other: C): C = ring { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") + @JvmName("powerConstant") public override fun power(arg: C, exponent: UInt) : C = ring { power(arg, exponent) } /** @@ -552,7 +552,7 @@ public interface RationalFunctionalSpaceOverRing, R: Rationa * @param R the type of rational functions. * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpaceOverPolynomialSpace< C, P: Polynomial, @@ -659,32 +659,32 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Returns the same constant. */ - @JvmName("constantUnaryPlus") + @JvmName("unaryPlusConstant") public override operator fun C.unaryPlus(): C = polynomialRing { +this@unaryPlus } /** * Returns negation of the constant. */ - @JvmName("constantUnaryMinus") + @JvmName("unaryMinusConstant") public override operator fun C.unaryMinus(): C = polynomialRing { -this@unaryMinus } /** * Returns sum of the constants. */ - @JvmName("constantPlus") + @JvmName("plusConstantConstant") public override operator fun C.plus(other: C): C = polynomialRing { this@plus + other } /** * Returns difference of the constants. */ - @JvmName("constantMinus") + @JvmName("minusConstantConstant") public override operator fun C.minus(other: C): C = polynomialRing { this@minus - other } /** * Returns product of the constants. */ - @JvmName("constantTimes") + @JvmName("timesConstantConstant") public override operator fun C.times(other: C): C = polynomialRing { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ - @JvmName("constantPower") + @JvmName("powerConstant") public override fun power(arg: C, exponent: UInt) : C = polynomialRing { power(arg, exponent) } /** @@ -780,7 +780,7 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. * @param R the type of rational functions. */ -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class PolynomialSpaceOfFractions< C, P: Polynomial, @@ -1052,78 +1052,78 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, V, P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { - @JvmName("VariableIntPlus") + @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P - @JvmName("VariableIntMinus") + @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P - @JvmName("VariableIntMinusTimes") + @JvmName("timesVariableInt") public operator fun V.times(other: Int): P - @JvmName("IntVariablePlus") + @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P - @JvmName("IntVariableMinus") + @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P - @JvmName("IntVariableTimes") + @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("ConstantVariablePlus") + @JvmName("plusConstantVariable") public operator fun C.plus(other: V): P - @JvmName("ConstantVariableMinus") + @JvmName("minusConstantVariable") public operator fun C.minus(other: V): P - @JvmName("ConstantVariableTimes") + @JvmName("timesConstantVariable") public operator fun C.times(other: V): P - @JvmName("VariableConstantPlus") + @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P - @JvmName("VariableConstantMinus") + @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P - @JvmName("VariableConstantTimes") + @JvmName("timesVariableConstant") public operator fun V.times(other: C): P - @JvmName("VariableUnaryPlus") + @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P - @JvmName("VariableUnaryMinus") + @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P - @JvmName("VariablePlus") + @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P - @JvmName("VariableMinus") + @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P - @JvmName("VariableTimes") + @JvmName("timesVariableVariable") public operator fun V.times(other: V): P - @JvmName("VariablePolynomialPlus") + @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P - @JvmName("VariablePolynomialMinus") + @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P - @JvmName("VariablePolynomialTimes") + @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P - @JvmName("PolynomialVariablePlus") + @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P - @JvmName("PolynomialVariableMinus") + @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P - @JvmName("PolynomialVariableTimes") + @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P - @JvmName("VariableRationalFunctionPlus") + @JvmName("plusVariableRational") public operator fun V.plus(other: R): R - @JvmName("VariableRationalFunctionMinus") + @JvmName("minusVariableRational") public operator fun V.minus(other: R): R - @JvmName("VariableRationalFunctionTimes") + @JvmName("timesVariableRational") public operator fun V.times(other: R): R - @JvmName("RationalFunctionVariablePlus") + @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R - @JvmName("RationalFunctionVariableMinus") + @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R - @JvmName("RationalFunctionVariableTimes") + @JvmName("timesRationalVariable") public operator fun R.times(other: V): R /** @@ -1177,7 +1177,7 @@ public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, V, @@ -1185,57 +1185,57 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp R: RationalFunction, AP: MultivariatePolynomialSpace, > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { - @JvmName("VariableIntPlus") + @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } - @JvmName("VariableIntMinus") + @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } - @JvmName("VariableIntMinusTimes") + @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } - @JvmName("IntVariablePlus") + @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("IntVariableMinus") + @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("IntVariableTimes") + @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("ConstantVariablePlus") + @JvmName("plusConstantVariable") public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("ConstantVariableMinus") + @JvmName("minusConstantVariable") public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("ConstantVariableTimes") + @JvmName("timesConstantVariable") public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - @JvmName("VariableConstantPlus") + @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } - @JvmName("VariableConstantMinus") + @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } - @JvmName("VariableConstantTimes") + @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } - @JvmName("VariableUnaryPlus") + @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } - @JvmName("VariableUnaryMinus") + @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } - @JvmName("VariablePlus") + @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("VariableMinus") + @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("VariableTimes") + @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } - @JvmName("VariablePolynomialPlus") + @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } - @JvmName("VariablePolynomialMinus") + @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } - @JvmName("VariablePolynomialTimes") + @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } - @JvmName("PolynomialVariablePlus") + @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("PolynomialVariableMinus") + @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("PolynomialVariableTimes") + @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } /** @@ -1264,45 +1264,45 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } -@Suppress("INAPPLICABLE_JVM_NAME") +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, V, P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { - @JvmName("VariableRationalFunctionPlus") + @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) - @JvmName("VariableRationalFunctionMinus") + @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) - @JvmName("VariableRationalFunctionTimes") + @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - @JvmName("RationalFunctionVariablePlus") + @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) - @JvmName("RationalFunctionVariableMinus") + @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) - @JvmName("RationalFunctionVariableTimes") + @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( numerator * other, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index fa97d6a6c..b40aa4775 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -18,9 +18,9 @@ import space.kscience.kmath.operations.* * @return product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = - if (multiplier >= 0) multiplyBySquaring(arg, multiplier.toUInt()) - else multiplyBySquaring(-arg, (-multiplier).toUInt()) +internal fun Group.multiplyByDoubling(arg: C, multiplier: Int): C = + if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt()) + else multiplyByDoubling(-arg, (-multiplier).toUInt()) // FIXME: Move receiver to context receiver /** @@ -32,9 +32,9 @@ internal fun Group.multiplyBySquaring(arg: C, multiplier: Int): C = * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -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()) +internal fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt()) + else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt()) // FIXME: Move receiver to context receiver /** @@ -47,12 +47,12 @@ internal fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier * @return product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): C = +internal tailrec fun Group.multiplyByDoubling(arg: C, multiplier: UInt): C = when { 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) + multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } @@ -68,12 +68,12 @@ internal tailrec fun Group.multiplyBySquaring(arg: C, multiplier: UInt): * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. * @author Gleb Minaev */ -internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, multiplier: UInt): C = +internal tailrec fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C = when { multiplier == 0u -> base multiplier == 1u -> base + arg - multiplier and 1u == 0u -> addMultipliedBySquaring(base, arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedBySquaring(base + arg, arg + arg, multiplier shr 1) + multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1) else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") } @@ -86,9 +86,9 @@ internal tailrec fun GroupOps.addMultipliedBySquaring(base: C, arg: C, mu * @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()) +internal fun Field.exponentiateBySquaring(arg: C, exponent: Int): C = + if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt()) + else exponentiateBySquaring(one / arg, (-exponent).toUInt()) // FIXME: Move receiver to context receiver /** @@ -100,9 +100,9 @@ internal fun Field.exponentiationBySquaring(arg: C, exponent: Int): C = * @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()) +internal fun Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = + if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) + else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) // FIXME: Move receiver to context receiver /** @@ -115,12 +115,12 @@ internal fun Field.multiplyExponentiationBySquaring(base: C, arg: C, expo * @return [arg] raised to the power [exponent]. * @author Gleb Minaev */ -internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt): C = +internal tailrec fun Ring.exponentiateBySquaring(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) + exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(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") } @@ -136,11 +136,11 @@ internal tailrec fun Ring.exponentiationBySquaring(arg: C, exponent: UInt * @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 = +internal tailrec fun RingOps.multiplyExponentiatedBySquaring(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) + exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(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 88d357413..af918b9ae 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 @@ -271,7 +271,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - multiplyBySquaring(c, degs[variable]!!) + multiplyByDoubling(c, degs[variable]!!) ) } } @@ -302,7 +302,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( } } }, - cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } ) } } @@ -335,7 +335,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( }, degs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } } ) } @@ -371,7 +371,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 -> multiplyBySquaring(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } } } ) @@ -398,7 +398,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - c / multiplyBySquaring(one, newDegs[variable]!!) + c / multiplyByDoubling(one, newDegs[variable]!!) ) } } @@ -425,7 +425,7 @@ public fun > LabeledPolynomial.antiderivativeWithRespectTo( } put( newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyBySquaring(one, newDegs[variable]!!) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } ) } } @@ -454,7 +454,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo newDegs, newDegs[variable]!!.let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyBySquaring(one, ord) } + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } } ) } @@ -485,7 +485,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 / multiplyBySquaring(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(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 ee85b0f56..ad817c7ba 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 @@ -322,7 +322,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - multiplyBySquaring(c, degs[variable]) + multiplyByDoubling(c, degs[variable]) ) } } @@ -353,7 +353,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( else -> return@forEach } }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyBySquaring(acc, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } ) } } @@ -385,7 +385,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( }.cleanUp(), degs[variable].let { deg -> (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyBySquaring(acc, ord) } + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } } ) } @@ -418,7 +418,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 -> multiplyBySquaring(acc2, ord) } + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } } } ) @@ -441,7 +441,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 / multiplyBySquaring(one, degs[variable]) + c / multiplyByDoubling(one, degs[variable]) ) } } @@ -465,7 +465,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 / multiplyBySquaring(one, degs[variable]) } + cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, degs[variable]) } ) } } @@ -490,7 +490,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 / multiplyBySquaring(one, ord) } + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } } ) } @@ -518,7 +518,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 / multiplyBySquaring(one, ord) } + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } } } ) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt index fe4a82f11..487cd9ee1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -31,47 +31,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - addMultipliedBySquaring(Expr("57"), Expr("179"), 0u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, "tried addMultipliedBySquaring(57, 179, 0u)" ) assertEquals( "(57 + 179)", - addMultipliedBySquaring(Expr("57"), Expr("179"), 1u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, "tried addMultipliedBySquaring(57, 179, 1u)" ) assertEquals( "(57 + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 2u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, "tried addMultipliedBySquaring(57, 179, 2u)" ) assertEquals( "((57 + 179) + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 3u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, "tried addMultipliedBySquaring(57, 179, 3u)" ) assertEquals( "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 4u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, "tried addMultipliedBySquaring(57, 179, 4u)" ) assertEquals( "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 5u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, "tried addMultipliedBySquaring(57, 179, 5u)" ) assertEquals( "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 6u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, "tried addMultipliedBySquaring(57, 179, 6u)" ) assertEquals( "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 7u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, "tried addMultipliedBySquaring(57, 179, 7u)" ) assertEquals( "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 8u).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, "tried addMultipliedBySquaring(57, 179, 8u)" ) } @@ -81,47 +81,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - multiplyBySquaring(Expr("57"), 0u).expr, + multiplyByDoubling(Expr("57"), 0u).expr, "tried multiplyBySquaring(57, 0u)" ) assertEquals( "57", - multiplyBySquaring(Expr("57"), 1u).expr, + multiplyByDoubling(Expr("57"), 1u).expr, "tried multiplyBySquaring(57, 1u)" ) assertEquals( "(57 + 57)", - multiplyBySquaring(Expr("57"), 2u).expr, + multiplyByDoubling(Expr("57"), 2u).expr, "tried multiplyBySquaring(57, 2u)" ) assertEquals( "(57 + (57 + 57))", - multiplyBySquaring(Expr("57"), 3u).expr, + multiplyByDoubling(Expr("57"), 3u).expr, "tried multiplyBySquaring(57, 3u)" ) assertEquals( "((57 + 57) + (57 + 57))", - multiplyBySquaring(Expr("57"), 4u).expr, + multiplyByDoubling(Expr("57"), 4u).expr, "tried multiplyBySquaring(57, 4u)" ) assertEquals( "(57 + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 5u).expr, + multiplyByDoubling(Expr("57"), 5u).expr, "tried multiplyBySquaring(57, 5u)" ) assertEquals( "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 6u).expr, + multiplyByDoubling(Expr("57"), 6u).expr, "tried multiplyBySquaring(57, 6u)" ) assertEquals( "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 7u).expr, + multiplyByDoubling(Expr("57"), 7u).expr, "tried multiplyBySquaring(57, 7u)" ) assertEquals( "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 8u).expr, + multiplyByDoubling(Expr("57"), 8u).expr, "tried multiplyBySquaring(57, 8u)" ) } @@ -131,87 +131,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - addMultipliedBySquaring(Expr("57"), Expr("179"), 0).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, "tried addMultipliedBySquaring(57, 179, 0)" ) assertEquals( "(57 + 179)", - addMultipliedBySquaring(Expr("57"), Expr("179"), 1).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, "tried addMultipliedBySquaring(57, 179, 1)" ) assertEquals( "(57 + -179)", - addMultipliedBySquaring(Expr("57"), Expr("179"), -1).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, "tried addMultipliedBySquaring(57, 179, -1)" ) assertEquals( "(57 + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 2).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, "tried addMultipliedBySquaring(57, 179, 2)" ) assertEquals( "(57 + (-179 + -179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -2).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, "tried addMultipliedBySquaring(57, 179, -2)" ) assertEquals( "((57 + 179) + (179 + 179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 3).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, "tried addMultipliedBySquaring(57, 179, 3)" ) assertEquals( "((57 + -179) + (-179 + -179))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -3).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, "tried addMultipliedBySquaring(57, 179, -3)" ) assertEquals( "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 4).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, "tried addMultipliedBySquaring(57, 179, 4)" ) assertEquals( "(57 + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -4).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, "tried addMultipliedBySquaring(57, 179, -4)" ) assertEquals( "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 5).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, "tried addMultipliedBySquaring(57, 179, 5)" ) assertEquals( "((57 + -179) + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -5).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, "tried addMultipliedBySquaring(57, 179, -5)" ) assertEquals( "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 6).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, "tried addMultipliedBySquaring(57, 179, 6)" ) assertEquals( "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -6).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, "tried addMultipliedBySquaring(57, 179, -6)" ) assertEquals( "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 7).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, "tried addMultipliedBySquaring(57, 179, 7)" ) assertEquals( "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -7).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, "tried addMultipliedBySquaring(57, 179, -7)" ) assertEquals( "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedBySquaring(Expr("57"), Expr("179"), 8).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, "tried addMultipliedBySquaring(57, 179, 8)" ) assertEquals( "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", - addMultipliedBySquaring(Expr("57"), Expr("179"), -8).expr, + addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, "tried addMultipliedBySquaring(57, 179, -8)" ) } @@ -221,87 +221,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - multiplyBySquaring(Expr("57"), 0).expr, + multiplyByDoubling(Expr("57"), 0).expr, "tried multiplyBySquaring(57, 0)" ) assertEquals( "57", - multiplyBySquaring(Expr("57"), 1).expr, + multiplyByDoubling(Expr("57"), 1).expr, "tried multiplyBySquaring(57, 1)" ) assertEquals( "-57", - multiplyBySquaring(Expr("57"), -1).expr, + multiplyByDoubling(Expr("57"), -1).expr, "tried multiplyBySquaring(57, -1)" ) assertEquals( "(57 + 57)", - multiplyBySquaring(Expr("57"), 2).expr, + multiplyByDoubling(Expr("57"), 2).expr, "tried multiplyBySquaring(57, 2)" ) assertEquals( "(-57 + -57)", - multiplyBySquaring(Expr("57"), -2).expr, + multiplyByDoubling(Expr("57"), -2).expr, "tried multiplyBySquaring(57, -2)" ) assertEquals( "(57 + (57 + 57))", - multiplyBySquaring(Expr("57"), 3).expr, + multiplyByDoubling(Expr("57"), 3).expr, "tried multiplyBySquaring(57, 3)" ) assertEquals( "(-57 + (-57 + -57))", - multiplyBySquaring(Expr("57"), -3).expr, + multiplyByDoubling(Expr("57"), -3).expr, "tried multiplyBySquaring(57, -3)" ) assertEquals( "((57 + 57) + (57 + 57))", - multiplyBySquaring(Expr("57"), 4).expr, + multiplyByDoubling(Expr("57"), 4).expr, "tried multiplyBySquaring(57, 4)" ) assertEquals( "((-57 + -57) + (-57 + -57))", - multiplyBySquaring(Expr("57"), -4).expr, + multiplyByDoubling(Expr("57"), -4).expr, "tried multiplyBySquaring(57, -4)" ) assertEquals( "(57 + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 5).expr, + multiplyByDoubling(Expr("57"), 5).expr, "tried multiplyBySquaring(57, 5)" ) assertEquals( "(-57 + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -5).expr, + multiplyByDoubling(Expr("57"), -5).expr, "tried multiplyBySquaring(57, -5)" ) assertEquals( "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 6).expr, + multiplyByDoubling(Expr("57"), 6).expr, "tried multiplyBySquaring(57, 6)" ) assertEquals( "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -6).expr, + multiplyByDoubling(Expr("57"), -6).expr, "tried multiplyBySquaring(57, -6)" ) assertEquals( "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 7).expr, + multiplyByDoubling(Expr("57"), 7).expr, "tried multiplyBySquaring(57, 7)" ) assertEquals( "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -7).expr, + multiplyByDoubling(Expr("57"), -7).expr, "tried multiplyBySquaring(57, -7)" ) assertEquals( "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyBySquaring(Expr("57"), 8).expr, + multiplyByDoubling(Expr("57"), 8).expr, "tried multiplyBySquaring(57, 8)" ) assertEquals( "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyBySquaring(Expr("57"), -8).expr, + multiplyByDoubling(Expr("57"), -8).expr, "tried multiplyBySquaring(57, -8)" ) } @@ -311,47 +311,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr, "tried multiplyExponentiationBySquaring(57, 179, 0u)" ) assertEquals( "(57 * 179)", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr, "tried multiplyExponentiationBySquaring(57, 179, 1u)" ) assertEquals( "(57 * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr, "tried multiplyExponentiationBySquaring(57, 179, 2u)" ) assertEquals( "((57 * 179) * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr, "tried multiplyExponentiationBySquaring(57, 179, 3u)" ) assertEquals( "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr, "tried multiplyExponentiationBySquaring(57, 179, 4u)" ) assertEquals( "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr, "tried multiplyExponentiationBySquaring(57, 179, 5u)" ) assertEquals( "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr, "tried multiplyExponentiationBySquaring(57, 179, 6u)" ) assertEquals( "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr, "tried multiplyExponentiationBySquaring(57, 179, 7u)" ) assertEquals( "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8u).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr, "tried multiplyExponentiationBySquaring(57, 179, 8u)" ) } @@ -361,47 +361,47 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - exponentiationBySquaring(Expr("57"), 0u).expr, + exponentiateBySquaring(Expr("57"), 0u).expr, "tried exponentiationBySquaring(57, 0u)" ) assertEquals( "57", - exponentiationBySquaring(Expr("57"), 1u).expr, + exponentiateBySquaring(Expr("57"), 1u).expr, "tried exponentiationBySquaring(57, 1u)" ) assertEquals( "(57 * 57)", - exponentiationBySquaring(Expr("57"), 2u).expr, + exponentiateBySquaring(Expr("57"), 2u).expr, "tried exponentiationBySquaring(57, 2u)" ) assertEquals( "(57 * (57 * 57))", - exponentiationBySquaring(Expr("57"), 3u).expr, + exponentiateBySquaring(Expr("57"), 3u).expr, "tried exponentiationBySquaring(57, 3u)" ) assertEquals( "((57 * 57) * (57 * 57))", - exponentiationBySquaring(Expr("57"), 4u).expr, + exponentiateBySquaring(Expr("57"), 4u).expr, "tried exponentiationBySquaring(57, 4u)" ) assertEquals( "(57 * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 5u).expr, + exponentiateBySquaring(Expr("57"), 5u).expr, "tried exponentiationBySquaring(57, 5u)" ) assertEquals( "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 6u).expr, + exponentiateBySquaring(Expr("57"), 6u).expr, "tried exponentiationBySquaring(57, 6u)" ) assertEquals( "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 7u).expr, + exponentiateBySquaring(Expr("57"), 7u).expr, "tried exponentiationBySquaring(57, 7u)" ) assertEquals( "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 8u).expr, + exponentiateBySquaring(Expr("57"), 8u).expr, "tried exponentiationBySquaring(57, 8u)" ) } @@ -411,87 +411,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "57", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 0).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr, "tried multiplyExponentiationBySquaring(57, 179, 0)" ) assertEquals( "(57 * 179)", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 1).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr, "tried multiplyExponentiationBySquaring(57, 179, 1)" ) assertEquals( "(57 * (1 / 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -1).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr, "tried multiplyExponentiationBySquaring(57, 179, -1)" ) assertEquals( "(57 * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 2).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr, "tried multiplyExponentiationBySquaring(57, 179, 2)" ) assertEquals( "(57 * ((1 / 179) * (1 / 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -2).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr, "tried multiplyExponentiationBySquaring(57, 179, -2)" ) assertEquals( "((57 * 179) * (179 * 179))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 3).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr, "tried multiplyExponentiationBySquaring(57, 179, 3)" ) assertEquals( "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -3).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr, "tried multiplyExponentiationBySquaring(57, 179, -3)" ) assertEquals( "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 4).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr, "tried multiplyExponentiationBySquaring(57, 179, 4)" ) assertEquals( "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -4).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr, "tried multiplyExponentiationBySquaring(57, 179, -4)" ) assertEquals( "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 5).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr, "tried multiplyExponentiationBySquaring(57, 179, 5)" ) assertEquals( "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -5).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr, "tried multiplyExponentiationBySquaring(57, 179, -5)" ) assertEquals( "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 6).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr, "tried multiplyExponentiationBySquaring(57, 179, 6)" ) assertEquals( "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -6).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr, "tried multiplyExponentiationBySquaring(57, 179, -6)" ) assertEquals( "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 7).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr, "tried multiplyExponentiationBySquaring(57, 179, 7)" ) assertEquals( "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -7).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr, "tried multiplyExponentiationBySquaring(57, 179, -7)" ) assertEquals( "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), 8).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr, "tried multiplyExponentiationBySquaring(57, 179, 8)" ) assertEquals( "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", - multiplyExponentiationBySquaring(Expr("57"), Expr("179"), -8).expr, + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr, "tried multiplyExponentiationBySquaring(57, 179, -8)" ) } @@ -501,87 +501,87 @@ class AlgebraicStubTest { ExprRing { assertEquals( "0", - exponentiationBySquaring(Expr("57"), 0).expr, + exponentiateBySquaring(Expr("57"), 0).expr, "tried exponentiationBySquaring(57, 0)" ) assertEquals( "57", - exponentiationBySquaring(Expr("57"), 1).expr, + exponentiateBySquaring(Expr("57"), 1).expr, "tried exponentiationBySquaring(57, 1)" ) assertEquals( "(1 / 57)", - exponentiationBySquaring(Expr("57"), -1).expr, + exponentiateBySquaring(Expr("57"), -1).expr, "tried exponentiationBySquaring(57, -1)" ) assertEquals( "(57 * 57)", - exponentiationBySquaring(Expr("57"), 2).expr, + exponentiateBySquaring(Expr("57"), 2).expr, "tried exponentiationBySquaring(57, 2)" ) assertEquals( "((1 / 57) * (1 / 57))", - exponentiationBySquaring(Expr("57"), -2).expr, + exponentiateBySquaring(Expr("57"), -2).expr, "tried exponentiationBySquaring(57, -2)" ) assertEquals( "(57 * (57 * 57))", - exponentiationBySquaring(Expr("57"), 3).expr, + exponentiateBySquaring(Expr("57"), 3).expr, "tried exponentiationBySquaring(57, 3)" ) assertEquals( "((1 / 57) * ((1 / 57) * (1 / 57)))", - exponentiationBySquaring(Expr("57"), -3).expr, + exponentiateBySquaring(Expr("57"), -3).expr, "tried exponentiationBySquaring(57, -3)" ) assertEquals( "((57 * 57) * (57 * 57))", - exponentiationBySquaring(Expr("57"), 4).expr, + exponentiateBySquaring(Expr("57"), 4).expr, "tried exponentiationBySquaring(57, 4)" ) assertEquals( "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", - exponentiationBySquaring(Expr("57"), -4).expr, + exponentiateBySquaring(Expr("57"), -4).expr, "tried exponentiationBySquaring(57, -4)" ) assertEquals( "(57 * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 5).expr, + exponentiateBySquaring(Expr("57"), 5).expr, "tried exponentiationBySquaring(57, 5)" ) assertEquals( "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -5).expr, + exponentiateBySquaring(Expr("57"), -5).expr, "tried exponentiationBySquaring(57, -5)" ) assertEquals( "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 6).expr, + exponentiateBySquaring(Expr("57"), 6).expr, "tried exponentiationBySquaring(57, 6)" ) assertEquals( "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -6).expr, + exponentiateBySquaring(Expr("57"), -6).expr, "tried exponentiationBySquaring(57, -6)" ) assertEquals( "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 7).expr, + exponentiateBySquaring(Expr("57"), 7).expr, "tried exponentiationBySquaring(57, 7)" ) assertEquals( "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -7).expr, + exponentiateBySquaring(Expr("57"), -7).expr, "tried exponentiationBySquaring(57, -7)" ) assertEquals( "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiationBySquaring(Expr("57"), 8).expr, + exponentiateBySquaring(Expr("57"), 8).expr, "tried exponentiationBySquaring(57, 8)" ) assertEquals( "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiationBySquaring(Expr("57"), -8).expr, + exponentiateBySquaring(Expr("57"), -8).expr, "tried exponentiationBySquaring(57, -8)" ) } From 9b51062bf7c8b7d65f93120ac36a87bc6731742e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 16:09:24 +0300 Subject: [PATCH 066/174] Sift. --- .../kmath/functions/LabeledPolynomial.kt | 539 ------------------ .../functions/LabeledRationalFunction.kt | 139 ----- .../kmath/functions/ListPolynomial.kt | 367 ------------ .../kmath/functions/ListRationalFunction.kt | 105 ---- .../kmath/functions/NumberedPolynomial.kt | 389 ------------- .../functions/NumberedRationalFunction.kt | 188 ------ .../kscience/kmath/functions/Piecewise.kt | 132 ----- .../kmath/functions/labeledConstructors.kt | 203 ------- .../kmath/functions/labeledPolynomialUtil.kt | 495 ---------------- .../functions/labeledRationalFunctionUtil.kt | 33 -- .../kmath/functions/listConstructors.kt | 60 -- .../kmath/functions/listPolynomialUtil.kt | 233 -------- .../functions/listRationalFunctionUtil.kt | 221 ------- .../kmath/functions/numberedConstructors.kt | 195 ------- .../kmath/functions/numberedPolynomialUtil.kt | 528 ----------------- .../functions/numberedRationalFunctionUtil.kt | 33 -- .../kmath/integration/SplineIntegrator.kt | 107 ---- .../kmath/functions/ListPolynomialTest.kt | 491 ---------------- .../kmath/functions/ListPolynomialUtilTest.kt | 257 --------- 19 files changed, 4715 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt deleted file mode 100644 index b904f7331..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ /dev/null @@ -1,539 +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.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.max - - -/** - * Represents multivariate polynomials with labeled variables. - * - * @param C Ring in which the polynomial is considered. - */ -public data class LabeledPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every non-zero monomial - * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and - * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. - * For example polynomial - * ``` - * 5 a^2 c^3 - 6 b + 0 b c - * ``` - * has coefficients represented as - * ``` - * mapOf( - * mapOf( - * a to 2, - * c to 3 - * ) to 5, - * mapOf( - * b to 1 - * ) to (-6) - * ) - * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "LabeledPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public class LabeledPolynomialSpace>( - public override val ring: A, -) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { - public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * other, - )) - - public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, - )) - public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, - )) - public override operator fun Int.times(other: Symbol): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne * this@times, - )) - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + 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 override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * 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 override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - - public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, - )) - public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, - )) - public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to this@times, - )) - - public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@times to 1U) to other, - )) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) - - public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - )) - public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to -constantOne, - )) - public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to constantOne, - )) - public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = - if (this == other) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to -constantOne, - )) - public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to constantOne - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to constantOne, - )) - - public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = mapOf(this@minus to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } - ) - - public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial( - coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } - ) - - /** - * Returns negation of the polynomial. - */ - override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = - LabeledPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public override val LabeledPolynomial.degrees: Map - get() = - buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.variables: Set - get() = - buildSet { - coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } - } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -// -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } -// -// @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt deleted file mode 100644 index 76c6874f5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ /dev/null @@ -1,139 +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.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke - - -public class LabeledRationalFunction( - public override val numerator: LabeledPolynomial, - public override val denominator: LabeledPolynomial -) : RationalFunction> { - override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class LabeledRationalFunctionSpace>( - public val ring: A, -) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - >, - MultivariatePolynomialSpaceOfFractions< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - >() { - - override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: LabeledPolynomial, - denominator: LabeledPolynomial - ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: Map): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in variables) if (variable in arg) { -// val degreeDif = degrees[variable]!! -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return LabeledRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(emptyMap()) -// -// fun toString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(names) -// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" -// } -// -// fun toString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(names) -// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" -// } -// -// fun toStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(names) -// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" -// } -// -// fun toReversedString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) -// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt deleted file mode 100644 index 585da95ea..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -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.min - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param coefficients constant is the leftmost coefficient. - */ -public data class ListPolynomial( - /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is recommended not to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example), but is not - * prohibited. - */ - public val coefficients: List -) : Polynomial { - override fun toString(): String = "Polynomial$coefficients" -} - -/** - * Space of univariate polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public open class ListPolynomialSpace>( - public override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } + other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } - other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - if (other == 0) zero - else ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - val result = this@plus + getOrElse(0) { constantZero } - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = this@minus - getOrElse(0) { constantZero } - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - if (this == 0) zero - else ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.plus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@plus)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun C.minus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@minus)) - else ListPolynomial( - toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } - - val result = if (size == 0) this@minus else this@minus - get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun C.times(other: ListPolynomial): ListPolynomial = - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - public override operator fun ListPolynomial.plus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - public override operator fun ListPolynomial.minus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(-other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - public override operator fun ListPolynomial.times(other: C): ListPolynomial = - ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): ListPolynomial = ListPolynomial(value) - - /** - * Returns negation of the polynomial. - */ - public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = - ListPolynomial(coefficients.map { -it }) - /** - * Returns sum of the polynomials. - */ - public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } - /** - * Returns difference of the polynomials. - */ - public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } - /** - * Returns product of the polynomials. - */ - public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: ListPolynomial = ListPolynomial(emptyList()) - /** - * Instance of unit constant (unit of the underlying ring). - */ - override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public override val ListPolynomial.degree: Int get() = coefficients.lastIndex - - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } - - /** - * Evaluates the polynomial for the given value [argument]. - */ - @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) -} - -/** - * Space of polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public class ScalableListPolynomialSpace( - ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: ListPolynomial, value: Double): ListPolynomial = - ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt deleted file mode 100644 index 7b6c23ac3..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring - - -public data class ListRationalFunction( - public override val numerator: ListPolynomial, - public override val denominator: ListPolynomial -) : RationalFunction> { - override fun toString(): String = "RationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class ListRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - ListPolynomial, - ListRationalFunction, - ListPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - ListPolynomial, - ListRationalFunction, - >() { - - override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) - override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt deleted file mode 100644 index e75373819..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param C the type of constants. - */ -public data class NumberedPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as - * pair "key-value" in the map, where value is coefficients `a` and - * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring - * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * ) - * ``` - * and also as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * listOf(0, 1, 1) to 0, - * ) - * ``` - * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not - * contain any zeros on end, but can contain zeros on start or anywhere in middle. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "NumberedPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public open class NumberedPolynomialSpace>( - public final override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + 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 override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - /** - * 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 override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) - else NumberedPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): NumberedPolynomial = - NumberedPolynomial(mapOf(emptyList() to value)) - - /** - * Returns negation of the polynomial. - */ - override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = - NumberedPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: NumberedPolynomial = - NumberedPolynomial( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List - get() = - MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - this[index] = max(this[index], deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } - } ?: 0u - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("substitutePolynomial") - public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } - - @Suppress("NOTHING_TO_INLINE") - public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") - public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - // FIXME: Move to other constructors with context receiver - public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt deleted file mode 100644 index 30c7f0188..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max - - -public class NumberedRationalFunction internal constructor( - public override val numerator: NumberedPolynomial, - public override val denominator: NumberedPolynomial -) : RationalFunction> { - override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class NumberedRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - NumberedPolynomial, - NumberedRationalFunction, - >() { - - override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: NumberedPolynomial, - denominator: NumberedPolynomial - ): NumberedRationalFunction = - NumberedRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val NumberedRationalFunction.lastVariable: Int - get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } - /** - * Count of variables occurring in the rational function with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedRationalFunction.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - denominator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - // TODO: Разобрать - -// operator fun invoke(arg: Map): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokePolynomial") -// operator fun invoke(arg: Map>): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeRationalFunction") -// operator fun invoke(arg: Map>): NumberedRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { -// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return NumberedRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(Polynomial.variableName) -// -// fun toString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt deleted file mode 100644 index 612b00535..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ /dev/null @@ -1,132 +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.PerformancePitfall -import space.kscience.kmath.operations.Ring - -/** - * Represents piecewise-defined function. - * - * @param T the piece key type. - * @param R the sub-function type. - */ -public fun interface Piecewise { - /** - * Returns the appropriate sub-function for given piece key. - */ - public fun findPiece(arg: T): R? -} - -/** - * Represents piecewise-defined function where all the sub-functions are polynomials. - * - * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no - * "holes" in it. - */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> - - override fun findPiece(arg: T): ListPolynomial? -} - -/** - * A generic piecewise without constraints on how pieces are placed - */ -@PerformancePitfall("findPiece method of resulting piecewise is slow") -public fun > PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, -): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces - - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second -} - -/** - * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. - * The pieces search is logarithmic. - */ -private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, -) : PiecewisePolynomial { - - override fun findPiece(arg: T): ListPolynomial? { - val index = pieces.binarySearch { (range, _) -> - when { - arg >= range.endInclusive -> -1 - arg < range.start -> +1 - else -> 0 - } - } - return if (index < 0) null else pieces[index].second - } - -} - -/** - * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. - * - * @param T the comparable piece key type. - * @param delimiter the initial piecewise separator - */ -public class PiecewiseBuilder>(delimiter: T) { - private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() - - /** - * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) - * - * @param right new rightmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putRight(right: T, piece: ListPolynomial) { - require(right > delimiters.last()) { "New delimiter should be to the right of old one" } - delimiters += right - pieces += piece - } - - /** - * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) - * - * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putLeft(left: T, piece: ListPolynomial) { - require(left < delimiters.first()) { "New delimiter should be to the left of old one" } - delimiters.add(0, left) - pieces.add(0, piece) - } - - public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> - l..r - }.zip(pieces)) -} - -/** - * A builder for [PiecewisePolynomial] - */ -public fun > PiecewisePolynomial( - startingPoint: T, - builder: PiecewiseBuilder.() -> Unit, -): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() - -/** - * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise - * definition. - */ -public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = - findPiece(arg)?.substitute(ring, arg) - -/** - * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } - -/** - * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +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.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ 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 deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +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.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt deleted file mode 100644 index 9498c77ca..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring - - -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) - - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial(listOf(one)) - ) - -//context(A) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) -//context(ListRationalFunctionSpace) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -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) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - 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 multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = 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.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 ListPolynomial.substitute(ring: Ring, 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 ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = 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 = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = 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(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt deleted file mode 100644 index 367212588..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max - - -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() -} - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) - -/** - * 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 ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) -} - -/** - * Returns numerator (polynomial) of rational function gotten by substitution rational function [arg] to the polynomial instance. - * More concrete, if [arg] is a fraction `f(x)/g(x)` and the receiving instance is `p(x)`, then - * ``` - * p(f/g) * g^deg(p) - * ``` - * is returned. - * - * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. - */ // TODO: Дописать -internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() - val numeratorDegree = arg.numerator.coefficients.lastIndex - val denominatorDegree = arg.denominator.coefficients.lastIndex - val argDegree = max(numeratorDegree, denominatorDegree) - val constantZero = zero - val powersOf2 = buildList(thisDegreeLog2 + 1) { - var result = 1 - for (exp in 0 .. thisDegreeLog2) { - add(result) - result = result shl 1 - } - } - val hashes = powersOf2.runningReduce { acc, i -> acc + i } - val numeratorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.numerator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * numeratorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * numeratorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * numeratorDegree + 1, - target = next, - ) - } - } - val denominatorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.denominator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * denominatorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * denominatorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * denominatorDegree + 1, - target = next, - ) - } - } - val levelResultCoefsPool = buildList>(thisDegreeLog2 + 1) { - repeat(thisDegreeLog2 + 1) { - add(MutableList(hashes[it] * argDegree) { constantZero }) - } - } - val edgedMultiplier = MutableList(0) { TODO() } - val edgedMultiplierUpdater = MutableList(0) { TODO() } - - fun MutableList.reset() { - for (i in indices) set(i, constantZero) - } - - fun processLevel(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - levelResultCoefs.reset() - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = (start + end) / 2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = (start + end) / 2, end = end), - multiplicandDegree = hashes[level] * argDegree, - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - } - - return levelResultCoefs - } - - fun processLevelEdged(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - val levelsPowerOf2 = powersOf2[level] - if (end - start >= levelsPowerOf2) { - multiplyAddingTo( - ring = ring, - multiplicand = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - multiplicandDegree = hashes[level] * argDegree, // TODO: Ввести переменную - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = start + levelsPowerOf2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = edgedMultiplier, - multiplierDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - if (level != thisDegreeLog2) { - multiplyAddingToUpdater( - ring = ring, - multiplicand = edgedMultiplier, - multiplicandDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - updater = edgedMultiplierUpdater, - zero = constantZero - ) - } - } else { - copyTo( - origin = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - originDegree = hashes[level] * argDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - } - } - - return levelResultCoefs - } - - return ListPolynomial( - processLevelEdged( - level = thisDegreeLog2, - start = 0, - end = thisDegree + 1 - ) - ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// 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 > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +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.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file 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 deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * 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 NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .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 / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - 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 / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt deleted file mode 100644 index 0fcd4c6e5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ /dev/null @@ -1,107 +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.integration - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.functions.antiderivative -import space.kscience.kmath.interpolation.PolynomialInterpolator -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) - -/** - * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] - * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] - * - * TODO use context receiver for algebra - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate( - algebra: Field, range: ClosedRange, -): T = algebra.sum( - pieces.map { (region, poly) -> - val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) - //Check if polynomial range is not used - if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero - else poly.integrate(algebra, intersectedRange) - } -) - -/** - * A generic spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses - * the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public class SplineIntegrator>( - public val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - - val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map(bufferFactory) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials( - nodes.map(bufferFactory) { number(it) }, - values - ) - val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -/** - * A simplified double-based spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials(nodes, values) - val res = polynomials.integrate(DoubleField, range) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -@Suppress("unused") -@UnstableKMathAPI -public inline val DoubleField.splineIntegrator: UnivariateIntegrator - get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt deleted file mode 100644 index 5401be707..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ /dev/null @@ -1,491 +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.test.misc.* -import kotlin.test.* - - -class ListPolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + 2, - "test 3" - ) - assertEquals( - ListPolynomial(), - ListPolynomial() + 0, - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - 2, - "test 3" - ) - assertEquals( - ListPolynomial(), - ListPolynomial() - 0, - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - 2, - "test 7" - ) - } - } - @Test - fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27, - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15, - "test 2" - ) - } - } - @Test - fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - 2 + ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(), - 0 + ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - 1 + ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - 2 + ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - -2 - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(), - 0 - ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - -1 - ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - -2 - ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() + Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() - Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(2) + ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) + ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - Rational(1) + ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - Rational(2) + ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) - ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - Rational(-1) - ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - Rational(-2) - ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { - // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 - assertEquals( - ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + - ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 - assertEquals( - ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + - ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 - assertEquals( - ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + - ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + - ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - - ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 - assertEquals( - ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - - ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - - ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - ListPolynomial(1, 0, 1, 0, 1), - ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), - "test 2" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt deleted file mode 100644 index c5eb8fb81..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ /dev/null @@ -1,257 +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.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - - -class ListPolynomialUtilTest { - @Test - fun test_substitute_Double() { - assertEquals( - 0.0, - ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 1.1931904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 2" - ) - assertEquals( - 0.5681904761904762, - ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 3" - ) - assertEquals( - 1.1811904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), - 0.001, - "test 4" - ) - assertEquals( - 1.1703333333333332, - ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), - 0.001, - "test 5" - ) - } - @Test - fun test_substitute_Constant() { - assertEquals( - Rational(0), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_substitute_Polynomial() { - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - fun test_derivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthDerivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test - fun test_antiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), - "test 4" - ) - } - @Test - fun test_nthAntiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), - "test 1" - ) - assertFailsWith("test2") { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), - "test 9" - ) - } -} \ No newline at end of file From a2b02ef09e3b077b11db7023eb82882738ff5aca Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 16:15:59 +0300 Subject: [PATCH 067/174] Sifted rest usage of non-basic polynomial things. --- .../kmath/interpolation/Interpolator.kt | 92 ------------ .../kmath/interpolation/LinearInterpolator.kt | 43 ------ .../kmath/interpolation/SplineInterpolator.kt | 83 ---------- .../kmath/integration/SplineIntegralTest.kt | 48 ------ .../interpolation/LinearInterpolatorTest.kt | 29 ---- .../interpolation/SplineInterpolatorTest.kt | 31 ---- .../kscience/kmath/test/misc/IntModulo.kt | 142 ------------------ .../kscience/kmath/test/misc/Rational.kt | 135 ----------------- .../test/misc/RationalWithMemorization.kt | 107 ------------- .../kscience/kmath/test/misc/memorization.kt | 51 ------- .../space/kscience/kmath/test/misc/misc.kt | 31 ---- 11 files changed, 792 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt deleted file mode 100644 index 62819be0c..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.substitute -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * And interpolator for data with x column type [X], y column type [Y]. - */ -public fun interface Interpolator { - public fun interpolate(points: XYColumnarData): (X) -> Y -} - -/** - * And interpolator returning [PiecewisePolynomial] function - */ -public interface PolynomialInterpolator> : Interpolator { - public val algebra: Ring - - public fun getDefaultValue(): T = error("Out of bounds") - - public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial - - override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() - } -} - - -public fun > PolynomialInterpolator.interpolatePolynomials( - x: Buffer, - y: Buffer, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(x, y) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: Map, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: List>, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, -): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: Map, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: List>, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, - defaultValue: T, -): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: Map, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: List>, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt deleted file mode 100644 index b55f16cf2..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ /dev/null @@ -1,43 +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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke - -@OptIn(UnstableKMathAPI::class) -internal fun > insureSorted(points: XYColumnarData<*, T, *>) { - for (i in 0 until points.size - 1) - require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } -} - -/** - * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java - */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size > 0) { "Point array should not be empty" } - insureSorted(points) - - PiecewisePolynomial(points.x[0]) { - for (i in 0 until points.size - 1) { - val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) - val const = points.y[i] - slope * points.x[i] - val polynomial = ListPolynomial(const, slope) - putRight(points.x[i + 1], polynomial) - } - } - } -} - -public val > Field.linearInterpolator: LinearInterpolator - get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt deleted file mode 100644 index 48c90ff23..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ /dev/null @@ -1,83 +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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type - * specific ones. - * - * Based on - * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java - */ -public class SplineInterpolator>( - override val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : PolynomialInterpolator { - //TODO possibly optimize zeroed buffers - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } - insureSorted(points) - // Number of intervals. The number of data points is n + 1. - val n = points.size - 1 - // Differences between knot points - val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(n) { zero } - val z = bufferFactory(n + 1) { zero } - - for (i in 1 until n) { - val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] - mu[i] = h[i] / g - z[i] = - ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / - (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g - } - - // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - - PiecewisePolynomial(points.x[points.size - 1]) { - var cOld = zero - - for (j in n - 1 downTo 0) { - val c = z[j] - mu[j] * cOld - val a = points.y[j] - val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 - val d = (cOld - c) / (3.0 * h[j]) - val x0 = points.x[j] - val x02 = x0 * x0 - val x03 = x02 * x0 - //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = ListPolynomial( - a - b * x0 + c * x02 - d * x03, - b - 2 * c * x0 + 3 * d * x02, - c - 3 * d * x0, - d - ) - cOld = c - putLeft(x0, polynomial) - } - } - } -} - - -public fun > Field.splineInterpolator( - bufferFactory: MutableBufferFactory, -): SplineInterpolator = SplineInterpolator(this, bufferFactory) - -public val DoubleField.splineInterpolator: SplineInterpolator - get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt deleted file mode 100644 index aae0ad017..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ /dev/null @@ -1,48 +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.integration - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SplineIntegralTest { - - @Test - fun integratePolynomial(){ - val polynomial = ListPolynomial(1.0, 2.0, 3.0) - val integral = polynomial.integrate(DoubleField,1.0..2.0) - assertEquals(11.0, integral, 0.001) - } - - @Test - fun gaussSin() { - val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt deleted file mode 100644 index 1143036d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ /dev/null @@ -1,29 +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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class LinearInterpolatorTest { - @Test - fun testInterpolation() { - val data = listOf( - 0.0 to 0.0, - 1.0 to 1.0, - 2.0 to 3.0, - 3.0 to 4.0 - ) - - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) - val function = DoubleField.linearInterpolator.interpolate(data) - assertEquals(null, function(-1.0)) - assertEquals(0.5, function(0.5)) - assertEquals(2.0, function(1.5)) - assertEquals(3.0, function(2.0)) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt deleted file mode 100644 index 4c7d816d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ /dev/null @@ -1,31 +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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class SplineInterpolatorTest { - @Test - fun testInterpolation() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) - - val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) - - assertEquals(Double.NaN, function(-1.0)) - assertEquals(sin(0.5), function(0.5), 0.1) - assertEquals(sin(1.5), function(1.5), 0.1) - assertEquals(sin(2.0), function(2.0), 0.1) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt deleted file mode 100644 index 2353beee6..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ /dev/null @@ -1,142 +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.test.misc - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -class IntModuloRing : Ring { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt deleted file mode 100644 index 72bb5942c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ /dev/null @@ -1,135 +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.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, NumbersAddOps { - 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 -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt deleted file mode 100644 index 05d9115fa..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ /dev/null @@ -1,107 +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.test.misc - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* - -class RationalWithMemorization private constructor( - val value: Rational, - override val memory : OperationsMemory -): WithMemorization { - companion object { - /** - * Constant containing the zero (the additive identity) of the [Rational] field. - */ - public val ZERO: RationalWithMemorization = RationalWithMemorization(Rational.ZERO, object : Endpoint {}) - /** - * Constant containing the one (the multiplicative identity) of the [Rational] field. - */ - public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {}) - } - constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - - operator fun unaryPlus(): RationalWithMemorization = this - operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( - -value, - object : Negation { - override val negated: OperationsMemory = memory - } - ) - operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value + other.value, - object : Sum { - override val augend: OperationsMemory = memory - override val addend: OperationsMemory = other.memory - } - ) - operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value - other.value, - object : Difference { - override val minuend: OperationsMemory = memory - override val subtrahend: OperationsMemory = other.memory - } - ) - operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value * other.value, - object : Product { - override val multiplicand: OperationsMemory = memory - override val multiplier: OperationsMemory = other.memory - } - ) - operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value / other.value, - object : Quotient { - override val dividend: OperationsMemory = memory - override val divisor: OperationsMemory = other.memory - } - ) - - override fun equals(other: Any?): Boolean = - other is RationalWithMemorization && value == other.value - - override fun hashCode(): Int = value.hashCode() - - override fun toString(): String = value.toString() -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RationalWithMemorizationRing : Ring { - override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO - override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE - - override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right - override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right - - override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this - override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg - override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg - override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RationalWithMemorizationField : Field { - override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO - override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE - - override inline fun number(value: Number): RationalWithMemorization = RationalWithMemorization(value.toLong()) - - override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right - override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right - override inline fun divide(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left / right - override inline fun scale(a: RationalWithMemorization, value: Double): RationalWithMemorization = a * number(value) - - override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this - override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg - override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg - override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg - override inline fun RationalWithMemorization.div(arg: RationalWithMemorization): RationalWithMemorization = this / arg -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt deleted file mode 100644 index a4fb81274..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt +++ /dev/null @@ -1,51 +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.test.misc - -sealed interface OperationsMemory - -interface Endpoint: OperationsMemory - -interface Negation: OperationsMemory { - val negated: OperationsMemory -} - -interface Sum: OperationsMemory { - val augend: OperationsMemory - val addend: OperationsMemory -} - -interface Difference: OperationsMemory { - val minuend: OperationsMemory - val subtrahend: OperationsMemory -} - -interface Product: OperationsMemory { - val multiplicand: OperationsMemory - val multiplier: OperationsMemory -} - -interface Quotient: OperationsMemory { - val dividend: OperationsMemory - val divisor: OperationsMemory -} - - -fun equalMemories(one: OperationsMemory, other: OperationsMemory) : Boolean = - when(one) { - is Negation -> other is Negation && equalMemories(one.negated, other.negated) - is Sum -> other is Sum && equalMemories(one.augend, other.augend) && equalMemories(one.addend, other.addend) - is Difference -> other is Difference && equalMemories(one.minuend, other.minuend) && equalMemories(one.subtrahend, other.subtrahend) - is Product -> other is Product && equalMemories(one.multiplicand, other.multiplicand) && equalMemories(one.multiplier, other.multiplier) - is Quotient -> other is Quotient && equalMemories(one.dividend, other.dividend) && equalMemories(one.divisor, other.divisor) - is Endpoint -> one === other - } - -interface WithMemorization { - val memory: OperationsMemory -} - -fun equalMemories(one: WithMemorization, other: WithMemorization) : Boolean = equalMemories(one.memory, other.memory) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt deleted file mode 100644 index cc647fa2c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ /dev/null @@ -1,31 +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.test.misc - -// TODO: Move to corresponding module "kmath-number-theory" - -import kotlin.math.abs - - -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file From 8af183a969e2099cea5d3c293be319e7aa1b0080 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 19:22:57 +0300 Subject: [PATCH 068/174] Fixed typos. Added docstrings. Added variable convertional methods. --- .../kscience/kmath/functions/Polynomial.kt | 150 ++++-- .../kmath/functions/RationalFunction.kt | 467 +++++++++++++----- 2 files changed, 468 insertions(+), 149 deletions(-) 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 e201f1f6e..f2eba10d5 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 @@ -25,38 +25,38 @@ public interface Polynomial @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -72,38 +72,38 @@ public interface PolynomialSpace> : Ring

{ public fun Int.asConstant(): C = constantNumber(this) /** - * 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]. */ public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** - * 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]. */ public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** - * 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]. */ public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** - * 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]. */ public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** - * 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]. */ public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** - * 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]. */ @@ -165,28 +165,28 @@ public interface PolynomialSpace> : Ring

{ public val constantOne: 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 operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -254,41 +254,44 @@ public interface PolynomialSpace> : Ring

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,143 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..edc9dfa5c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a 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 = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a 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 = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: 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 operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * 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: P): P = polynomialRing { this@plus + other } /** - * 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: P): P = polynomialRing { this@minus - other } /** - * 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: P): P = polynomialRing { this@times * other } /** - * 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 P.plus(other: C): P = polynomialRing { this@plus + other } /** - * 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 P.minus(other: C): P = polynomialRing { this@minus - other } /** - * 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 P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -826,7 +842,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +852,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +862,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -873,7 +889,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +897,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,7 +905,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( @@ -904,7 +920,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +928,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,7 +936,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( @@ -940,7 +956,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +964,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,7 +972,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( @@ -971,7 +987,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +995,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( @@ -1052,6 +1068,15 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1084,175 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1291,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1309,135 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1467,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1484,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1512,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( From 03b92de6e0803c0813bf53469cf9d195699f016a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 19:29:14 +0300 Subject: [PATCH 069/174] Sifted ListPolynomial's basics. --- .../kmath/functions/LabeledPolynomial.kt | 539 ------------------ .../functions/LabeledRationalFunction.kt | 139 ----- .../kmath/functions/NumberedPolynomial.kt | 389 ------------- .../functions/NumberedRationalFunction.kt | 188 ------ .../kscience/kmath/functions/Piecewise.kt | 132 ----- .../kmath/functions/labeledConstructors.kt | 203 ------- .../kmath/functions/labeledPolynomialUtil.kt | 495 ---------------- .../functions/labeledRationalFunctionUtil.kt | 33 -- .../kmath/functions/numberedConstructors.kt | 195 ------- .../kmath/functions/numberedPolynomialUtil.kt | 528 ----------------- .../functions/numberedRationalFunctionUtil.kt | 33 -- .../kmath/integration/SplineIntegrator.kt | 107 ---- .../kmath/interpolation/Interpolator.kt | 92 --- .../kmath/interpolation/LinearInterpolator.kt | 43 -- .../kmath/interpolation/SplineInterpolator.kt | 83 --- .../kmath/integration/SplineIntegralTest.kt | 48 -- .../interpolation/LinearInterpolatorTest.kt | 29 - .../interpolation/SplineInterpolatorTest.kt | 31 - .../kscience/kmath/test/misc/IntModulo.kt | 142 ----- .../kscience/kmath/test/misc/Rational.kt | 135 ----- .../test/misc/RationalWithMemorization.kt | 107 ---- .../kscience/kmath/test/misc/memorization.kt | 51 -- .../space/kscience/kmath/test/misc/misc.kt | 31 - 23 files changed, 3773 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt deleted file mode 100644 index b904f7331..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ /dev/null @@ -1,539 +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.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.max - - -/** - * Represents multivariate polynomials with labeled variables. - * - * @param C Ring in which the polynomial is considered. - */ -public data class LabeledPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every non-zero monomial - * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and - * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. - * For example polynomial - * ``` - * 5 a^2 c^3 - 6 b + 0 b c - * ``` - * has coefficients represented as - * ``` - * mapOf( - * mapOf( - * a to 2, - * c to 3 - * ) to 5, - * mapOf( - * b to 1 - * ) to (-6) - * ) - * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "LabeledPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public class LabeledPolynomialSpace>( - public override val ring: A, -) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { - public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * other, - )) - - public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, - )) - public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, - )) - public override operator fun Int.times(other: Symbol): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne * this@times, - )) - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + 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 override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * 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 override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - - public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, - )) - public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, - )) - public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to this@times, - )) - - public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@times to 1U) to other, - )) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) - - public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - )) - public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to -constantOne, - )) - public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to constantOne, - )) - public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = - if (this == other) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to -constantOne, - )) - public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to constantOne - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to constantOne, - )) - - public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = mapOf(this@minus to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } - ) - - public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial( - coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } - ) - - /** - * Returns negation of the polynomial. - */ - override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = - LabeledPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public override val LabeledPolynomial.degrees: Map - get() = - buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.variables: Set - get() = - buildSet { - coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } - } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -// -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } -// -// @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt deleted file mode 100644 index 76c6874f5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ /dev/null @@ -1,139 +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.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke - - -public class LabeledRationalFunction( - public override val numerator: LabeledPolynomial, - public override val denominator: LabeledPolynomial -) : RationalFunction> { - override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class LabeledRationalFunctionSpace>( - public val ring: A, -) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - >, - MultivariatePolynomialSpaceOfFractions< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - >() { - - override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: LabeledPolynomial, - denominator: LabeledPolynomial - ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: Map): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in variables) if (variable in arg) { -// val degreeDif = degrees[variable]!! -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return LabeledRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(emptyMap()) -// -// fun toString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(names) -// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" -// } -// -// fun toString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(names) -// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" -// } -// -// fun toStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(names) -// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" -// } -// -// fun toReversedString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) -// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt deleted file mode 100644 index e75373819..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param C the type of constants. - */ -public data class NumberedPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as - * pair "key-value" in the map, where value is coefficients `a` and - * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring - * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * ) - * ``` - * and also as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * listOf(0, 1, 1) to 0, - * ) - * ``` - * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not - * contain any zeros on end, but can contain zeros on start or anywhere in middle. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "NumberedPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public open class NumberedPolynomialSpace>( - public final override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + 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 override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - /** - * 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 override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) - else NumberedPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): NumberedPolynomial = - NumberedPolynomial(mapOf(emptyList() to value)) - - /** - * Returns negation of the polynomial. - */ - override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = - NumberedPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: NumberedPolynomial = - NumberedPolynomial( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List - get() = - MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - this[index] = max(this[index], deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } - } ?: 0u - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("substitutePolynomial") - public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } - - @Suppress("NOTHING_TO_INLINE") - public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") - public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - // FIXME: Move to other constructors with context receiver - public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt deleted file mode 100644 index 30c7f0188..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max - - -public class NumberedRationalFunction internal constructor( - public override val numerator: NumberedPolynomial, - public override val denominator: NumberedPolynomial -) : RationalFunction> { - override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class NumberedRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - NumberedPolynomial, - NumberedRationalFunction, - >() { - - override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: NumberedPolynomial, - denominator: NumberedPolynomial - ): NumberedRationalFunction = - NumberedRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val NumberedRationalFunction.lastVariable: Int - get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } - /** - * Count of variables occurring in the rational function with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedRationalFunction.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - denominator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - // TODO: Разобрать - -// operator fun invoke(arg: Map): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokePolynomial") -// operator fun invoke(arg: Map>): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeRationalFunction") -// operator fun invoke(arg: Map>): NumberedRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { -// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return NumberedRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(Polynomial.variableName) -// -// fun toString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt deleted file mode 100644 index 612b00535..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ /dev/null @@ -1,132 +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.PerformancePitfall -import space.kscience.kmath.operations.Ring - -/** - * Represents piecewise-defined function. - * - * @param T the piece key type. - * @param R the sub-function type. - */ -public fun interface Piecewise { - /** - * Returns the appropriate sub-function for given piece key. - */ - public fun findPiece(arg: T): R? -} - -/** - * Represents piecewise-defined function where all the sub-functions are polynomials. - * - * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no - * "holes" in it. - */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> - - override fun findPiece(arg: T): ListPolynomial? -} - -/** - * A generic piecewise without constraints on how pieces are placed - */ -@PerformancePitfall("findPiece method of resulting piecewise is slow") -public fun > PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, -): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces - - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second -} - -/** - * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. - * The pieces search is logarithmic. - */ -private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, -) : PiecewisePolynomial { - - override fun findPiece(arg: T): ListPolynomial? { - val index = pieces.binarySearch { (range, _) -> - when { - arg >= range.endInclusive -> -1 - arg < range.start -> +1 - else -> 0 - } - } - return if (index < 0) null else pieces[index].second - } - -} - -/** - * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. - * - * @param T the comparable piece key type. - * @param delimiter the initial piecewise separator - */ -public class PiecewiseBuilder>(delimiter: T) { - private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() - - /** - * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) - * - * @param right new rightmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putRight(right: T, piece: ListPolynomial) { - require(right > delimiters.last()) { "New delimiter should be to the right of old one" } - delimiters += right - pieces += piece - } - - /** - * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) - * - * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. - * @param piece the sub-function. - */ - public fun putLeft(left: T, piece: ListPolynomial) { - require(left < delimiters.first()) { "New delimiter should be to the left of old one" } - delimiters.add(0, left) - pieces.add(0, piece) - } - - public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> - l..r - }.zip(pieces)) -} - -/** - * A builder for [PiecewisePolynomial] - */ -public fun > PiecewisePolynomial( - startingPoint: T, - builder: PiecewiseBuilder.() -> Unit, -): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() - -/** - * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise - * definition. - */ -public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = - findPiece(arg)?.substitute(ring, arg) - -/** - * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } - -/** - * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +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.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ 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 deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +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.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +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.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file 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 deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * 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 NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .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 / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - 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 / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt deleted file mode 100644 index 0fcd4c6e5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ /dev/null @@ -1,107 +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.integration - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.functions.antiderivative -import space.kscience.kmath.interpolation.PolynomialInterpolator -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) - -/** - * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] - * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] - * - * TODO use context receiver for algebra - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate( - algebra: Field, range: ClosedRange, -): T = algebra.sum( - pieces.map { (region, poly) -> - val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) - //Check if polynomial range is not used - if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero - else poly.integrate(algebra, intersectedRange) - } -) - -/** - * A generic spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses - * the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public class SplineIntegrator>( - public val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - - val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map(bufferFactory) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials( - nodes.map(bufferFactory) { number(it) }, - values - ) - val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -/** - * A simplified double-based spline-interpolation-based analytic integration - * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. - * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always - * uses the maximum number of points. By default, uses 10 points. - */ -@UnstableKMathAPI -public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - - val nodes: Buffer = integrand.getFeature()?.nodes ?: run { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val step = (range.endInclusive - range.start) / (numPoints - 1) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials(nodes, values) - val res = polynomials.integrate(DoubleField, range) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -@Suppress("unused") -@UnstableKMathAPI -public inline val DoubleField.splineIntegrator: UnivariateIntegrator - get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt deleted file mode 100644 index 62819be0c..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.substitute -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * And interpolator for data with x column type [X], y column type [Y]. - */ -public fun interface Interpolator { - public fun interpolate(points: XYColumnarData): (X) -> Y -} - -/** - * And interpolator returning [PiecewisePolynomial] function - */ -public interface PolynomialInterpolator> : Interpolator { - public val algebra: Ring - - public fun getDefaultValue(): T = error("Out of bounds") - - public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial - - override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() - } -} - - -public fun > PolynomialInterpolator.interpolatePolynomials( - x: Buffer, - y: Buffer, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(x, y) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: Map, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: List>, -): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, -): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: Map, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: List>, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, - defaultValue: T, -): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: Map, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: List>, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt deleted file mode 100644 index b55f16cf2..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ /dev/null @@ -1,43 +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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke - -@OptIn(UnstableKMathAPI::class) -internal fun > insureSorted(points: XYColumnarData<*, T, *>) { - for (i in 0 until points.size - 1) - require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } -} - -/** - * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java - */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size > 0) { "Point array should not be empty" } - insureSorted(points) - - PiecewisePolynomial(points.x[0]) { - for (i in 0 until points.size - 1) { - val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) - val const = points.y[i] - slope * points.x[i] - val polynomial = ListPolynomial(const, slope) - putRight(points.x[i + 1], polynomial) - } - } - } -} - -public val > Field.linearInterpolator: LinearInterpolator - get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt deleted file mode 100644 index 48c90ff23..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ /dev/null @@ -1,83 +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.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type - * specific ones. - * - * Based on - * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java - */ -public class SplineInterpolator>( - override val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : PolynomialInterpolator { - //TODO possibly optimize zeroed buffers - - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } - insureSorted(points) - // Number of intervals. The number of data points is n + 1. - val n = points.size - 1 - // Differences between knot points - val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(n) { zero } - val z = bufferFactory(n + 1) { zero } - - for (i in 1 until n) { - val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] - mu[i] = h[i] / g - z[i] = - ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / - (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g - } - - // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - - PiecewisePolynomial(points.x[points.size - 1]) { - var cOld = zero - - for (j in n - 1 downTo 0) { - val c = z[j] - mu[j] * cOld - val a = points.y[j] - val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 - val d = (cOld - c) / (3.0 * h[j]) - val x0 = points.x[j] - val x02 = x0 * x0 - val x03 = x02 * x0 - //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = ListPolynomial( - a - b * x0 + c * x02 - d * x03, - b - 2 * c * x0 + 3 * d * x02, - c - 3 * d * x0, - d - ) - cOld = c - putLeft(x0, polynomial) - } - } - } -} - - -public fun > Field.splineInterpolator( - bufferFactory: MutableBufferFactory, -): SplineInterpolator = SplineInterpolator(this, bufferFactory) - -public val DoubleField.splineInterpolator: SplineInterpolator - get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt deleted file mode 100644 index aae0ad017..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ /dev/null @@ -1,48 +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.integration - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SplineIntegralTest { - - @Test - fun integratePolynomial(){ - val polynomial = ListPolynomial(1.0, 2.0, 3.0) - val integral = polynomial.integrate(DoubleField,1.0..2.0) - assertEquals(11.0, integral, 0.001) - } - - @Test - fun gaussSin() { - val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt deleted file mode 100644 index 1143036d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ /dev/null @@ -1,29 +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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class LinearInterpolatorTest { - @Test - fun testInterpolation() { - val data = listOf( - 0.0 to 0.0, - 1.0 to 1.0, - 2.0 to 3.0, - 3.0 to 4.0 - ) - - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) - val function = DoubleField.linearInterpolator.interpolate(data) - assertEquals(null, function(-1.0)) - assertEquals(0.5, function(0.5)) - assertEquals(2.0, function(1.5)) - assertEquals(3.0, function(2.0)) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt deleted file mode 100644 index 4c7d816d4..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ /dev/null @@ -1,31 +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.interpolation - -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class SplineInterpolatorTest { - @Test - fun testInterpolation() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) - - val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) - - assertEquals(Double.NaN, function(-1.0)) - assertEquals(sin(0.5), function(0.5), 0.1) - assertEquals(sin(1.5), function(1.5), 0.1) - assertEquals(sin(2.0), function(2.0), 0.1) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt deleted file mode 100644 index 2353beee6..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ /dev/null @@ -1,142 +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.test.misc - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -class IntModuloRing : Ring { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt deleted file mode 100644 index 72bb5942c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ /dev/null @@ -1,135 +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.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, NumbersAddOps { - 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 -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt deleted file mode 100644 index 05d9115fa..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ /dev/null @@ -1,107 +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.test.misc - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* - -class RationalWithMemorization private constructor( - val value: Rational, - override val memory : OperationsMemory -): WithMemorization { - companion object { - /** - * Constant containing the zero (the additive identity) of the [Rational] field. - */ - public val ZERO: RationalWithMemorization = RationalWithMemorization(Rational.ZERO, object : Endpoint {}) - /** - * Constant containing the one (the multiplicative identity) of the [Rational] field. - */ - public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {}) - } - constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - - operator fun unaryPlus(): RationalWithMemorization = this - operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( - -value, - object : Negation { - override val negated: OperationsMemory = memory - } - ) - operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value + other.value, - object : Sum { - override val augend: OperationsMemory = memory - override val addend: OperationsMemory = other.memory - } - ) - operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value - other.value, - object : Difference { - override val minuend: OperationsMemory = memory - override val subtrahend: OperationsMemory = other.memory - } - ) - operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value * other.value, - object : Product { - override val multiplicand: OperationsMemory = memory - override val multiplier: OperationsMemory = other.memory - } - ) - operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value / other.value, - object : Quotient { - override val dividend: OperationsMemory = memory - override val divisor: OperationsMemory = other.memory - } - ) - - override fun equals(other: Any?): Boolean = - other is RationalWithMemorization && value == other.value - - override fun hashCode(): Int = value.hashCode() - - override fun toString(): String = value.toString() -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RationalWithMemorizationRing : Ring { - override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO - override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE - - override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right - override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right - - override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this - override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg - override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg - override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RationalWithMemorizationField : Field { - override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO - override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE - - override inline fun number(value: Number): RationalWithMemorization = RationalWithMemorization(value.toLong()) - - override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right - override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right - override inline fun divide(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left / right - override inline fun scale(a: RationalWithMemorization, value: Double): RationalWithMemorization = a * number(value) - - override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this - override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg - override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg - override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg - override inline fun RationalWithMemorization.div(arg: RationalWithMemorization): RationalWithMemorization = this / arg -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt deleted file mode 100644 index a4fb81274..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt +++ /dev/null @@ -1,51 +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.test.misc - -sealed interface OperationsMemory - -interface Endpoint: OperationsMemory - -interface Negation: OperationsMemory { - val negated: OperationsMemory -} - -interface Sum: OperationsMemory { - val augend: OperationsMemory - val addend: OperationsMemory -} - -interface Difference: OperationsMemory { - val minuend: OperationsMemory - val subtrahend: OperationsMemory -} - -interface Product: OperationsMemory { - val multiplicand: OperationsMemory - val multiplier: OperationsMemory -} - -interface Quotient: OperationsMemory { - val dividend: OperationsMemory - val divisor: OperationsMemory -} - - -fun equalMemories(one: OperationsMemory, other: OperationsMemory) : Boolean = - when(one) { - is Negation -> other is Negation && equalMemories(one.negated, other.negated) - is Sum -> other is Sum && equalMemories(one.augend, other.augend) && equalMemories(one.addend, other.addend) - is Difference -> other is Difference && equalMemories(one.minuend, other.minuend) && equalMemories(one.subtrahend, other.subtrahend) - is Product -> other is Product && equalMemories(one.multiplicand, other.multiplicand) && equalMemories(one.multiplier, other.multiplier) - is Quotient -> other is Quotient && equalMemories(one.dividend, other.dividend) && equalMemories(one.divisor, other.divisor) - is Endpoint -> one === other - } - -interface WithMemorization { - val memory: OperationsMemory -} - -fun equalMemories(one: WithMemorization, other: WithMemorization) : Boolean = equalMemories(one.memory, other.memory) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt deleted file mode 100644 index cc647fa2c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ /dev/null @@ -1,31 +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.test.misc - -// TODO: Move to corresponding module "kmath-number-theory" - -import kotlin.math.abs - - -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file From a6b86eeee122ce42229ccef2fb3372828e36b3bc Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 11 Jun 2022 19:31:01 +0300 Subject: [PATCH 070/174] Cleaned out useless code. --- .../kscience/kmath/test/misc/IntModulo.kt | 142 ------------------ .../kscience/kmath/test/misc/Rational.kt | 135 ----------------- .../test/misc/RationalWithMemorization.kt | 107 ------------- .../kscience/kmath/test/misc/memorization.kt | 51 ------- .../space/kscience/kmath/test/misc/misc.kt | 31 ---- 5 files changed, 466 deletions(-) delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt deleted file mode 100644 index 2353beee6..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ /dev/null @@ -1,142 +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.test.misc - -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -class IntModulo { - val residue: Int - val modulus: Int - - @PublishedApi - internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { - if (toCheckInput) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) - } else { - this.residue = residue - this.modulus = modulus - } - } - - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = - IntModulo( - if (residue == 0) 0 else modulus - residue, - modulus, - toCheckInput = false - ) - operator fun plus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not add two residue different modulo" } - return IntModulo( - (residue + other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun plus(other: Int): IntModulo = - IntModulo( - (residue + other) % modulus, - modulus, - toCheckInput = false - ) - operator fun minus(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not subtract two residue different modulo" } - return IntModulo( - (residue - other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun minus(other: Int): IntModulo = - IntModulo( - (residue - other) % modulus, - modulus, - toCheckInput = false - ) - operator fun times(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not multiply two residue different modulo" } - return IntModulo( - (residue * other.residue) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun times(other: Int): IntModulo = - IntModulo( - (residue * other) % modulus, - modulus, - toCheckInput = false - ) - operator fun div(other: IntModulo): IntModulo { - require(modulus == other.modulus) { "can not divide two residue different modulo" } - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - operator fun div(other: Int): IntModulo { - val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) - require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } - return IntModulo( - (residue * reciprocalCandidate) % modulus, - modulus, - toCheckInput = false - ) - } - override fun equals(other: Any?): Boolean = - when (other) { - is IntModulo -> residue == other.residue && modulus == other.modulus - else -> false - } - - override fun hashCode(): Int = residue.hashCode() - - override fun toString(): String = "$residue mod $modulus" -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) -class IntModuloRing : Ring { - - val modulus: Int - - constructor(modulus: Int) { - require(modulus != 0) { "modulus can not be zero" } - this.modulus = if (modulus < 0) -modulus else modulus - } - - override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) - override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) - - override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right - override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right - - override inline fun IntModulo.unaryMinus(): IntModulo = -this - override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg - override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg - override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.number(arg: Int) = IntModulo(arg, ring.modulus, toCheckInput = false) - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt deleted file mode 100644 index 72bb5942c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ /dev/null @@ -1,135 +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.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, NumbersAddOps { - 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 -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt deleted file mode 100644 index 05d9115fa..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/RationalWithMemorization.kt +++ /dev/null @@ -1,107 +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.test.misc - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* - -class RationalWithMemorization private constructor( - val value: Rational, - override val memory : OperationsMemory -): WithMemorization { - companion object { - /** - * Constant containing the zero (the additive identity) of the [Rational] field. - */ - public val ZERO: RationalWithMemorization = RationalWithMemorization(Rational.ZERO, object : Endpoint {}) - /** - * Constant containing the one (the multiplicative identity) of the [Rational] field. - */ - public val ONE: RationalWithMemorization = RationalWithMemorization(Rational.ONE, object : Endpoint {}) - } - constructor(numerator: Int, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Int) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Long, denominator: Long) : this(Rational(numerator, denominator), object : Endpoint {}) - constructor(numerator: Int) : this(Rational(numerator), object : Endpoint {}) - constructor(numerator: Long) : this(Rational(numerator), object : Endpoint {}) - - operator fun unaryPlus(): RationalWithMemorization = this - operator fun unaryMinus(): RationalWithMemorization = RationalWithMemorization( - -value, - object : Negation { - override val negated: OperationsMemory = memory - } - ) - operator fun plus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value + other.value, - object : Sum { - override val augend: OperationsMemory = memory - override val addend: OperationsMemory = other.memory - } - ) - operator fun minus(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value - other.value, - object : Difference { - override val minuend: OperationsMemory = memory - override val subtrahend: OperationsMemory = other.memory - } - ) - operator fun times(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value * other.value, - object : Product { - override val multiplicand: OperationsMemory = memory - override val multiplier: OperationsMemory = other.memory - } - ) - operator fun div(other: RationalWithMemorization): RationalWithMemorization = RationalWithMemorization( - value / other.value, - object : Quotient { - override val dividend: OperationsMemory = memory - override val divisor: OperationsMemory = other.memory - } - ) - - override fun equals(other: Any?): Boolean = - other is RationalWithMemorization && value == other.value - - override fun hashCode(): Int = value.hashCode() - - override fun toString(): String = value.toString() -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RationalWithMemorizationRing : Ring { - override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO - override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE - - override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right - override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right - - override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this - override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg - override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg - override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg -} - -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -object RationalWithMemorizationField : Field { - override inline val zero: RationalWithMemorization get() = RationalWithMemorization.ZERO - override inline val one: RationalWithMemorization get() = RationalWithMemorization.ONE - - override inline fun number(value: Number): RationalWithMemorization = RationalWithMemorization(value.toLong()) - - override inline fun add(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left + right - override inline fun multiply(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left * right - override inline fun divide(left: RationalWithMemorization, right: RationalWithMemorization): RationalWithMemorization = left / right - override inline fun scale(a: RationalWithMemorization, value: Double): RationalWithMemorization = a * number(value) - - override inline fun RationalWithMemorization.unaryMinus(): RationalWithMemorization = -this - override inline fun RationalWithMemorization.plus(arg: RationalWithMemorization): RationalWithMemorization = this + arg - override inline fun RationalWithMemorization.minus(arg: RationalWithMemorization): RationalWithMemorization = this - arg - override inline fun RationalWithMemorization.times(arg: RationalWithMemorization): RationalWithMemorization = this * arg - override inline fun RationalWithMemorization.div(arg: RationalWithMemorization): RationalWithMemorization = this / arg -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt deleted file mode 100644 index a4fb81274..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/memorization.kt +++ /dev/null @@ -1,51 +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.test.misc - -sealed interface OperationsMemory - -interface Endpoint: OperationsMemory - -interface Negation: OperationsMemory { - val negated: OperationsMemory -} - -interface Sum: OperationsMemory { - val augend: OperationsMemory - val addend: OperationsMemory -} - -interface Difference: OperationsMemory { - val minuend: OperationsMemory - val subtrahend: OperationsMemory -} - -interface Product: OperationsMemory { - val multiplicand: OperationsMemory - val multiplier: OperationsMemory -} - -interface Quotient: OperationsMemory { - val dividend: OperationsMemory - val divisor: OperationsMemory -} - - -fun equalMemories(one: OperationsMemory, other: OperationsMemory) : Boolean = - when(one) { - is Negation -> other is Negation && equalMemories(one.negated, other.negated) - is Sum -> other is Sum && equalMemories(one.augend, other.augend) && equalMemories(one.addend, other.addend) - is Difference -> other is Difference && equalMemories(one.minuend, other.minuend) && equalMemories(one.subtrahend, other.subtrahend) - is Product -> other is Product && equalMemories(one.multiplicand, other.multiplicand) && equalMemories(one.multiplier, other.multiplier) - is Quotient -> other is Quotient && equalMemories(one.dividend, other.dividend) && equalMemories(one.divisor, other.divisor) - is Endpoint -> one === other - } - -interface WithMemorization { - val memory: OperationsMemory -} - -fun equalMemories(one: WithMemorization, other: WithMemorization) : Boolean = equalMemories(one.memory, other.memory) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt deleted file mode 100644 index cc647fa2c..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ /dev/null @@ -1,31 +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.test.misc - -// TODO: Move to corresponding module "kmath-number-theory" - -import kotlin.math.abs - - -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) - -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) - -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = - when { - a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } - a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } - b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } - else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) - } - -internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = - if (b == 0) BezoutIdentityWithGCD(m1, m3, a) - else { - val quotient = a / b - val reminder = a % b - bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) - } \ No newline at end of file From 17703e407dd33dcddff3608c9a8fa06c052af8d7 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 00:24:23 +0300 Subject: [PATCH 071/174] Applied changes from previous sift. --- .../kscience/kmath/functions/Polynomial.kt | 150 ++++-- .../kmath/functions/RationalFunction.kt | 467 +++++++++++++----- 2 files changed, 468 insertions(+), 149 deletions(-) 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 e201f1f6e..f2eba10d5 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 @@ -25,38 +25,38 @@ public interface Polynomial @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -72,38 +72,38 @@ public interface PolynomialSpace> : Ring

{ public fun Int.asConstant(): C = constantNumber(this) /** - * 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]. */ public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** - * 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]. */ public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** - * 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]. */ public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** - * 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]. */ public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** - * 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]. */ public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** - * 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]. */ @@ -165,28 +165,28 @@ public interface PolynomialSpace> : Ring

{ public val constantOne: 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 operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -254,41 +254,44 @@ public interface PolynomialSpace> : Ring

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,143 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..edc9dfa5c 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a 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 = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a 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 = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: 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 operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * 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: P): P = polynomialRing { this@plus + other } /** - * 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: P): P = polynomialRing { this@minus - other } /** - * 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: P): P = polynomialRing { this@times * other } /** - * 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 P.plus(other: C): P = polynomialRing { this@plus + other } /** - * 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 P.minus(other: C): P = polynomialRing { this@minus - other } /** - * 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 P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -826,7 +842,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +852,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +862,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -873,7 +889,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +897,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,7 +905,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( @@ -904,7 +920,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +928,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,7 +936,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( @@ -940,7 +956,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +964,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,7 +972,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( @@ -971,7 +987,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +995,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( @@ -1052,6 +1068,15 @@ public abstract class PolynomialSpaceOfFractions< public override val one: R get() = constructRationalFunction(polynomialOne) } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1084,175 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1291,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1309,135 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1467,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1484,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1512,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( From 569e01fce13f890e8c938d90ac4285e99f3b3e93 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 12 Jun 2022 15:16:40 +0300 Subject: [PATCH 072/174] Migration to kotlin 1.7 --- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 13 +++---- buildSrc/gradle.properties | 7 ---- buildSrc/settings.gradle.kts | 14 ++++++-- .../kmath/ejml/codegen/ejmlCodegen.kt | 4 ++- gradle.properties | 5 ++- kmath-ast/build.gradle.kts | 2 +- kmath-core/build.gradle.kts | 4 +-- .../space/kscience/kmath/nd/AlgebraND.kt | 19 ---------- .../kscience/kmath/nd/BufferAlgebraND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/Shape.kt | 35 +++++++++++++++++++ .../space/kscience/kmath/nd/ShapeIndexer.kt | 14 +++++--- .../space/kscience/kmath/nd/StructureND.kt | 4 +-- .../kscience/kmath/nd/VirtualStructureND.kt | 18 ++++++++-- .../space/kscience/kmath/nd/operationsND.kt | 32 +++++++++++++++++ .../kscience/kmath/nd/NdOperationsTest.kt | 28 +++++++++++++++ .../space/kscience/kmath/ejml/_generated.kt | 16 ++++++--- .../kscience/kmath/ejml/EjmlMatrixTest.kt | 6 ++-- kmath-histograms/build.gradle.kts | 8 ++--- .../kmath/histogram/TreeHistogramTest.kt | 2 ++ kmath-memory/build.gradle.kts | 3 +- kmath-optimization/build.gradle.kts | 5 +-- kmath-stat/build.gradle.kts | 5 +-- .../space/kscience/kmath/stat/Sampler.kt | 2 ++ .../space/kscience/kmath/stat/MCScopeTest.kt | 2 +- .../kscience/kmath/viktor/ViktorFieldOpsND.kt | 1 + settings.gradle.kts | 20 ++++++++++- 27 files changed, 200 insertions(+), 73 deletions(-) delete mode 100644 buildSrc/gradle.properties create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 9fa012fb2..ab136bfbc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1" + version = "0.3.1-dev-1" } subprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index dcb39d448..20611e92d 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - kotlin("jvm") version "1.7.0-RC" + kotlin("jvm") version "1.7.0" `kotlin-dsl` `version-catalog` - alias(miptNpmLibs.plugins.kotlin.plugin.serialization) + alias(npmlibs.plugins.kotlin.plugin.serialization) } java.targetCompatibility = JavaVersion.VERSION_11 @@ -14,17 +14,18 @@ repositories { gradlePluginPortal() } -val toolsVersion: String by extra -val kotlinVersion = miptNpmLibs.versions.kotlin.asProvider().get() -val benchmarksVersion = miptNpmLibs.versions.kotlinx.benchmark.get() +val toolsVersion = npmlibs.versions.tools.get() +val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() +val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() dependencies { api("ru.mipt.npm:gradle-tools:$toolsVersion") + api(npmlibs.atomicfu.gradle) //plugins form benchmarks api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") //to be used inside build-script only - implementation(miptNpmLibs.kotlinx.serialization.json) + implementation(npmlibs.kotlinx.serialization.json) } kotlin.sourceSets.all { diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties deleted file mode 100644 index 751caec36..000000000 --- a/buildSrc/gradle.properties +++ /dev/null @@ -1,7 +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. -# - -kotlin.code.style=official -toolsVersion=0.11.5-kotlin-1.7.0-RC diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index 7c1df133d..bce265510 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -6,7 +6,17 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") dependencyResolutionManagement { - val toolsVersion: String by extra + val projectProperties = java.util.Properties() + file("../gradle.properties").inputStream().use { + projectProperties.load(it) + } + + projectProperties.forEach { key, value -> + extra.set(key.toString(), value) + } + + + val toolsVersion: String = projectProperties["toolsVersion"].toString() repositories { mavenLocal() @@ -16,7 +26,7 @@ dependencyResolutionManagement { } versionCatalogs { - create("miptNpmLibs") { + create("npmlibs") { from("ru.mipt.npm:version-catalog:$toolsVersion") } } diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt index 7f8cb35b3..7c23d8ea0 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt @@ -319,7 +319,9 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } else -> null - }?.let(type::cast) + }?.let{ + type.cast(it) + } } /** diff --git a/gradle.properties b/gradle.properties index 4923364d8..9cdd7801c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,10 @@ kotlin.code.style=official kotlin.jupyter.add.scanner=false kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true -#kotlin.incremental.js.ir=true +//kotlin.incremental.js.ir=true org.gradle.configureondemand=true org.gradle.parallel=true +org.gradle.jvmargs=-Xmx4096m + +toolsVersion=0.11.6-kotlin-1.7.0 diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 15b1d0900..0dd625ef1 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -57,7 +57,7 @@ tasks.dokkaHtml { if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") tasks.jvmTest { - jvmArgs = (jvmArgs ?: emptyList()) + listOf("-Dspace.kscience.kmath.ast.dump.generated.classes=1") + jvmArgs("-Dspace.kscience.kmath.ast.dump.generated.classes=1") } readme { diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 4a35a54fb..052924ce8 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -1,8 +1,6 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.mpp") id("ru.mipt.npm.gradle.native") -// id("com.xcporter.metaview") version "0.0.5" } kotlin.sourceSets { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index a9712e870..ad291cf7f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -10,25 +10,6 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import kotlin.reflect.KClass -/** - * An exception is thrown when the expected and actual shape of NDArray differ. - * - * @property expected the expected shape. - * @property actual the actual shape. - */ -public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : - RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") - -public typealias Shape = IntArray - -public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = intArrayOf(shapeFirst, *shapeRest) - -public interface WithShape { - public val shape: Shape - - public val indices: ShapeIndexer get() = DefaultStrides(shape) -} - /** * The base interface for all ND-algebra implementations. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt index b09344d12..68e8ebe90 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt @@ -47,7 +47,7 @@ public interface BufferAlgebraND> : AlgebraND { zipInline(left.toBufferND(), right.toBufferND(), transform) public companion object { - public val defaultIndexerBuilder: (IntArray) -> ShapeIndexer = DefaultStrides.Companion::invoke + public val defaultIndexerBuilder: (IntArray) -> ShapeIndexer = ::Strides } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt new file mode 100644 index 000000000..d682d5e69 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt @@ -0,0 +1,35 @@ +/* + * 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.nd + +/** + * An exception is thrown when the expected and actual shape of NDArray differ. + * + * @property expected the expected shape. + * @property actual the actual shape. + */ +public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : + RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") + +public class IndexOutOfShapeException(public val shape: Shape, public val index: IntArray) : + RuntimeException("Index ${index.contentToString()} is out of shape ${shape.contentToString()}") + +public typealias Shape = IntArray + +public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = intArrayOf(shapeFirst, *shapeRest) + +public interface WithShape { + public val shape: Shape + + public val indices: ShapeIndexer get() = DefaultStrides(shape) +} + +internal fun requireIndexInShape(index: IntArray, shape: Shape) { + if (index.size != shape.size) throw IndexOutOfShapeException(index, shape) + shape.forEachIndexed { axis, axisShape -> + if (index[axis] !in 0 until axisShape) throw IndexOutOfShapeException(index, shape) + } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt index c6ff79587..29701425f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt @@ -10,7 +10,7 @@ import kotlin.native.concurrent.ThreadLocal /** * A converter from linear index to multivariate index */ -public interface ShapeIndexer: Iterable{ +public interface ShapeIndexer : Iterable { public val shape: Shape /** @@ -44,7 +44,7 @@ public interface ShapeIndexer: Iterable{ /** * Linear transformation of indexes */ -public abstract class Strides: ShapeIndexer { +public abstract class Strides : ShapeIndexer { /** * Array strides */ @@ -66,7 +66,7 @@ public abstract class Strides: ShapeIndexer { /** * Simple implementation of [Strides]. */ -public class DefaultStrides private constructor(override val shape: IntArray) : Strides() { +public class DefaultStrides(override val shape: IntArray) : Strides() { override val linearSize: Int get() = strides[shape.size] /** @@ -112,10 +112,16 @@ public class DefaultStrides private constructor(override val shape: IntArray) : /** * Cached builder for default strides */ + @Deprecated("Replace by Strides(shape)") public operator fun invoke(shape: IntArray): Strides = defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } } } @ThreadLocal -private val defaultStridesCache = HashMap() \ No newline at end of file +private val defaultStridesCache = HashMap() + +/** + * Cached builder for default strides + */ +public fun Strides(shape: IntArray): Strides = defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index d948cf36f..e934c6370 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -101,8 +101,8 @@ public interface StructureND : Featured, WithShape { val bufferRepr: String = when (structure.shape.size) { 1 -> (0 until structure.shape[0]).map { structure[it] } .joinToString(prefix = "[", postfix = "]", separator = ", ") - 2 -> (0 until structure.shape[0]).joinToString(prefix = "[", postfix = "]", separator = ", ") { i -> - (0 until structure.shape[1]).joinToString(prefix = "[", postfix = "]", separator = ", ") { j -> + 2 -> (0 until structure.shape[0]).joinToString(prefix = "[\n", postfix = "\n]", separator = ",\n") { i -> + (0 until structure.shape[1]).joinToString(prefix = " [", postfix = "]", separator = ", ") { j -> structure[i, j].toString() } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt index 799d14b3d..7e86ea73d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt @@ -5,12 +5,26 @@ package space.kscience.kmath.nd +import space.kscience.kmath.misc.UnstableKMathAPI + public open class VirtualStructureND( override val shape: Shape, public val producer: (IntArray) -> T, ) : StructureND { override fun get(index: IntArray): T { - require(check that index is in the shape boundaries) + requireIndexInShape(index, shape) return producer(index) } -} \ No newline at end of file +} + +@UnstableKMathAPI +public class VirtualDoubleStructureND( + shape: Shape, + producer: (IntArray) -> Double, +) : VirtualStructureND(shape, producer) + +@UnstableKMathAPI +public class VirtualIntStructureND( + shape: Shape, + producer: (IntArray) -> Int, +) : VirtualStructureND(shape, producer) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt new file mode 100644 index 000000000..c9624dc4e --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt @@ -0,0 +1,32 @@ +/* + * 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.nd + +public fun StructureND.roll(axis: Int, step: Int = 1): StructureND { + require(axis in shape.indices) { "Axis $axis is outside of shape dimensions: [0, ${shape.size})" } + return VirtualStructureND(shape) { index -> + val newIndex: IntArray = IntArray(index.size) { indexAxis -> + if (indexAxis == axis) { + (index[indexAxis] + step).mod(shape[indexAxis]) + } else { + index[indexAxis] + } + } + get(newIndex) + } +} + +public fun StructureND.roll(pair: Pair, vararg others: Pair): StructureND { + val axisMap: Map = mapOf(pair, *others) + require(axisMap.keys.all { it in shape.indices }) { "Some of axes ${axisMap.keys} is outside of shape dimensions: [0, ${shape.size})" } + return VirtualStructureND(shape) { index -> + val newIndex: IntArray = IntArray(index.size) { indexAxis -> + val offset = axisMap[indexAxis] ?: 0 + (index[indexAxis] + offset).mod(shape[indexAxis]) + } + get(newIndex) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt new file mode 100644 index 000000000..25b062b44 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.nd + +import space.kscience.kmath.operations.DoubleField +import kotlin.test.Test +import kotlin.test.assertEquals + +class NdOperationsTest { + @Test + fun roll() { + val structure = DoubleField.ndAlgebra.structureND(5, 5) { index -> + index.sumOf { it.toDouble() } + } + + println(StructureND.toString(structure)) + + val rolled = structure.roll(0,-1) + + println(StructureND.toString(rolled)) + + assertEquals(4.0, rolled[0, 0]) + } + +} \ No newline at end of file diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt index dce739dc2..aac327a84 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -271,7 +271,9 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace null - }?.let(type::cast) + }?.let{ + type.cast(it) + } } /** @@ -505,7 +507,9 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace null - }?.let(type::cast) + }?.let{ + type.cast(it) + } } /** @@ -734,7 +738,9 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace null - }?.let(type::cast) + }?.let{ + type.cast(it) + } } /** @@ -963,7 +969,9 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace null - }?.let(type::cast) + }?.let{ + type.cast(it) + } } /** diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index 209bb5b27..af6284e5e 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:OptIn(PerformancePitfall::class) + package space.kscience.kmath.ejml import org.ejml.data.DMatrixRMaj @@ -18,11 +20,11 @@ import kotlin.random.Random import kotlin.random.asJavaRandom import kotlin.test.* -@OptIn(PerformancePitfall::class) -fun assertMatrixEquals(expected: StructureND, actual: StructureND) { +internal fun assertMatrixEquals(expected: StructureND, actual: StructureND) { assertTrue { StructureND.contentEquals(expected, actual) } } +@OptIn(UnstableKMathAPI::class) internal class EjmlMatrixTest { private val random = Random(0) diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 51271bb0a..786086c9f 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,17 +1,15 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.mpp") id("ru.mipt.npm.gradle.native") } -kscience { - useAtomic() -} +//apply(plugin = "kotlinx-atomicfu") kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-core")) + api(npmlibs.atomicfu) } } commonTest { diff --git a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt index c4eeb53cc..2c56a88a7 100644 --- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt +++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt @@ -6,12 +6,14 @@ package space.kscience.kmath.histogram import org.junit.jupiter.api.Test +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.real.step import kotlin.random.Random import kotlin.test.assertEquals import kotlin.test.assertTrue +@OptIn(UnstableKMathAPI::class) class TreeHistogramTest { @Test diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 4478e5b80..2bd6dd723 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.mpp") id("ru.mipt.npm.gradle.native") } diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index b920b9267..2e5bf6005 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -3,10 +3,6 @@ plugins { id("ru.mipt.npm.gradle.native") } -kscience { - useAtomic() -} - kotlin.sourceSets { all { languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") @@ -15,6 +11,7 @@ kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-coroutines")) + api(npmlibs.atomicfu) } } } diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index 41a1666f8..b458135b3 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -3,14 +3,11 @@ plugins { id("ru.mipt.npm.gradle.native") } -kscience { - useAtomic() -} - kotlin.sourceSets { commonMain { dependencies { api(project(":kmath-coroutines")) + implementation(npmlibs.atomicfu) } } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index c96ecdc8c..a88f3e437 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.stat import kotlinx.coroutines.flow.first import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.combine +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer @@ -30,6 +31,7 @@ public fun interface Sampler { /** * Sample a bunch of values */ +@OptIn(UnstableKMathAPI::class) public fun Sampler.sampleBuffer( generator: RandomGenerator, size: Int, diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt index 075d7f3e5..cca645809 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt @@ -66,7 +66,7 @@ class MCScopeTest { } - @OptIn(ObsoleteCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) fun compareResult(test: ATest) { val res1 = runBlocking(Dispatchers.Default) { test() } val res2 = runBlocking(newSingleThreadContext("test")) { test() } diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt index 1d4d6cebd..cecbc35b8 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt @@ -117,6 +117,7 @@ public open class ViktorFieldOpsND : public val DoubleField.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND +@OptIn(UnstableKMathAPI::class) public open class ViktorFieldND( override val shape: Shape, ) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { diff --git a/settings.gradle.kts b/settings.gradle.kts index b3c275810..b14c594b4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,24 @@ rootProject.name = "kmath" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + +dependencyResolutionManagement { + val toolsVersion: String by extra + + repositories { + mavenLocal() + maven("https://repo.kotlin.link") + mavenCentral() + gradlePluginPortal() + } + + versionCatalogs { + create("npmlibs") { + from("ru.mipt.npm:version-catalog:$toolsVersion") + } + } +} + include( ":kmath-memory", ":kmath-complex", @@ -27,4 +45,4 @@ include( ":kmath-jafama", ":examples", ":benchmarks", -) +) \ No newline at end of file From e1276b684f5b4220b01842f325a0407d14a1415f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 12 Jun 2022 15:19:59 +0300 Subject: [PATCH 073/174] Update better-parse --- kmath-ast/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 0dd625ef1..f49c2767a 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -24,7 +24,7 @@ kotlin.sourceSets { commonMain { dependencies { - api("com.github.h0tk3y.betterParse:better-parse:0.4.2") + api("com.github.h0tk3y.betterParse:better-parse:0.4.4") api(project(":kmath-core")) } } From fabad733f4cb9436fd3dd34ea0dbb3871e0348ea Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 12 Jun 2022 15:30:10 +0300 Subject: [PATCH 074/174] Fix binaryen module creation --- .../kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt index aacb62f36..878919d8d 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt @@ -71,7 +71,7 @@ internal sealed class WasmBuilder>( protected open fun visitBinary(mst: TypedMst.Binary): ExpressionRef = error("Binary operation ${mst.operation} not defined in $this") - protected open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") + protected open fun createModule(): BinaryenModule = space.kscience.kmath.internal.binaryen.Module() protected fun visit(node: TypedMst): ExpressionRef = when (node) { is TypedMst.Constant -> visitNumber( From 3a6aa1432094c6803ac026593e3035c14a51111d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 22:52:08 +0300 Subject: [PATCH 075/174] Cleaned up ListPolynomials and ListRationalFunctions: - Added/updated docs. - Fully (but in a simple way) implemented invocation, substitution, functional representation, derivatives and antiderivatives. Optimized reimplementation is in progress. - Upgraded `PolynomialSpaceOfFractions` by adding a bit of laziness. - Other little things... --- .../kmath/functions/ListPolynomial.kt | 80 ++++-- .../kmath/functions/ListRationalFunction.kt | 159 +++++++---- .../kscience/kmath/functions/Polynomial.kt | 2 + .../kmath/functions/RationalFunction.kt | 10 +- .../kmath/functions/listPolynomialUtil.kt | 233 --------------- .../kscience/kmath/functions/listUtil.kt | 268 ++++++++++++++++++ ...alFunctionUtil.kt => listUtilOptimized.kt} | 129 +++++---- .../space/kscience/kmath/functions/misc.kt | 13 + .../kmath/functions/ListPolynomialUtilTest.kt | 2 + .../kscience/kmath/test/misc/Rational.kt | 135 +++++++++ .../space/kscience/kmath/test/misc/misc.kt | 11 + 11 files changed, 667 insertions(+), 375 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{listRationalFunctionUtil.kt => listUtilOptimized.kt} (72%) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 585da95ea..fce179fc8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -8,23 +8,19 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName import kotlin.math.max 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. */ public data class ListPolynomial( /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as * ``` * listOf( * -6, // -6 + @@ -42,26 +38,28 @@ public data class ListPolynomial( * 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 - * prohibited. + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. */ public val coefficients: List ) : Polynomial { - override fun toString(): String = "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 A type of underlying ring of constants. It's [Ring] of [C]. + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ public open class ListPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** - * Returns sum of the polynomial and the integer represented as 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]. */ @@ -79,7 +77,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -97,7 +95,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -112,7 +110,7 @@ public open class ListPolynomialSpace>( ) /** - * 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]. */ @@ -130,7 +128,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -150,7 +148,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -170,7 +168,7 @@ public open class ListPolynomialSpace>( public override fun number(value: Int): ListPolynomial = 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): ListPolynomial = with(other.coefficients) { @@ -186,7 +184,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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): ListPolynomial = with(other.coefficients) { @@ -204,7 +202,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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): ListPolynomial = ListPolynomial( @@ -216,7 +214,7 @@ public open class ListPolynomialSpace>( ) /** - * 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.plus(other: C): ListPolynomial = with(coefficients) { @@ -232,7 +230,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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.minus(other: C): ListPolynomial = with(coefficients) { @@ -248,7 +246,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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.times(other: C): ListPolynomial = ListPolynomial( @@ -262,7 +260,7 @@ public open class ListPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): ListPolynomial = ListPolynomial(value) + public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) /** * Returns negation of the polynomial. @@ -321,9 +319,9 @@ public open class ListPolynomialSpace>( */ override val zero: ListPolynomial = ListPolynomial(emptyList()) /** - * Instance of unit constant (unit of the underlying ring). + * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) + override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is @@ -331,23 +329,43 @@ public open class ListPolynomialSpace>( */ public override val ListPolynomial.degree: Int get() = coefficients.lastIndex + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided argument. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } /** - * Evaluates the polynomial for the given value [argument]. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 7b6c23ac3..45ea99fb0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -8,13 +8,23 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring +/** + * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + */ public data class ListRationalFunction( public override val numerator: ListPolynomial, public override val denominator: ListPolynomial ) : RationalFunction> { - 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> ( public val ring: A, ) : @@ -30,7 +40,13 @@ public class ListRationalFunctionSpace> ( ListRationalFunction, >() { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) + /** + * Constructor of [ListRationalFunction] from numerator and denominator [ListPolynomial]. + */ override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, denominator) @@ -43,63 +59,88 @@ public class ListRationalFunctionSpace> ( */ public override val one: ListRationalFunction = 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.substitute(argument: C): C = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) } \ No newline at end of file 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 f2eba10d5..12490d133 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 @@ -435,10 +435,12 @@ public interface MultivariatePolynomialSpace>: Polynomial /** * Represents the [variable] as a monic monomial. */ + @JvmName("numberVariable") public fun number(variable: V): P = +variable /** * Represents the variable as a monic monomial. */ + @JvmName("asPolynomialVariable") public fun V.asPolynomial(): P = number(this) /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index edc9dfa5c..4ce6c7c26 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1060,12 +1060,12 @@ public abstract class PolynomialSpaceOfFractions< /** * 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). */ - 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. */ + @JvmName("polynomialNumberVariable") public fun polynomialNumber(variable: V): P = +variable /** * Represents the variable as a monic monomial. */ + @JvmName("asPolynomialVariable") public fun V.asPolynomial(): P = polynomialNumber(this) /** * Represents the [variable] as a rational function. */ + @JvmName("numberVariable") public fun number(variable: V): R = number(polynomialNumber(variable)) /** * Represents the variable as a rational function. */ + @JvmName("asRationalFunctionVariable") public fun V.asRationalFunction(): R = number(this) /** @@ -1403,10 +1407,12 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp /** * Represents the [variable] as a monic monomial. */ + @JvmName("polynomialNumberVariable") public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } /** * Represents the variable as a monic monomial. */ + @JvmName("asPolynomialVariable") public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -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) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - 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 multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = 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.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 ListPolynomial.substitute(ring: Ring, 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 ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = 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 = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = 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(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt new file mode 100644 index 000000000..127dd8c7a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -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 > A.listPolynomialSpace(): ListPolynomialSpace = + ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} + +/** + * Returns algebraic derivative of received rational function. + */ +@UnstableKMathAPI +public fun ListRationalFunction.derivative( + ring: A, +): ListRationalFunction where A : Ring, A : NumericAlgebra = 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 ListRationalFunction.nthDerivative( + ring: A, + order: Int, +): ListRationalFunction where A : Ring, A : NumericAlgebra = + if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt index 367212588..6eb3a1dc7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt @@ -5,41 +5,91 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.math.max +import kotlin.math.min -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() +// TODO: Optimized copies of substitution and invocation +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingToUpdater( + ring: Ring, + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + 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 + } +} -/** - * 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 ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = 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 ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = 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 = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] + val resultCoefsUpdate: MutableList = 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(resultCoefs) } /** @@ -52,6 +102,7 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r * * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать +@UnstablePolynomialBoxingOptimization internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) @@ -196,26 +247,4 @@ internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: end = thisDegree + 1 ) ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// 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 > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt new file mode 100644 index 000000000..8b6fac39e --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -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 \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c5eb8fb81..69c1611f3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test @@ -12,6 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith +@OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_substitute_Double() { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt new file mode 100644 index 000000000..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -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, NumbersAddOps { + 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 +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..873162a1b --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -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) \ No newline at end of file From e7100138006c0b7f91ee40135a40498b09ddeebe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 23:02:26 +0300 Subject: [PATCH 076/174] Fixed tests. --- .../kmath/functions/ListPolynomialTest.kt | 32 ++-- .../kscience/kmath/test/misc/IntModulo.kt | 140 ++++++++++++++++++ .../space/kscience/kmath/test/misc/misc.kt | 20 ++- 3 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 5401be707..c9950fac5 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -12,7 +12,7 @@ import kotlin.test.* class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, @@ -52,7 +52,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, @@ -92,7 +92,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27, @@ -107,7 +107,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -147,7 +147,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -187,7 +187,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -202,7 +202,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), @@ -242,7 +242,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), @@ -282,7 +282,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), @@ -297,7 +297,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -337,7 +337,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -377,7 +377,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -392,7 +392,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -407,7 +407,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 assertEquals( ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), @@ -440,7 +440,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 assertEquals( ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), @@ -473,7 +473,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 assertEquals( ListPolynomial(1, 0, 1, 0, 1), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..36a0d8be5 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,140 @@ +/* + * 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.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@OptIn(UnstableKMathAPI::class) +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt index 873162a1b..ed41b9245 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -8,4 +8,22 @@ 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) \ No newline at end of file +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file From 94fd24d8524140c945412b980df8e5252a10e811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 12 Jun 2022 23:49:44 +0300 Subject: [PATCH 077/174] Fixed some tests and docstrings. Removed `zero` and `one` overridings because overrided fields are already lazily initialized. --- .../kmath/functions/ListRationalFunction.kt | 9 ----- .../kmath/functions/RationalFunction.kt | 34 +++++++++++++++---- .../kscience/kmath/test/misc/IntModulo.kt | 2 -- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 45ea99fb0..f3e352bcd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -50,15 +50,6 @@ public class ListRationalFunctionSpace> ( override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, denominator) - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) - // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with // [ListPolynomialSpace] as a context receiver /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 4ce6c7c26..01911f980 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -834,7 +834,12 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the integer represented as a rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ public override operator fun R.div(other: Int): R = constructRationalFunction( numerator, @@ -871,7 +876,12 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the integer represented as a rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ public override operator fun Int.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -912,7 +922,9 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the constant represented as a polynomial and the rational function. + */ public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -943,7 +955,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the constant represented as a rational function. + */ public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -979,7 +993,9 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the polynomial represented as a polynomial and the rational function. + */ public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -1010,7 +1026,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the polynomial represented as a rational function. + */ public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1050,7 +1068,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.numerator, denominator * other.denominator ) - + /** + * Returns quotient of the rational functions. + */ public override operator fun R.div(other: R): R = constructRationalFunction( numerator * other.denominator, diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 36a0d8be5..89764db46 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -109,7 +108,6 @@ class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -@OptIn(UnstableKMathAPI::class) class IntModuloRing : Ring { val modulus: Int From ab9bba22022187b0437e9fc085b16cd8cbf232fe Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 00:16:22 +0300 Subject: [PATCH 078/174] Put suddenly disappeared files back. --- .../kmath/functions/listConstructors.kt | 65 +++++++++ .../kscience/kmath/test/misc/Rational.kt | 135 ++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt new file mode 100644 index 000000000..fc55ba310 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring + + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +@Suppress("FunctionName") +public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) + +//context(A) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +//context(ListRationalFunctionSpace) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt new file mode 100644 index 000000000..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -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, NumbersAddOps { + 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 +} \ No newline at end of file From dbb48a2a9f3ecabc0eb0aeb7e7c72d589aba0c4f Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 01:41:04 +0300 Subject: [PATCH 079/174] Added docstrings to ListPolynomial and ListRationalFunction fabric functions. --- .../kmath/functions/listConstructors.kt | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index fc55ba310..35c736914 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -14,52 +14,84 @@ import space.kscience.kmath.operations.Ring /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) +/** + * Represents [this] constant as a [ListPolynomial]. + */ public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ @Suppress("FunctionName") public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial(listOf(one)) ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(A) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(ListRationalFunctionSpace) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file From 37ad48e820cde271ba93d1249b84b0abfd033f21 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 02:06:15 +0300 Subject: [PATCH 080/174] Sift # 3. Filtered last sift and usages of [ListPolynomial]s. --- .../kmath/functions/LabeledPolynomial.kt | 539 ------------------ .../functions/LabeledRationalFunction.kt | 139 ----- .../kmath/functions/ListPolynomial.kt | 80 ++- .../kmath/functions/ListRationalFunction.kt | 158 +++-- .../kmath/functions/NumberedPolynomial.kt | 389 ------------- .../functions/NumberedRationalFunction.kt | 188 ------ .../kscience/kmath/functions/Polynomial.kt | 152 ++++- .../kmath/functions/RationalFunction.kt | 511 ++++++++++++----- .../kmath/functions/labeledConstructors.kt | 203 ------- .../kmath/functions/labeledPolynomialUtil.kt | 495 ---------------- .../functions/labeledRationalFunctionUtil.kt | 33 -- .../kmath/functions/listConstructors.kt | 61 +- .../kmath/functions/listPolynomialUtil.kt | 233 -------- .../kscience/kmath/functions/listUtil.kt | 268 +++++++++ ...alFunctionUtil.kt => listUtilOptimized.kt} | 129 +++-- .../space/kscience/kmath/functions/misc.kt | 13 + .../kmath/functions/numberedConstructors.kt | 195 ------- .../kmath/functions/numberedPolynomialUtil.kt | 528 ----------------- .../functions/numberedRationalFunctionUtil.kt | 33 -- .../kmath/functions/ListPolynomialTest.kt | 32 +- .../kmath/functions/ListPolynomialUtilTest.kt | 2 + .../kscience/kmath/test/misc/IntModulo.kt | 138 +++++ .../kscience/kmath/test/misc/Rational.kt | 135 +++++ .../space/kscience/kmath/test/misc/misc.kt | 29 + 24 files changed, 1378 insertions(+), 3305 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt rename kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/{listRationalFunctionUtil.kt => listUtilOptimized.kt} (72%) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt deleted file mode 100644 index b904f7331..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ /dev/null @@ -1,539 +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.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.math.max - - -/** - * Represents multivariate polynomials with labeled variables. - * - * @param C Ring in which the polynomial is considered. - */ -public data class LabeledPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every non-zero monomial - * `a x_1^{d_1} ... x_n^{d_n}` is represented as pair "key-value" in the map, where value is coefficients `a` and - * key is map that associates variables in the monomial with multiplicity of them occurring in the monomial. - * For example polynomial - * ``` - * 5 a^2 c^3 - 6 b + 0 b c - * ``` - * has coefficients represented as - * ``` - * mapOf( - * mapOf( - * a to 2, - * c to 3 - * ) to 5, - * mapOf( - * b to 1 - * ) to (-6) - * ) - * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "LabeledPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public class LabeledPolynomialSpace>( - public override val ring: A, -) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { - public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) - public override operator fun Symbol.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * other, - )) - - public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, - )) - public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to constantOne * this@minus, - )) - public override operator fun Int.times(other: Symbol): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne * this@times, - )) - - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + 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 override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to (-other).asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * 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 override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus.asConstant())) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - - public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to constantOne, - emptyMap() to this@plus, - )) - public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to -constantOne, - emptyMap() to this@minus, - )) - public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(other to 1U) to this@times, - )) - - public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@plus to 1U) to constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) - public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this@times to 1U) to other, - )) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@plus)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to this@minus)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(emptyMap() to other)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = - LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) - - public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - )) - public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomial(mapOf( - mapOf(this to 1U) to -constantOne, - )) - public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to constantOne, - )) - public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = - if (this == other) zero - else LabeledPolynomial(mapOf( - mapOf(this to 1U) to constantOne, - mapOf(other to 1U) to -constantOne, - )) - public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomial(mapOf( - mapOf(this to 2U) to constantOne - )) - else LabeledPolynomial(mapOf( - mapOf(this to 1U, other to 1U) to constantOne, - )) - - public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@plus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(this@minus to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = mapOf(this@minus to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } - ) - - public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) LabeledPolynomial(mapOf(mapOf(other to 1u) to constantOne)) - else LabeledPolynomial( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne - getOrElse(degs) { constantZero } - } - ) - } - public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = - LabeledPolynomial( - coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } - ) - - /** - * Returns negation of the polynomial. - */ - override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = - LabeledPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = - LabeledPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantZero)) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to constantOne)) - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val LabeledPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, c) -> degs.values.sum().toInt() } ?: -1 - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public override val LabeledPolynomial.degrees: Map - get() = - buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.variables: Set - get() = - buildSet { - coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } - } - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public override val LabeledPolynomial.countOfVariables: Int get() = variables.size - -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("substitutePolynomial") -// public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -// -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunction(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnConstants(): (Map) -> LabeledPolynomial = { this.substitute(ring, it) } -// @Suppress("NOTHING_TO_INLINE") -// public inline fun LabeledPolynomial.asFunctionOnPolynomials(): (Map>) -> LabeledPolynomial = { this.substitute(ring, it) } -// -// @Suppress("NOTHING_TO_INLINE") -// public inline operator fun LabeledPolynomial.invoke(argument: Map): LabeledPolynomial = this.substitute(ring, argument) -// @Suppress("NOTHING_TO_INLINE") -// @JvmName("invokePolynomial") -// public inline operator fun LabeledPolynomial.invoke(argument: Map>): LabeledPolynomial = this.substitute(ring, argument) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt deleted file mode 100644 index 76c6874f5..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ /dev/null @@ -1,139 +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.expressions.Symbol -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke - - -public class LabeledRationalFunction( - public override val numerator: LabeledPolynomial, - public override val denominator: LabeledPolynomial -) : RationalFunction> { - override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class LabeledRationalFunctionSpace>( - public val ring: A, -) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - LabeledPolynomialSpace, - >, - MultivariatePolynomialSpaceOfFractions< - C, - Symbol, - LabeledPolynomial, - LabeledRationalFunction, - >() { - - override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: LabeledPolynomial, - denominator: LabeledPolynomial - ): LabeledRationalFunction = - LabeledRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: LabeledRationalFunction = LabeledRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: LabeledRationalFunction = LabeledRationalFunction(polynomialOne, polynomialOne) - - // TODO: Разобрать - -// operator fun invoke(arg: Map): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledPolynomial") -// operator fun invoke(arg: Map>): LabeledRationalFunction = -// LabeledRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeLabeledRationalFunction") -// operator fun invoke(arg: Map>): LabeledRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in variables) if (variable in arg) { -// val degreeDif = degrees[variable]!! -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return LabeledRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(emptyMap()) -// -// fun toString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(names) -// else -> "${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)}" -// } -// -// fun toString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(names) -// else -> "(${numerator.toStringWithBrackets(names)}/${denominator.toStringWithBrackets(names)})" -// } -// -// fun toStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(names) -// else -> "${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)}" -// } -// -// fun toReversedString(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(names: Map = emptyMap()): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(names) -// else -> "(${numerator.toReversedStringWithBrackets(names)}/${denominator.toReversedStringWithBrackets(names)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Symbol) -> String): String = -// when (true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 585da95ea..fce179fc8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -8,23 +8,19 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName import kotlin.math.max 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. */ public data class ListPolynomial( /** - * List that collects coefficients of the polynomial. Every monomial `a x^d` is represented as a coefficients - * `a` placed into the list with index `d`. For example coefficients of polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as * ``` * listOf( * -6, // -6 + @@ -42,26 +38,28 @@ public data class ListPolynomial( * 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 - * prohibited. + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. */ public val coefficients: List ) : Polynomial { - override fun toString(): String = "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 A type of underlying ring of constants. It's [Ring] of [C]. + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ public open class ListPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** - * Returns sum of the polynomial and the integer represented as 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]. */ @@ -79,7 +77,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -97,7 +95,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -112,7 +110,7 @@ public open class ListPolynomialSpace>( ) /** - * 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]. */ @@ -130,7 +128,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -150,7 +148,7 @@ public open class ListPolynomialSpace>( } ) /** - * 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]. */ @@ -170,7 +168,7 @@ public open class ListPolynomialSpace>( public override fun number(value: Int): ListPolynomial = 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): ListPolynomial = with(other.coefficients) { @@ -186,7 +184,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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): ListPolynomial = with(other.coefficients) { @@ -204,7 +202,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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): ListPolynomial = ListPolynomial( @@ -216,7 +214,7 @@ public open class ListPolynomialSpace>( ) /** - * 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.plus(other: C): ListPolynomial = with(coefficients) { @@ -232,7 +230,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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.minus(other: C): ListPolynomial = with(coefficients) { @@ -248,7 +246,7 @@ public open class ListPolynomialSpace>( ) } /** - * 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.times(other: C): ListPolynomial = ListPolynomial( @@ -262,7 +260,7 @@ public open class ListPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): ListPolynomial = ListPolynomial(value) + public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) /** * Returns negation of the polynomial. @@ -321,9 +319,9 @@ public open class ListPolynomialSpace>( */ override val zero: ListPolynomial = ListPolynomial(emptyList()) /** - * Instance of unit constant (unit of the underlying ring). + * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: ListPolynomial = ListPolynomial(listOf(constantOne)) + override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is @@ -331,23 +329,43 @@ public open class ListPolynomialSpace>( */ public override val ListPolynomial.degree: Int get() = coefficients.lastIndex + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided argument. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnConstants(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOnPolynomials(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } /** - * Evaluates the polynomial for the given value [argument]. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 7b6c23ac3..f3e352bcd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -8,13 +8,23 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring +/** + * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + */ public data class ListRationalFunction( public override val numerator: ListPolynomial, public override val denominator: ListPolynomial ) : RationalFunction> { - 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> ( public val ring: A, ) : @@ -30,76 +40,98 @@ public class ListRationalFunctionSpace> ( ListRationalFunction, >() { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ override val polynomialRing : ListPolynomialSpace = ListPolynomialSpace(ring) + /** + * Constructor of [ListRationalFunction] from numerator and denominator [ListPolynomial]. + */ override fun constructRationalFunction(numerator: ListPolynomial, denominator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, denominator) + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver /** - * Instance of zero rational function (zero of the rational functions ring). + * Evaluates value of [this] polynomial on provided argument. */ - public override val zero: ListRationalFunction = ListRationalFunction(polynomialZero, polynomialOne) + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) /** - * Instance of unit polynomial (unit of the rational functions ring). + * Substitutes provided polynomial [argument] into [this] polynomial. */ - public override val one: ListRationalFunction = ListRationalFunction(polynomialOne, polynomialOne) + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) - // TODO: Разобрать + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + /** + * Represent [this] rational function as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } -// operator fun invoke(arg: UnivariatePolynomial): RationalFunction = -// RationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// operator fun invoke(arg: RationalFunction): RationalFunction { -// val num = numerator invokeRFTakeNumerator arg -// val den = denominator invokeRFTakeNumerator arg -// val degreeDif = numeratorDegree - denominatorDegree -// return if (degreeDif > 0) -// RationalFunction( -// num, -// multiplyByPower(den, arg.denominator, degreeDif) -// ) -// else -// RationalFunction( -// multiplyByPower(num, arg.denominator, -degreeDif), -// den -// ) -// } -// -// override fun toString(): String = toString(UnivariatePolynomial.variableName) -// -// fun toString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedString(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = UnivariatePolynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun removeZeros() = -// RationalFunction( -// numerator.removeZeros(), -// denominator.removeZeros() -// ) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + /** + * Evaluates value of [this] rational function on provided argument. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt deleted file mode 100644 index e75373819..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.experimental.ExperimentalTypeInference -import kotlin.jvm.JvmName -import kotlin.math.max - - -/** - * Polynomial model without fixation on specific context they are applied to. - * - * @param C the type of constants. - */ -public data class NumberedPolynomial -internal constructor( - /** - * Map that collects coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is represented as - * pair "key-value" in the map, where value is coefficients `a` and - * key is list that associates index of every variable in the monomial with multiplicity of the variable occurring - * in the monomial. For example coefficients of polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * ) - * ``` - * and also as - * ``` - * mapOf( - * listOf(2, 0, 3) to 5, - * listOf(0, 1) to (-6), - * listOf(0, 1, 1) to 0, - * ) - * ``` - * It is recommended not to put zero monomials into the map, but is not prohibited. Lists of degrees always do not - * contain any zeros on end, but can contain zeros on start or anywhere in middle. - */ - public val coefficients: Map, C> -) : Polynomial { - override fun toString(): String = "NumberedPolynomial$coefficients" -} - -/** - * Space of polynomials. - * - * @param C the type of operated polynomials. - * @param A the intersection of [Ring] of [C] and [ScaleOperations] of [C]. - * @param ring the [A] instance. - */ -public open class NumberedPolynomialSpace>( - public final override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + 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 override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = - if (other == 0) this - else - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - /** - * Returns product of the polynomial and the integer represented as polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Returns sum of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - /** - * 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 override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - /** - * Returns product of the integer represented as polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@plus)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to this@minus)) - else NumberedPolynomial( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) - - /** - * Returns sum of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } - ) - } - /** - * Returns difference between the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomial(mapOf(emptyList() to other)) - else NumberedPolynomial( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } - ) - } - /** - * Returns product of the constant represented as polynomial and the polynomial. - */ - override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = - NumberedPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): NumberedPolynomial = - NumberedPolynomial(mapOf(emptyList() to value)) - - /** - * Returns negation of the polynomial. - */ - override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = - NumberedPolynomial( - coefficients.mapValues { -it.value } - ) - /** - * Returns sum of the polynomials. - */ - override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } - ) - /** - * Returns difference of the polynomials. - */ - override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } - } - ) - /** - * Returns product of the polynomials. - */ - override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomial( - buildMap(coefficients.size * other.coefficients.size) { - for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = - (0..max(degs1.lastIndex, degs2.lastIndex)) - .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } - val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c - } - } - ) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: NumberedPolynomial = NumberedPolynomial(emptyMap()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: NumberedPolynomial = - NumberedPolynomial( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List - get() = - MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - this[index] = max(this[index], deg) - } - } - } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } - } ?: 0u - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("substitutePolynomial") - public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunction(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnConstants(): (Map) -> NumberedPolynomial = { this.substitute(ring, it) } - @Suppress("NOTHING_TO_INLINE") - public inline fun NumberedPolynomial.asFunctionOnPolynomials(): (Map>) -> NumberedPolynomial = { this.substitute(ring, it) } - - @Suppress("NOTHING_TO_INLINE") - public inline operator fun NumberedPolynomial.invoke(argument: Map): NumberedPolynomial = this.substitute(ring, argument) - @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") - public inline operator fun NumberedPolynomial.invoke(argument: Map>): NumberedPolynomial = this.substitute(ring, argument) - - // FIXME: Move to other constructors with context receiver - public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt deleted file mode 100644 index 30c7f0188..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max - - -public class NumberedRationalFunction internal constructor( - public override val numerator: NumberedPolynomial, - public override val denominator: NumberedPolynomial -) : RationalFunction> { - override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" -} - -public class NumberedRationalFunctionSpace> ( - public val ring: A, -) : - RationalFunctionalSpaceOverPolynomialSpace< - C, - NumberedPolynomial, - NumberedRationalFunction, - NumberedPolynomialSpace, - >, - PolynomialSpaceOfFractions< - C, - NumberedPolynomial, - NumberedRationalFunction, - >() { - - override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) - override fun constructRationalFunction( - numerator: NumberedPolynomial, - denominator: NumberedPolynomial - ): NumberedRationalFunction = - NumberedRationalFunction(numerator, denominator) - - /** - * Instance of zero rational function (zero of the rational functions ring). - */ - public override val zero: NumberedRationalFunction = NumberedRationalFunction(polynomialZero, polynomialOne) - /** - * Instance of unit polynomial (unit of the rational functions ring). - */ - public override val one: NumberedRationalFunction = NumberedRationalFunction(polynomialOne, polynomialOne) - - /** - * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. - */ - public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } - /** - * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most - * exponents in which the variables are appeared in the polynomial. - * - * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. - * And last index of the list is [lastVariable]. - */ - public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } - /** - * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } - - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val NumberedRationalFunction.lastVariable: Int - get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } - /** - * Count of variables occurring in the rational function with positive power. If there is no such variable, - * the result is `0`. - */ - public val NumberedRationalFunction.countOfVariables: Int - get() = - MutableList(lastVariable + 1) { false }.apply { - numerator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - denominator.coefficients.entries.forEach { (degs, _) -> - degs.forEachIndexed { index, deg -> - if (deg != 0u) this[index] = true - } - } - }.count { it } - - // TODO: Разобрать - -// operator fun invoke(arg: Map): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokePolynomial") -// operator fun invoke(arg: Map>): NumberedRationalFunction = -// NumberedRationalFunction( -// numerator(arg), -// denominator(arg) -// ) -// -// @JvmName("invokeRationalFunction") -// operator fun invoke(arg: Map>): NumberedRationalFunction { -// var num = numerator invokeRFTakeNumerator arg -// var den = denominator invokeRFTakeNumerator arg -// for (variable in 0 until max(numerator.countOfVariables, denominator.countOfVariables)) if (variable in arg) { -// val degreeDif = numerator.degrees.getOrElse(variable) { 0 } - denominator.degrees.getOrElse(variable) { 0 } -// if (degreeDif > 0) -// den = multiplyByPower(den, arg[variable]!!.denominator, degreeDif) -// else -// num = multiplyByPower(num, arg[variable]!!.denominator, -degreeDif) -// } -// return NumberedRationalFunction(num, den) -// } -// -// override fun toString(): String = toString(Polynomial.variableName) -// -// fun toString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(withVariableName) -// else -> "${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)}" -// } -// -// fun toString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toString(namer) -// else -> "${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)}" -// } -// -// fun toStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(withVariableName) -// else -> "(${numerator.toStringWithBrackets(withVariableName)}/${denominator.toStringWithBrackets(withVariableName)})" -// } -// -// fun toStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toStringWithBrackets(namer) -// else -> "(${numerator.toStringWithBrackets(namer)}/${denominator.toStringWithBrackets(namer)})" -// } -// -// fun toReversedString(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(withVariableName) -// else -> "${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)}" -// } -// -// fun toReversedString(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedString(namer) -// else -> "${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)}" -// } -// -// fun toReversedStringWithBrackets(withVariableName: String = Polynomial.variableName): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(withVariableName) -// else -> "(${numerator.toReversedStringWithBrackets(withVariableName)}/${denominator.toReversedStringWithBrackets(withVariableName)})" -// } -// -// fun toReversedStringWithBrackets(namer: (Int) -> String): String = -// when(true) { -// numerator.isZero() -> "0" -// denominator.isOne() -> numerator.toReversedStringWithBrackets(namer) -// else -> "(${numerator.toReversedStringWithBrackets(namer)}/${denominator.toReversedStringWithBrackets(namer)})" -// } -} \ No newline at end of file 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 e201f1f6e..12490d133 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 @@ -25,38 +25,38 @@ public interface Polynomial @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface PolynomialSpace> : Ring

{ /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -72,38 +72,38 @@ public interface PolynomialSpace> : Ring

{ public fun Int.asConstant(): C = constantNumber(this) /** - * 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]. */ public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) /** - * 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]. */ public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) /** - * 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]. */ public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) /** - * 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]. */ public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) /** - * 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]. */ public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) /** - * 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]. */ @@ -165,28 +165,28 @@ public interface PolynomialSpace> : Ring

{ public val constantOne: 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 operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -254,41 +254,44 @@ public interface PolynomialSpace> : Ring

{ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -330,58 +333,145 @@ public interface PolynomialSpaceOverRing, A: Ring> : Poly public override val constantOne: C get() = ring.one } +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("numberVariable") + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index dfec126f3..01911f980 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -25,44 +25,44 @@ public interface RationalFunction> { * [C]. * * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param P the type of polynomials. Rational functions have them as numerators and denominators. * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 public interface RationalFunctionalSpace, R: RationalFunction> : Ring { /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public operator fun C.plus(other: Int): C /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public operator fun C.minus(other: Int): C /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun C.times(other: Int): C /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public operator fun Int.plus(other: C): C /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public operator fun Int.minus(other: C): C /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -78,38 +78,38 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asConstant(): C = constantNumber(this) /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun P.plus(other: Int): P /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun P.minus(other: Int): P /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun P.times(other: Int): P /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: P): P /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public operator fun Int.minus(other: P): P /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -125,25 +125,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun Int.asPolynomial(): P = polynomialNumber(this) /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public operator fun R.plus(other: Int): R = addMultipliedByDoubling(this, one, other) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public operator fun R.minus(other: Int): R = addMultipliedByDoubling(this, one, -other) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ public operator fun R.times(other: Int): R = multiplyByDoubling(this, other) /** - * Returns quotient of the rational function and the integer represented as rational function. + * Returns quotient of the rational function and the integer represented as a rational function. * * The operation is equivalent to creating a new rational function by preserving numerator of [this] and * multiplication denominator of [this] to [other]. @@ -151,25 +151,25 @@ public interface RationalFunctionalSpace, R: RationalFunctio public operator fun R.div(other: Int): R = this / multiplyByDoubling(one, other) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public operator fun Int.plus(other: R): R = addMultipliedByDoubling(other, one, this) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a 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 = addMultipliedByDoubling(-other, one, this) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a 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 = multiplyByDoubling(other, this) /** - * Returns quotient of the integer represented as rational function and the rational function. + * Returns quotient of the integer represented as a rational function and the rational function. * * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of * [other] and which denominator is [other]'s numerator. @@ -232,28 +232,28 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val constantOne: 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 operator fun C.plus(other: P): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun C.minus(other: P): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun C.times(other: P): P /** - * Returns sum of the constant represented as polynomial and the polynomial. + * Returns sum of the constant represented as a polynomial and the polynomial. */ public operator fun P.plus(other: C): P /** - * Returns difference between the constant represented as polynomial and the polynomial. + * Returns difference between the constant represented as a polynomial and the polynomial. */ public operator fun P.minus(other: C): P /** - * Returns product of the constant represented as polynomial and the polynomial. + * Returns product of the constant represented as a polynomial and the polynomial. */ public operator fun P.times(other: C): P @@ -305,36 +305,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public val polynomialOne: P /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public operator fun C.plus(other: R): R /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public operator fun C.minus(other: R): R /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public operator fun C.times(other: R): R /** - * Returns quotient of the constant represented as polynomial and the rational function. + * Returns quotient of the constant represented as a polynomial and the rational function. */ public operator fun C.div(other: R): R /** - * Returns sum of the rational function and the constant represented as rational function. + * Returns sum of the rational function and the constant represented as a rational function. */ public operator fun R.plus(other: C): R /** - * Returns difference between the rational function and the constant represented as rational function. + * Returns difference between the rational function and the constant represented as a rational function. */ public operator fun R.minus(other: C): R /** - * Returns product of the rational function and the constant represented as rational function. + * Returns product of the rational function and the constant represented as a rational function. */ public operator fun R.times(other: C): R /** - * Returns quotient of the rational function and the constant represented as rational function. + * Returns quotient of the rational function and the constant represented as a rational function. */ public operator fun R.div(other: C): R @@ -348,36 +348,36 @@ public interface RationalFunctionalSpace, R: RationalFunctio public fun C.asRationalFunction(): R = number(this) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public operator fun P.plus(other: R): R /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public operator fun P.minus(other: R): R /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public operator fun P.times(other: R): R /** - * Returns quotient of the polynomial represented as polynomial and the rational function. + * Returns quotient of the polynomial represented as a polynomial and the rational function. */ public operator fun P.div(other: R): R /** - * Returns sum of the rational function and the polynomial represented as rational function. + * Returns sum of the rational function and the polynomial represented as a rational function. */ public operator fun R.plus(other: P): R /** - * Returns difference between the rational function and the polynomial represented as rational function. + * Returns difference between the rational function and the polynomial represented as a rational function. */ public operator fun R.minus(other: P): R /** - * Returns product of the rational function and the polynomial represented as rational function. + * Returns product of the rational function and the polynomial represented as a rational function. */ public operator fun R.times(other: P): R /** - * Returns quotient of the rational function and the polynomial represented as rational function. + * Returns quotient of the rational function and the polynomial represented as a rational function. */ public operator fun R.div(other: P): R @@ -459,43 +459,51 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing, R: RationalFunction, A: Ring> : RationalFunctionalSpace { +public interface RationalFunctionalSpaceOverRing< + C, + P: Polynomial, + R: RationalFunction, + A: Ring + > : RationalFunctionalSpace { + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ public val ring: A /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -560,41 +568,44 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< AP: PolynomialSpace, > : RationalFunctionalSpace { + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ public val polynomialRing: AP /** - * Returns sum of the constant and the integer represented as constant (member of underlying ring). + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as constant (member of underlying ring). + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as constant (member of underlying ring). + * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as constant (member of underlying ring) and the constant. + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as constant (member of underlying ring) and the constant. + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as constant (member of underlying ring) and the constant. + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -610,38 +621,38 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< override fun Int.asConstant(): C = polynomialRing { asConstant() } /** - * Returns sum of the constant and the integer represented as polynomial. + * Returns sum of the constant and the integer represented as a polynomial. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** - * Returns difference between the constant and the integer represented as polynomial. + * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** - * Returns product of the constant and the integer represented as polynomial. + * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** - * Returns sum of the integer represented as polynomial and the constant. + * Returns sum of the integer represented as a polynomial and the constant. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** - * Returns difference between the integer represented as polynomial and the constant. + * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** - * Returns product of the integer represented as polynomial and the constant. + * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -697,28 +708,28 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< public override val constantOne: C get() = polynomialRing.constantOne /** - * 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: P): P = polynomialRing { this@plus + other } /** - * 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: P): P = polynomialRing { this@minus - other } /** - * 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: P): P = polynomialRing { this@times * other } /** - * 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 P.plus(other: C): P = polynomialRing { this@plus + other } /** - * 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 P.minus(other: C): P = polynomialRing { this@minus - other } /** - * 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 P.times(other: C): P = polynomialRing { this@times * other } @@ -774,7 +785,8 @@ public interface RationalFunctionalSpaceOverPolynomialSpace< /** * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] and constants of type - * [C]. It also assumes that there is provided constructor + * [C]. It also assumes that there is provided constructor [constructRationalFunction] of rational functions from + * polynomial numerator and denominator. * * @param C the type of constants. Polynomials have them as coefficients in their terms. * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. @@ -786,10 +798,14 @@ public abstract class PolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : RationalFunctionalSpace { + + /** + * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). + */ protected abstract fun constructRationalFunction(numerator: P, denominator: P = polynomialOne) : R /** - * Returns sum of the rational function and the integer represented as rational function. + * Returns sum of the rational function and the integer represented as a rational function. * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ @@ -799,7 +815,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the rational function and the integer represented as rational function. + * Returns difference between the rational function and the integer represented as a rational function. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ @@ -809,7 +825,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the rational function and the integer represented as rational function. + * Returns product of the rational function and the integer represented as a rational function. * * The operation is equivalent to sum of [other] copies of [this]. */ @@ -818,7 +834,12 @@ public abstract class PolynomialSpaceOfFractions< numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the integer represented as a rational function. + * + * The operation is equivalent to creating a new rational function by preserving numerator of [this] and + * multiplication denominator of [this] to [other]. + */ public override operator fun R.div(other: Int): R = constructRationalFunction( numerator, @@ -826,7 +847,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the integer represented as rational function and the rational function. + * Returns sum of the integer represented as a rational function and the rational function. * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ @@ -836,7 +857,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the integer represented as rational function and the rational function. + * Returns difference between the integer represented as a rational function and the rational function. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ @@ -846,7 +867,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the integer represented as rational function and the rational function. + * Returns product of the integer represented as a rational function and the rational function. * * The operation is equivalent to sum of [this] copies of [other]. */ @@ -855,7 +876,12 @@ public abstract class PolynomialSpaceOfFractions< this * other.numerator, other.denominator ) - + /** + * Returns quotient of the integer represented as a rational function and the rational function. + * + * The operation is equivalent to creating a new rational function which numerator is [this] times denominator of + * [other] and which denominator is [other]'s numerator. + */ public override operator fun Int.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -873,7 +899,7 @@ public abstract class PolynomialSpaceOfFractions< public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun C.plus(other: R): R = constructRationalFunction( @@ -881,7 +907,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the constant represented as polynomial and the rational function. + * Returns difference between the constant represented as a polynomial and the rational function. */ public override operator fun C.minus(other: R): R = constructRationalFunction( @@ -889,14 +915,16 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the constant represented as polynomial and the rational function. + * Returns product of the constant represented as a polynomial and the rational function. */ public override operator fun C.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - + /** + * Returns quotient of the constant represented as a polynomial and the rational function. + */ public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -904,7 +932,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the constant represented as rational function and the rational function. + * Returns sum of the constant represented as a rational function and the rational function. */ public override operator fun R.plus(other: C): R = constructRationalFunction( @@ -912,7 +940,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the constant represented as rational function and the rational function. + * Returns difference between the constant represented as a rational function and the rational function. */ public override operator fun R.minus(other: C): R = constructRationalFunction( @@ -920,14 +948,16 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the constant represented as rational function and the rational function. + * Returns product of the constant represented as a rational function and the rational function. */ public override operator fun R.times(other: C): R = constructRationalFunction( numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the constant represented as a rational function. + */ public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -940,7 +970,7 @@ public abstract class PolynomialSpaceOfFractions< public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun P.plus(other: R): R = constructRationalFunction( @@ -948,7 +978,7 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns difference between the polynomial represented as polynomial and the rational function. + * Returns difference between the polynomial represented as a polynomial and the rational function. */ public override operator fun P.minus(other: R): R = constructRationalFunction( @@ -956,14 +986,16 @@ public abstract class PolynomialSpaceOfFractions< other.denominator ) /** - * Returns product of the polynomial represented as polynomial and the rational function. + * Returns product of the polynomial represented as a polynomial and the rational function. */ public override operator fun P.times(other: R): R = constructRationalFunction( this * other.numerator, other.denominator ) - + /** + * Returns quotient of the polynomial represented as a polynomial and the rational function. + */ public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -971,7 +1003,7 @@ public abstract class PolynomialSpaceOfFractions< ) /** - * Returns sum of the polynomial represented as rational function and the rational function. + * Returns sum of the polynomial represented as a rational function and the rational function. */ public override operator fun R.plus(other: P): R = constructRationalFunction( @@ -979,7 +1011,7 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns difference between the polynomial represented as rational function and the rational function. + * Returns difference between the polynomial represented as a rational function and the rational function. */ public override operator fun R.minus(other: P): R = constructRationalFunction( @@ -987,14 +1019,16 @@ public abstract class PolynomialSpaceOfFractions< denominator ) /** - * Returns product of the polynomial represented as rational function and the rational function. + * Returns product of the polynomial represented as a rational function and the rational function. */ public override operator fun R.times(other: P): R = constructRationalFunction( numerator * other, denominator ) - + /** + * Returns quotient of the rational function and the polynomial represented as a rational function. + */ public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1034,7 +1068,9 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.numerator, denominator * other.denominator ) - + /** + * Returns quotient of the rational functions. + */ public override operator fun R.div(other: R): R = constructRationalFunction( numerator * other.denominator, @@ -1044,14 +1080,23 @@ public abstract class PolynomialSpaceOfFractions< /** * 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). */ - public override val one: R get() = constructRationalFunction(polynomialOne) + public override val one: R by lazy { constructRationalFunction(polynomialOne) } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpace< C, @@ -1059,70 +1104,179 @@ public interface MultivariateRationalFunctionalSpace< P: Polynomial, R: RationalFunction >: RationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public operator fun V.times(other: Int): P + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public operator fun Int.times(other: V): P - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public operator fun V.times(other: C): P + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public operator fun V.times(other: V): P + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("polynomialNumberVariable") + public fun polynomialNumber(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = polynomialNumber(this) + + /** + * Represents the [variable] as a rational function. + */ + @JvmName("numberVariable") + public fun number(variable: V): R = number(polynomialNumber(variable)) + /** + * Represents the variable as a rational function. + */ + @JvmName("asRationalFunctionVariable") + public fun V.asRationalFunction(): R = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public operator fun V.times(other: P): P + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public operator fun P.times(other: V): P + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public operator fun V.plus(other: R): R + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public operator fun V.minus(other: R): R + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public operator fun V.times(other: R): R + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public operator fun R.plus(other: V): R + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public operator fun R.minus(other: V): R + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public operator fun R.times(other: V): R @@ -1161,22 +1315,17 @@ public interface MultivariateRationalFunctionalSpace< public val R.countOfVariables: Int get() = variables.size } -public interface MultivariateRationalFunctionalSpaceOverRing< - C, - V, - P: Polynomial, - R: RationalFunction, - A: Ring - > : RationalFunctionalSpaceOverRing, MultivariateRationalFunctionalSpace - -public interface MultivariateRationalFunctionalSpaceOverPolynomialSpace< - C, - V, - P: Polynomial, - R: RationalFunction, - AP: PolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace - +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided [polynomialRing] (of type [AP]), + * that provides constant-, variable- and polynomial-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< C, @@ -1184,57 +1333,137 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : MultivariateRationalFunctionalSpaceOverPolynomialSpace { + > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("plusVariableInt") public override operator fun V.plus(other: Int): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("minusVariableInt") public override operator fun V.minus(other: Int): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ @JvmName("timesVariableInt") public override operator fun V.times(other: Int): P = polynomialRing { this@times * other } + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("plusIntVariable") public override operator fun Int.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("minusIntVariable") public override operator fun Int.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ @JvmName("timesIntVariable") public override operator fun Int.times(other: V): P = polynomialRing { this@times * other } - @JvmName("plusConstantVariable") - public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } - @JvmName("minusConstantVariable") - public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } - @JvmName("timesConstantVariable") - public override operator fun C.times(other: V): P = polynomialRing { this@times * other } - + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("plusVariableConstant") public override operator fun V.plus(other: C): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("minusVariableConstant") public override operator fun V.minus(other: C): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ @JvmName("timesVariableConstant") public override operator fun V.times(other: C): P = polynomialRing { this@times * other } + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public override operator fun C.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public override operator fun C.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public override operator fun C.times(other: V): P = polynomialRing { this@times * other } + + /** + * Represents the variable as a monic monomial. + */ @JvmName("unaryPlusVariable") public override operator fun V.unaryPlus(): P = polynomialRing { +this@unaryPlus } + /** + * Returns negation of representation of the variable as a monic monomial. + */ @JvmName("unaryMinusVariable") public override operator fun V.unaryMinus(): P = polynomialRing { -this@unaryMinus } + /** + * Returns sum of the variables represented as monic monomials. + */ @JvmName("plusVariableVariable") public override operator fun V.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variables represented as monic monomials. + */ @JvmName("minusVariableVariable") public override operator fun V.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the variables represented as monic monomials. + */ @JvmName("timesVariableVariable") public override operator fun V.times(other: V): P = polynomialRing { this@times * other } + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("polynomialNumberVariable") + public override fun polynomialNumber(variable: V): P = polynomialRing { number(variable) } + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public override fun V.asPolynomial(): P = polynomialRing { this@asPolynomial.asPolynomial() } + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ @JvmName("plusVariablePolynomial") public override operator fun V.plus(other: P): P = polynomialRing { this@plus + other } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ @JvmName("minusVariablePolynomial") public override operator fun V.minus(other: P): P = polynomialRing { this@minus - other } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ @JvmName("timesVariablePolynomial") public override operator fun V.times(other: P): P = polynomialRing { this@times * other } + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ @JvmName("plusPolynomialVariable") public override operator fun P.plus(other: V): P = polynomialRing { this@plus + other } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ @JvmName("minusPolynomialVariable") public override operator fun P.minus(other: V): P = polynomialRing { this@minus - other } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ @JvmName("timesPolynomialVariable") public override operator fun P.times(other: V): P = polynomialRing { this@times * other } @@ -1264,6 +1493,16 @@ public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSp public override val P.countOfVariables: Int get() = polynomialRing { countOfVariables } } +/** + * Abstraction of field of rational functions of type [R] with respect to polynomials of type [P] of variables of type + * [V] and over ring of constants of type [C]. It also assumes that there is provided constructor + * [constructRationalFunction] of rational functions from polynomial numerator and denominator. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. Rational functions have them as numerators and denominators in them. + * @param R the type of rational functions. + */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class MultivariatePolynomialSpaceOfFractions< C, @@ -1271,18 +1510,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< P: Polynomial, R: RationalFunction, > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + /** + * Returns sum of the variable represented as a rational function and the rational function. + */ @JvmName("plusVariableRational") public override operator fun V.plus(other: R): R = constructRationalFunction( this * other.denominator + other.numerator, other.denominator ) + /** + * Returns difference between the variable represented as a rational function and the rational function. + */ @JvmName("minusVariableRational") public override operator fun V.minus(other: R): R = constructRationalFunction( this * other.denominator - other.numerator, other.denominator ) + /** + * Returns product of the variable represented as a rational function and the rational function. + */ @JvmName("timesVariableRational") public override operator fun V.times(other: R): R = constructRationalFunction( @@ -1290,18 +1538,27 @@ public abstract class MultivariatePolynomialSpaceOfFractions< other.denominator ) + /** + * Returns sum of the rational function and the variable represented as a rational function. + */ @JvmName("plusRationalVariable") public override operator fun R.plus(other: V): R = constructRationalFunction( numerator + denominator * other, denominator ) + /** + * Returns difference between the rational function and the variable represented as a rational function. + */ @JvmName("minusRationalVariable") public override operator fun R.minus(other: V): R = constructRationalFunction( numerator - denominator * other, denominator ) + /** + * Returns product of the rational function and the variable represented as a rational function. + */ @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt deleted file mode 100644 index e81a9388e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ /dev/null @@ -1,203 +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.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - - -/** - * Returns the same degrees' description of the monomial, but without zero degrees. - */ -internal fun Map.cleanUp() = filterValues { it > 0U } - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(coefs) - - val fixedCoefs = LinkedHashMap, C>(coefs.size) - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial = ring.LabeledPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.LabeledPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : LabeledPolynomial { - if (!toCheckInput) return LabeledPolynomial(pairs.toMap()) - - val fixedCoefs = LinkedHashMap, C>(pairs.size) - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return LabeledPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs, toCheckInput = true) - -//context(A) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) -//context(LabeledPolynomialSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) - -public fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(emptyMap() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { - private val signature: MutableMap = LinkedHashMap() - public fun build(): Map = signature - public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class LabeledPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) - public operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit) { - val signature = LabeledPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (LabeledPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): LabeledPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@LabeledPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(capacity: Int, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = - LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = - LabeledRationalFunction( - LabeledPolynomial(numeratorCoefficients, toCheckInput = true), - LabeledPolynomial(mapOf(emptyMap() to one), toCheckInput = false) - ) - -//context(A) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) - -//context(A) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) -//context(LabeledRationalFunctionSpace) -//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = LabeledRationalFunction(asLabeledPolynomial()) \ 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 deleted file mode 100644 index af918b9ae..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledPolynomialUtil.kt +++ /dev/null @@ -1,495 +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.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -// TODO: Docs - -/** - * Creates a [LabeledPolynomialSpace] over a received ring. - */ -public fun > A.labeledPolynomial(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) - -/** - * Creates a [LabeledPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.labeledPolynomial(block: LabeledPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.represent(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(names: Map = emptyMap()): String = -// with(represent(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representWithBrackets(namer: (Symbol) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(names: Map = emptyMap()): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// val variableName = names.getOrDefault(variable, variable.toString()) -// when (deg) { -// 1U -> variableName -// else -> "$variableName^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversed(namer: (Symbol) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -LabeledPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .toSortedMap() -// .filter { it.value > 0U } -// .map { (variable, deg) -> -// when (deg) { -// 1U -> namer(variable) -// else -> "${namer(variable)}^$deg" -// } -// } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] with names of variables substituted with names from [names] and with -// * brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(names: Map = emptyMap()): String = -// with(representReversed(names)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(LabeledPolynomialSpace) -//fun > LabeledPolynomial.representReversedWithBrackets(namer: (Symbol) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -//public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// LabeledPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.filterKeys { it !in args } -// val newC = degs.entries.asSequence().filter { it.key in args }.fold(c) { acc, (variable, deg) -> -// multiplyWithPower(acc, args[variable]!!, deg) -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//fun LabeledPolynomial.substitute(ring: Ring, arg: Map>) : LabeledPolynomial = -// ring.labeledPolynomial { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.entries -// .asSequence() -// .filter { it.key in arg } -// .fold(LabeledPolynomial(mapOf(degs.filterKeys { it !in arg } to c))) { acc, (index, deg) -> -// multiplyWithPower(acc, arg[index]!!, deg) -// } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//fun > LabeledPolynomial.asFunctionOver(ring: A): (Map) -> LabeledPolynomial = -// { substitute(ring, it) } -// -//fun > LabeledPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> LabeledPolynomial = -// { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (variable !in degs) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - multiplyByDoubling(c, degs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (!degs.keys.containsAll(cleanedVariables)) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari !in cleanedVariables -> put(vari, deg) - deg > 1u -> put(vari, deg - 1u) - } - } - }, - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.getOrElse(variable) { 0u } < order) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - when { - vari != variable -> put(vari, deg) - deg > order -> put(vari, deg - order) - } - } - }, - degs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach - put( - buildMap { - degs.forEach { (vari, deg) -> - if (vari !in filteredVariablesAndOrders) put(vari, deg) - else { - val order = filteredVariablesAndOrders[vari]!! - if (deg > order) put(vari, deg - order) - } - } - }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Symbol, -): LabeledPolynomial = algebra { - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - c / multiplyByDoubling(one, newDegs[variable]!!) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): LabeledPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for (variable in cleanedVariables) put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - cleanedVariables.fold(c) { acc, variable -> acc / multiplyByDoubling(one, newDegs[variable]!!) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Symbol, - order: UInt -): LabeledPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - newDegs[variable]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): LabeledPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - LabeledPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } - put( - newDegs, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - newDegs[index]!!.let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt deleted file mode 100644 index 583160cf4..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [LabeledRationalFunctionSpace] over a received ring. - */ -public fun > A.labeledRationalFunction(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) - -/** - * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.labeledRationalFunction(block: LabeledRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return LabeledRationalFunctionSpace(this).block() -} - -//fun > LabeledRationalFunction.reduced(): LabeledRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return LabeledRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index 9498c77ca..35c736914 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -3,58 +3,95 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) /** - * Returns a [ListPolynomial] instance with given [coefficients]. The collection of coefficients will be reversed if - * [reverse] parameter is true. + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. */ @Suppress("FunctionName") public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) +/** + * Represents [this] constant as a [ListPolynomial]. + */ public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ @Suppress("FunctionName") public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) ) -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ @Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ @Suppress("FunctionName") public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = ListRationalFunction( ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), ListPolynomial(listOf(one)) ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(A) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ //context(ListRationalFunctionSpace) //public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt deleted file mode 100644 index 50313cab9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listPolynomialUtil.kt +++ /dev/null @@ -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) -//fun > Polynomial.removeZeros() : Polynomial = -// if (degree > -1) Polynomial(coefficients.subList(0, degree + 1)) else zero - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public fun > A.listPolynomial(): ListPolynomialSpace = - ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ -public inline fun , R> A.listPolynomial(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public fun A.scalableListPolynomial(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ -public inline fun A.scalableListPolynomial(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - 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 multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = 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.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 ListPolynomial.substitute(ring: Ring, 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 ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = 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 = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = 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(resultCoefs) -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunction(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - algebra: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.nthDerivative( - algebra: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = 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 ListPolynomial.antiderivative( - algebra: A, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 ListPolynomial.nthAntiderivative( - algebra: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = 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 > ListPolynomial.integrate( - algebra: Field, - range: ClosedRange, -): C = algebra { - val integral = antiderivative(algebra) - integral.substitute(algebra, range.endInclusive) - integral.substitute(algebra, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt new file mode 100644 index 000000000..127dd8c7a --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -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 > A.listPolynomialSpace(): ListPolynomialSpace = + ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = + ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = + ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} + +/** + * Returns algebraic derivative of received rational function. + */ +@UnstableKMathAPI +public fun ListRationalFunction.derivative( + ring: A, +): ListRationalFunction where A : Ring, A : NumericAlgebra = 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 ListRationalFunction.nthDerivative( + ring: A, + order: Int, +): ListRationalFunction where A : Ring, A : NumericAlgebra = + if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt similarity index 72% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt rename to kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt index 367212588..6eb3a1dc7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listRationalFunctionUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt @@ -5,41 +5,91 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.math.max +import kotlin.math.min -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public fun > A.listRationalFunction(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.listRationalFunction(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() +// TODO: Optimized copies of substitution and invocation +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun copyTo( + origin: List, + originDegree: Int, + target: MutableList, +) { + for (deg in 0 .. originDegree) target[deg] = origin[deg] } -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingToUpdater( + ring: Ring, + multiplicand: MutableList, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + updater: MutableList, + 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 + } +} -/** - * 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 ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +@UnstablePolynomialBoxingOptimization +@Suppress("NOTHING_TO_INLINE") +internal inline fun multiplyAddingTo( + ring: Ring, + multiplicand: List, + multiplicandDegree: Int, + multiplier: List, + multiplierDegree: Int, + target: MutableList +) = 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 ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = 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 = MutableList(thisDegree * argDegree + 1) { constantZero } + resultCoefs[0] = coefficients[thisDegree] + val resultCoefsUpdate: MutableList = 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(resultCoefs) } /** @@ -52,6 +102,7 @@ public fun ListRationalFunction.substitute(ring: Field, arg: C): C = r * * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. */ // TODO: Дописать +@UnstablePolynomialBoxingOptimization internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { if (coefficients.isEmpty()) return ListPolynomial(emptyList()) @@ -196,26 +247,4 @@ internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: end = thisDegree + 1 ) ) -} - -//operator fun > RationalFunction.invoke(arg: T): T = numerator(arg) / denominator(arg) -// -//fun > RationalFunction.reduced(): RationalFunction = -// 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 > RationalFunction.derivative() = -// RationalFunction( -// numerator.derivative() * denominator - denominator.derivative() * numerator, -// denominator * denominator -// ) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt new file mode 100644 index 000000000..8b6fac39e --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -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 \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt deleted file mode 100644 index dca8a0cff..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ /dev/null @@ -1,195 +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.Ring - - -/** - * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. - */ -internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(coefs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(coefs: Map, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(coefs) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs, toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(pairs: Collection, C>>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName", "NOTHING_TO_INLINE") -internal inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial = ring.NumberedPolynomial(pairs = pairs, toCheckInput = toCheckInput) -@Suppress("FunctionName") -internal fun > A.NumberedPolynomial(vararg pairs: Pair, C>, toCheckInput: Boolean = true) : NumberedPolynomial { - if (!toCheckInput) return NumberedPolynomial(pairs.toMap()) - - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) fixedCoefs[key]!! + value else value - } - - return NumberedPolynomial(fixedCoefs) -} - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, toCheckInput = true) - -@Suppress("FunctionName") -public fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs, toCheckInput = true) - -public fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomial(mapOf(emptyList() to this)) - -@DslMarker -@UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { - private val signature: MutableList = ArrayList() - public fun build(): List = signature - public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) - signature.add(deg) - } else { - signature[this] = deg - } - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg - @Suppress("NOTHING_TO_INLINE") - public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg -} - -@UnstableKMathAPI -public class NumberedPolynomialBuilder(private val zero: C, private val add: (C, C) -> C, capacity: Int = 0) { - private val coefficients: MutableMap, C> = LinkedHashMap(capacity) - public fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit) { - val signature = NumberedPolynomialTermSignatureBuilder().apply(block).build() - coefficients[signature] = add(coefficients.getOrElse(signature) { zero }, this@invoke) - } - @Suppress("NOTHING_TO_INLINE") - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) - @Suppress("NOTHING_TO_INLINE") - public inline infix fun (NumberedPolynomialTermSignatureBuilder.() -> Unit).with(coef: C): Unit = coef.invoke(this) - @Suppress("NOTHING_TO_INLINE") - public infix fun sig(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): NumberedPolynomialTermSignatureBuilder.() -> Unit = block -} - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(zero, ::add, capacity).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}).apply(block).build() -@UnstableKMathAPI -@NumberedPolynomialConstructorDSL -@Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(capacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(constantZero, { left: C, right: C -> left + right}, capacity).apply(block).build() - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(denominatorCoefficients, toCheckInput = true) - ) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, polynomialOne) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = - NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false)) -@Suppress("FunctionName") -public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - polynomialOne - ) -@Suppress("FunctionName") -public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = - NumberedRationalFunction( - NumberedPolynomial(numeratorCoefficients, toCheckInput = true), - NumberedPolynomial(mapOf(emptyList() to one), toCheckInput = false) - ) - -//context(A) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) -//context(NumberedRationalFunctionSpace) -//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = NumberedRationalFunction(asLabeledPolynomial()) \ No newline at end of file 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 deleted file mode 100644 index ad817c7ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedPolynomialUtil.kt +++ /dev/null @@ -1,528 +0,0 @@ -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.* -import kotlin.jvm.JvmName -import kotlin.math.max - - -// TODO: Docs - -/** - * Creates a [NumberedPolynomialSpace] over a received ring. - */ -public fun > A.numberedPolynomial(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) - -/** - * Creates a [NumberedPolynomialSpace]'s scope over a received ring. - */ -@OptIn(ExperimentalContracts::class) -public inline fun , R> A.numberedPolynomial(block: NumberedPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedPolynomialSpace(this).block() -} - -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.represent(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(represent(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representWithBrackets(namer: (Int) -> String): String = -// with(represent(namer)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"`. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> "${withVariableName}_${index+1}" -// else -> "${withVariableName}_${index+1}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer]. -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversed(namer: (Int) -> String): String = -// coefficients.entries -// .sortedWith { o1, o2 -> -NumberedPolynomial.monomialComparator.compare(o1.key, o2.key) } -// .asSequence() -// .map { (degs, t) -> -// if (degs.isEmpty()) "$t" -// else { -// when { -// t.isOne() -> "" -// t.isMinusOne() -> "-" -// else -> "$t " -// } + -// degs -// .mapIndexed { index, deg -> -// when (deg) { -// 0U -> "" -// 1U -> namer(index) -// else -> "${namer(index)}^$deg" -// } -// } -// .filter { it.isNotEmpty() } -// .joinToString(separator = " ") { it } -// } -// } -// .joinToString(separator = " + ") { it } -// .ifEmpty { "0" } -// -///** -// * Represents the polynomial as a [String] where name of variable with index `i` is [withVariableName] + `"_${i+1}"` -// * and with brackets around the string if needed (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(withVariableName: String = NumberedPolynomial.defaultVariableName): String = -// with(representReversed(withVariableName)) { if (coefficients.count() == 1) this else "($this)" } -// -///** -// * Represents the polynomial as a [String] naming variables by [namer] and with brackets around the string if needed -// * (i.e. when there are at least two addends in the representation). -// * Consider that monomials are sorted in **reversed** lexicographic order. -// */ -//context(NumberedPolynomialSpace) -//public fun > NumberedPolynomial.representReversedWithBrackets(namer: (Int) -> String): String = -// with(representReversed(namer)) { if (coefficients.count() == 1) this else "($this)" } - -//public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { -// if (coefficients.isEmpty()) return this@substitute -// NumberedPolynomial( -// buildMap { -// coefficients.forEach { (degs, c) -> -// val newDegs = degs.mapIndexed { index, deg -> if (index in args) 0U else deg }.cleanUp() -// val newC = degs.foldIndexed(c) { index, acc, deg -> -// if (index in args) multiplyWithPower(acc, args[index]!!, deg) -// else acc -// } -// this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC -// } -// } -// ) -//} -// -//// TODO: Replace with optimisation: the [result] may be unboxed, and all operations may be performed as soon as -//// possible on it -//@JvmName("substitutePolynomial") -//public fun NumberedPolynomial.substitute(ring: Ring, arg: Map>) : NumberedPolynomial = -// ring.numberedPolynomialSpace { -// if (coefficients.isEmpty()) return zero -// coefficients -// .asSequence() -// .map { (degs, c) -> -// degs.foldIndexed( -// NumberedPolynomial( -// degs.mapIndexed { index, deg -> if (index in arg) 0U else deg } to c -// ) -// ) { index, acc, deg -> if (index in arg) multiplyWithPower(acc, arg[index]!!, deg) else acc } -// } -// .reduce { acc, polynomial -> acc + polynomial } // TODO: Rewrite. Might be slow. -// } -// -//// TODO: Substitute rational function -// -//public fun > NumberedPolynomial.asFunctionOver(ring: A): (Map) -> NumberedPolynomial = -// { substitute(ring, it) } -// -//public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = -// { substitute(ring, it) } - -//operator fun > Polynomial.div(other: T): Polynomial = -// if (other.isZero()) throw ArithmeticException("/ by zero") -// else -// Polynomial( -// coefficients -// .mapValues { it.value / other }, -// toCheckInput = false -// ) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { - val acc = LinkedHashMap, Double>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * substitution.pow(deg.toInt()) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -/** - * 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 NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { - val acc = LinkedHashMap, C>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = newC - else acc[newDegs] = acc[newDegs]!! + newC - } - return NumberedPolynomial(acc) -} - -// TODO: (Waiting for hero) Replace with optimisation: the [result] may be unboxed, and all operations may be performed -// as soon as possible on it -@JvmName("substitutePolynomial") -public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = TODO() /*ring.numberedPolynomial { - val acc = LinkedHashMap, NumberedPolynomial>(coefficients.size) - for ((degs, c) in coefficients) { - val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() - val newC = args.entries.fold(c.asNumberedPolynomial()) { product, (variable, substitution) -> - val deg = degs.getOrElse(variable) { 0u } - if (deg == 0u) product else product * power(substitution, deg) - } - if (newDegs !in acc) acc[newDegs] = c.asNumberedPolynomial() - else acc[newDegs] = acc[newDegs]!! + c - } -}*/ - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asFunction(ring: A): (Map) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > NumberedPolynomial.asPolynomialFunctionOver(ring: A): (Map>) -> NumberedPolynomial = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - multiplyByDoubling(c, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.derivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@derivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index !in cleanedVariables -> deg - deg > 0u -> deg - 1u - else -> return@forEach - } - }.cleanUp(), - cleanedVariables.fold(c) { acc, variable -> multiplyByDoubling(acc, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthDerivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > variable) return@forEach - put( - degs.mapIndexed { index, deg -> - when { - index != variable -> deg - deg >= order -> deg - order - else -> return@forEach - } - }.cleanUp(), - degs[variable].let { deg -> - (deg downTo deg - order + 1u) - .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthDerivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach - put( - degs.mapIndexed { index, deg -> - if (index !in filteredVariablesAndOrders) return@mapIndexed deg - val order = filteredVariablesAndOrders[index]!! - if (deg >= order) deg - order else return@forEach - }.cleanUp(), - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } - } - } - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variable: Int, -): NumberedPolynomial = algebra { - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) - ) - } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.antiderivativeWithRespectTo( - algebra: A, - variables: Collection, -): NumberedPolynomial = algebra { - val cleanedVariables = variables.toSet() - if (cleanedVariables.isEmpty()) return this@antiderivativeWithRespectTo - val maxRespectedVariable = cleanedVariables.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .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 / multiplyByDoubling(one, degs[variable]) } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variable: Int, - order: UInt -): NumberedPolynomial = algebra { - if (order == 0u) return this@nthAntiderivativeWithRespectTo - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - 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 / multiplyByDoubling(one, ord) } - } - ) - } - } - ) -} - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( - algebra: A, - variablesAndOrders: Map, -): NumberedPolynomial = algebra { - val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } - if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo - val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! - NumberedPolynomial( - buildMap(coefficients.size) { - coefficients - .forEach { (degs, c) -> - put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } - } - } - ) - } - } - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt deleted file mode 100644 index 5cd0679ab..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedRationalFunctionUtil.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * Creates a [NumberedRationalFunctionSpace] over a received ring. - */ -public fun > A.numberedRationalFunction(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) - -/** - * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. - */ -public inline fun , R> A.numberedRationalFunction(block: NumberedRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return NumberedRationalFunctionSpace(this).block() -} - -//fun > NumberedRationalFunction.reduced(): NumberedRationalFunction { -// val greatestCommonDivider = polynomialGCD(numerator, denominator) -// return NumberedRationalFunction( -// numerator / greatestCommonDivider, -// denominator / greatestCommonDivider -// ) -//} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index 5401be707..c9950fac5 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -12,7 +12,7 @@ import kotlin.test.* class ListPolynomialTest { @Test fun test_Polynomial_Int_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, @@ -52,7 +52,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, @@ -92,7 +92,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27, @@ -107,7 +107,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -147,7 +147,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -187,7 +187,7 @@ class ListPolynomialTest { } @Test fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -202,7 +202,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), @@ -242,7 +242,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), @@ -282,7 +282,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), @@ -297,7 +297,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -337,7 +337,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), @@ -377,7 +377,7 @@ class ListPolynomialTest { } @Test fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), 27 * ListPolynomial(22, 26, 13, 15, 26), @@ -392,7 +392,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_unaryMinus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { assertEquals( ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), @@ -407,7 +407,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 assertEquals( ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), @@ -440,7 +440,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomial { + RationalField.listPolynomialSpace { // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 assertEquals( ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), @@ -473,7 +473,7 @@ class ListPolynomialTest { } @Test fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomial { + IntModuloRing(35).listPolynomialSpace { // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 assertEquals( ListPolynomial(1, 0, 1, 0, 1), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index c5eb8fb81..69c1611f3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import kotlin.test.Test @@ -12,6 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith +@OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_substitute_Double() { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt new file mode 100644 index 000000000..89764db46 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -0,0 +1,138 @@ +/* + * 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.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.operations.Ring + + +class IntModulo { + val residue: Int + val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +class IntModuloRing : Ring { + + val modulus: Int + + constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} + +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt new file mode 100644 index 000000000..72bb5942c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -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, NumbersAddOps { + 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 +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt new file mode 100644 index 000000000..ed41b9245 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt @@ -0,0 +1,29 @@ +/* + * 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 + + +data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file From 1fd8dfd7b826718df16017dc7e2960ac85dbc98d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 13 Jun 2022 11:17:41 +0300 Subject: [PATCH 081/174] refactor Quaternions --- .../kmath/estree/internal/ESTreeBuilder.kt | 7 +- .../kscience/kmath/asm/internal/AsmBuilder.kt | 2 + kmath-complex/build.gradle.kts | 10 +- .../kscience/kmath/complex/Quaternion.kt | 133 ++++++++---------- kmath-geometry/build.gradle.kts | 2 +- .../kmath/geometry/Euclidean2DSpace.kt | 3 - .../kmath/geometry/Euclidean3DSpace.kt | 2 - 7 files changed, 68 insertions(+), 91 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 10a6c4a16..40c446da0 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -14,11 +14,12 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { @Suppress("UNUSED_VARIABLE") override fun invoke(arguments: Map): T { - val e = executable - val c = constants + //val e = executable + //val c = constants val a = js("{}") arguments.forEach { (key, value) -> a[key.identity] = value } - return js("e(c, a)").unsafeCast() + return executable.call(constants, a).unsafeCast() + //return js("e(c, a)").unsafeCast() } } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index a85079fc8..a76b47ecc 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -49,5 +49,7 @@ internal abstract class AsmBuilder { * ASM Type for [space.kscience.kmath.expressions.Symbol]. */ val SYMBOL_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Symbol") + + const val ARGUMENTS_NAME = "args" } } diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index ea74df646..f0ce631a5 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -19,13 +19,15 @@ readme { feature( id = "complex", - description = "Complex Numbers", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt" - ) + ){ + "Complex numbers operations" + } feature( id = "quaternion", - description = "Quaternions", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt" - ) + ){ + "Quaternions and their composition" + } } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 3ef3428c6..85c945faf 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -16,6 +16,52 @@ import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableMemoryBuffer import kotlin.math.* +/** + * Represents `double`-based quaternion. + * + * @property w The first component. + * @property x The second component. + * @property y The third component. + * @property z The fourth component. + */ +public data class Quaternion( + val w: Double, val x: Double, val y: Double, val z: Double, +) { + init { + require(!w.isNaN()) { "w-component of quaternion is not-a-number" } + require(!x.isNaN()) { "x-component of quaternion is not-a-number" } + require(!y.isNaN()) { "y-component of quaternion is not-a-number" } + require(!z.isNaN()) { "z-component of quaternion is not-a-number" } + } + + /** + * Returns a string representation of this quaternion. + */ + override fun toString(): String = "($w + $x * i + $y * j + $z * k)" + + public companion object : MemorySpec { + override val objectSize: Int + get() = 32 + + override fun MemoryReader.read(offset: Int): Quaternion = + Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) + + override fun MemoryWriter.write(offset: Int, value: Quaternion) { + writeDouble(offset, value.w) + writeDouble(offset + 8, value.x) + writeDouble(offset + 16, value.y) + writeDouble(offset + 24, value.z) + } + } +} + +public fun Quaternion(w: Number, x: Number = 0.0, y: Number = 0.0, z: Number = 0.0): Quaternion = Quaternion( + w.toDouble(), + x.toDouble(), + y.toDouble(), + z.toDouble(), +) + /** * This quaternion's conjugate. */ @@ -45,23 +91,23 @@ public val Quaternion.r: Double @OptIn(UnstableKMathAPI::class) public object QuaternionField : Field, Norm, PowerOperations, ExponentialOperations, NumbersAddOps, ScaleOperations { - override val zero: Quaternion = 0.toQuaternion() - override val one: Quaternion = 1.toQuaternion() + override val zero: Quaternion = Quaternion(0.0) + override val one: Quaternion = Quaternion(1.0) /** * The `i` quaternion unit. */ - public val i: Quaternion = Quaternion(0, 1) + public val i: Quaternion = Quaternion(0.0, 1.0, 0.0, 0.0) /** * The `j` quaternion unit. */ - public val j: Quaternion = Quaternion(0, 0, 1) + public val j: Quaternion = Quaternion(0.0, 0.0, 1.0, 0.0) /** * The `k` quaternion unit. */ - public val k: Quaternion = Quaternion(0, 0, 0, 1) + public val k: Quaternion = Quaternion(0.0, 0.0, 0.0, 1.0) override fun add(left: Quaternion, right: Quaternion): Quaternion = Quaternion(left.w + right.w, left.x + right.x, left.y + right.y, left.z + right.z) @@ -133,7 +179,7 @@ public object QuaternionField : Field, Norm, override fun exp(arg: Quaternion): Quaternion { val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z - if (un == 0.0) return exp(arg.w).toQuaternion() + if (un == 0.0) return Quaternion(exp(arg.w)) val n1 = sqrt(un) val ea = exp(arg.w) val n2 = ea * sin(n1) / n1 @@ -158,7 +204,8 @@ public object QuaternionField : Field, Norm, return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - override operator fun Number.plus(other: Quaternion): Quaternion = Quaternion(toDouble() + other.w, other.x, other.y, other.z) + override operator fun Number.plus(other: Quaternion): Quaternion = + Quaternion(toDouble() + other.w, other.x, other.y, other.z) override operator fun Number.minus(other: Quaternion): Quaternion = Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z) @@ -179,7 +226,7 @@ public object QuaternionField : Field, Norm, else -> null } - override fun number(value: Number): Quaternion = value.toQuaternion() + override fun number(value: Number): Quaternion = Quaternion(value) override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 @@ -189,76 +236,6 @@ public object QuaternionField : Field, Norm, override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 } -/** - * Represents `double`-based quaternion. - * - * @property w The first component. - * @property x The second component. - * @property y The third component. - * @property z The fourth component. - */ -@OptIn(UnstableKMathAPI::class) -public data class Quaternion( - val w: Double, val x: Double, val y: Double, val z: Double, -) { - public constructor(w: Number, x: Number, y: Number, z: Number) : this( - w.toDouble(), - x.toDouble(), - y.toDouble(), - z.toDouble(), - ) - - public constructor(w: Number, x: Number, y: Number) : this(w.toDouble(), x.toDouble(), y.toDouble(), 0.0) - public constructor(w: Number, x: Number) : this(w.toDouble(), x.toDouble(), 0.0, 0.0) - public constructor(w: Number) : this(w.toDouble(), 0.0, 0.0, 0.0) - public constructor(wx: Complex, yz: Complex) : this(wx.re, wx.im, yz.re, yz.im) - public constructor(wx: Complex) : this(wx.re, wx.im, 0, 0) - - init { - require(!w.isNaN()) { "w-component of quaternion is not-a-number" } - require(!x.isNaN()) { "x-component of quaternion is not-a-number" } - require(!y.isNaN()) { "x-component of quaternion is not-a-number" } - require(!z.isNaN()) { "x-component of quaternion is not-a-number" } - } - - /** - * Returns a string representation of this quaternion. - */ - override fun toString(): String = "($w + $x * i + $y * j + $z * k)" - - public companion object : MemorySpec { - override val objectSize: Int - get() = 32 - - override fun MemoryReader.read(offset: Int): Quaternion = - Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) - - override fun MemoryWriter.write(offset: Int, value: Quaternion) { - writeDouble(offset, value.w) - writeDouble(offset + 8, value.x) - writeDouble(offset + 16, value.y) - writeDouble(offset + 24, value.z) - } - } -} - -/** - * Creates a quaternion with real part equal to this real. - * - * @receiver the real part. - * @return a new quaternion. - */ -public fun Number.toQuaternion(): Quaternion = Quaternion(this) - -/** - * Creates a quaternion with `w`-component equal to `re`-component of given complex and `x`-component equal to - * `im`-component of given complex. - * - * @receiver the complex number. - * @return a new quaternion. - */ -public fun Complex.toQuaternion(): Quaternion = Quaternion(this) - /** * Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the * specified [init] function. diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 7eb814683..bfe2e32a2 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin.sourceSets.commonMain { dependencies { - api(project(":kmath-core")) + api(projects.kmath.kmathComplex) } } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index d00575bcc..a83cb3ac7 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -6,12 +6,10 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.math.sqrt -@OptIn(UnstableKMathAPI::class) public interface Vector2D : Point, Vector { public val x: Double public val y: Double @@ -29,7 +27,6 @@ public interface Vector2D : Point, Vector { public val Vector2D.r: Double get() = Euclidean2DSpace { norm() } -@Suppress("FunctionName") public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y) private data class Vector2DImpl( diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index e12563b46..d3b3fb15e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -6,12 +6,10 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.math.sqrt -@OptIn(UnstableKMathAPI::class) public interface Vector3D : Point, Vector { public val x: Double public val y: Double From 5928adfe45fc4b1d608e94fb5b2c12c447377c24 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:08:58 +0300 Subject: [PATCH 082/174] Fixed merging accidents. --- .../kscience/kmath/functions/Piecewise.kt | 132 ++++++++++++++++++ .../kmath/integration/SplineIntegrator.kt | 112 +++++++++++++++ .../kmath/interpolation/Interpolator.kt | 92 ++++++++++++ .../kmath/interpolation/LinearInterpolator.kt | 43 ++++++ .../kmath/interpolation/SplineInterpolator.kt | 88 ++++++++++++ .../kmath/integration/SplineIntegralTest.kt | 48 +++++++ .../interpolation/LinearInterpolatorTest.kt | 29 ++++ .../interpolation/SplineInterpolatorTest.kt | 36 +++++ 8 files changed, 580 insertions(+) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt new file mode 100644 index 000000000..612b00535 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -0,0 +1,132 @@ +/* + * 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.PerformancePitfall +import space.kscience.kmath.operations.Ring + +/** + * Represents piecewise-defined function. + * + * @param T the piece key type. + * @param R the sub-function type. + */ +public fun interface Piecewise { + /** + * Returns the appropriate sub-function for given piece key. + */ + public fun findPiece(arg: T): R? +} + +/** + * Represents piecewise-defined function where all the sub-functions are polynomials. + * + * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no + * "holes" in it. + */ +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, ListPolynomial>> + + override fun findPiece(arg: T): ListPolynomial? +} + +/** + * A generic piecewise without constraints on how pieces are placed + */ +@PerformancePitfall("findPiece method of resulting piecewise is slow") +public fun > PiecewisePolynomial( + pieces: Collection, ListPolynomial>>, +): PiecewisePolynomial = object : PiecewisePolynomial { + override val pieces: Collection, ListPolynomial>> = pieces + + override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second +} + +/** + * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. + * The pieces search is logarithmic. + */ +private class OrderedPiecewisePolynomial>( + override val pieces: List, ListPolynomial>>, +) : PiecewisePolynomial { + + override fun findPiece(arg: T): ListPolynomial? { + val index = pieces.binarySearch { (range, _) -> + when { + arg >= range.endInclusive -> -1 + arg < range.start -> +1 + else -> 0 + } + } + return if (index < 0) null else pieces[index].second + } + +} + +/** + * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. + * + * @param T the comparable piece key type. + * @param delimiter the initial piecewise separator + */ +public class PiecewiseBuilder>(delimiter: T) { + private val delimiters: MutableList = arrayListOf(delimiter) + private val pieces: MutableList> = arrayListOf() + + /** + * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) + * + * @param right new rightmost position. If is less than current rightmost position, an error is thrown. + * @param piece the sub-function. + */ + public fun putRight(right: T, piece: ListPolynomial) { + require(right > delimiters.last()) { "New delimiter should be to the right of old one" } + delimiters += right + pieces += piece + } + + /** + * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) + * + * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. + * @param piece the sub-function. + */ + public fun putLeft(left: T, piece: ListPolynomial) { + require(left < delimiters.first()) { "New delimiter should be to the left of old one" } + delimiters.add(0, left) + pieces.add(0, piece) + } + + public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> + l..r + }.zip(pieces)) +} + +/** + * A builder for [PiecewisePolynomial] + */ +public fun > PiecewisePolynomial( + startingPoint: T, + builder: PiecewiseBuilder.() -> Unit, +): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() + +/** + * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise + * definition. + */ +public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = + findPiece(arg)?.substitute(ring, arg) + +/** + * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). + */ +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } + +/** + * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. + */ +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = + { substitute(ring, it) ?: defaultValue } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt new file mode 100644 index 000000000..80006c2de --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -0,0 +1,112 @@ +/* + * 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. + */ + +/* + * 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.integration + +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.integrate +import space.kscience.kmath.functions.antiderivative +import space.kscience.kmath.interpolation.PolynomialInterpolator +import space.kscience.kmath.interpolation.SplineInterpolator +import space.kscience.kmath.interpolation.interpolatePolynomials +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory + +/** + * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact + */ +@OptIn(PerformancePitfall::class) +@UnstableKMathAPI +public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = + PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) + +/** + * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] + * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] + * + * TODO use context receiver for algebra + */ +@UnstableKMathAPI +public fun > PiecewisePolynomial.integrate( + algebra: Field, range: ClosedRange, +): T = algebra.sum( + pieces.map { (region, poly) -> + val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) + //Check if polynomial range is not used + if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero + else poly.integrate(algebra, intersectedRange) + } +) + +/** + * A generic spline-interpolation-based analytic integration + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses + * the maximum number of points. By default, uses 10 points. + */ +@UnstableKMathAPI +public class SplineIntegrator>( + public val algebra: Field, + public val bufferFactory: MutableBufferFactory, +) : UnivariateIntegrator { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { + val range = integrand.getFeature()?.range ?: 0.0..1.0 + + val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) + + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val step = (range.endInclusive - range.start) / (numPoints - 1) + DoubleBuffer(numPoints) { i -> range.start + i * step } + } + + val values = nodes.map(bufferFactory) { integrand.function(it) } + val polynomials = interpolator.interpolatePolynomials( + nodes.map(bufferFactory) { number(it) }, + values + ) + val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) + integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) + } +} + +/** + * A simplified double-based spline-interpolation-based analytic integration + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always + * uses the maximum number of points. By default, uses 10 points. + */ +@UnstableKMathAPI +public object DoubleSplineIntegrator : UnivariateIntegrator { + override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + val range = integrand.getFeature()?.range ?: 0.0..1.0 + val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) + + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { + val numPoints = integrand.getFeature()?.maxCalls ?: 100 + val step = (range.endInclusive - range.start) / (numPoints - 1) + DoubleBuffer(numPoints) { i -> range.start + i * step } + } + + val values = nodes.map { integrand.function(it) } + val polynomials = interpolator.interpolatePolynomials(nodes, values) + val res = polynomials.integrate(DoubleField, range) + return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) + } +} + +@Suppress("unused") +@UnstableKMathAPI +public inline val DoubleField.splineIntegrator: UnivariateIntegrator + get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt new file mode 100644 index 000000000..62819be0c --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.asFunction +import space.kscience.kmath.functions.substitute +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + +/** + * And interpolator for data with x column type [X], y column type [Y]. + */ +public fun interface Interpolator { + public fun interpolate(points: XYColumnarData): (X) -> Y +} + +/** + * And interpolator returning [PiecewisePolynomial] function + */ +public interface PolynomialInterpolator> : Interpolator { + public val algebra: Ring + + public fun getDefaultValue(): T = error("Out of bounds") + + public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial + + override fun interpolate(points: XYColumnarData): (T) -> T = { x -> + interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() + } +} + + +public fun > PolynomialInterpolator.interpolatePolynomials( + x: Buffer, + y: Buffer, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(x, y) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolatePolynomials( + data: Map, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolatePolynomials( + data: List>, +): PiecewisePolynomial { + val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + return interpolatePolynomials(pointSet) +} + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, +): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: Map, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + +public fun > PolynomialInterpolator.interpolate( + data: List>, +): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) + + +public fun > PolynomialInterpolator.interpolate( + x: Buffer, + y: Buffer, + defaultValue: T, +): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: Map, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) + +public fun > PolynomialInterpolator.interpolate( + data: List>, + defaultValue: T, +): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt new file mode 100644 index 000000000..b55f16cf2 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -0,0 +1,43 @@ +/* + * 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.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke + +@OptIn(UnstableKMathAPI::class) +internal fun > insureSorted(points: XYColumnarData<*, T, *>) { + for (i in 0 until points.size - 1) + require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } +} + +/** + * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java + */ +public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { + + @OptIn(UnstableKMathAPI::class) + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + require(points.size > 0) { "Point array should not be empty" } + insureSorted(points) + + PiecewisePolynomial(points.x[0]) { + for (i in 0 until points.size - 1) { + val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) + val const = points.y[i] - slope * points.x[i] + val polynomial = ListPolynomial(const, slope) + putRight(points.x[i + 1], polynomial) + } + } + } +} + +public val > Field.linearInterpolator: LinearInterpolator + get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt new file mode 100644 index 000000000..0bcbfd0c6 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* + * 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.interpolation + +import space.kscience.kmath.data.XYColumnarData +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory + +/** + * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type + * specific ones. + * + * Based on + * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java + */ +public class SplineInterpolator>( + override val algebra: Field, + public val bufferFactory: MutableBufferFactory, +) : PolynomialInterpolator { + //TODO possibly optimize zeroed buffers + + @OptIn(UnstableKMathAPI::class) + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } + insureSorted(points) + // Number of intervals. The number of data points is n + 1. + val n = points.size - 1 + // Differences between knot points + val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } + val mu = bufferFactory(n) { zero } + val z = bufferFactory(n + 1) { zero } + + for (i in 1 until n) { + val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] + mu[i] = h[i] / g + z[i] = + ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / + (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g + } + + // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) + + PiecewisePolynomial(points.x[points.size - 1]) { + var cOld = zero + + for (j in n - 1 downTo 0) { + val c = z[j] - mu[j] * cOld + val a = points.y[j] + val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 + val d = (cOld - c) / (3.0 * h[j]) + val x0 = points.x[j] + val x02 = x0 * x0 + val x03 = x02 * x0 + //Shift coefficients to represent absolute polynomial instead of one with an offset + val polynomial = ListPolynomial( + a - b * x0 + c * x02 - d * x03, + b - 2 * c * x0 + 3 * d * x02, + c - 3 * d * x0, + d + ) + cOld = c + putLeft(x0, polynomial) + } + } + } +} + + +public fun > Field.splineInterpolator( + bufferFactory: MutableBufferFactory, +): SplineInterpolator = SplineInterpolator(this, bufferFactory) + +public val DoubleField.splineInterpolator: SplineInterpolator + get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt new file mode 100644 index 000000000..aae0ad017 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -0,0 +1,48 @@ +/* + * 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.integration + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.integrate +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import kotlin.math.PI +import kotlin.math.sin +import kotlin.test.Test +import kotlin.test.assertEquals + +@OptIn(UnstableKMathAPI::class) +class SplineIntegralTest { + + @Test + fun integratePolynomial(){ + val polynomial = ListPolynomial(1.0, 2.0, 3.0) + val integral = polynomial.integrate(DoubleField,1.0..2.0) + assertEquals(11.0, integral, 0.001) + } + + @Test + fun gaussSin() { + val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> + sin(x) + } + assertEquals(0.0, res.value, 1e-2) + } + + @Test + fun gaussUniform() { + val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> + if(x in 30.0..50.0){ + 1.0 + } else { + 0.0 + } + } + assertEquals(15.0, res.value, 0.5) + } + + +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt new file mode 100644 index 000000000..1143036d4 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -0,0 +1,29 @@ +/* + * 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.interpolation + +import space.kscience.kmath.operations.DoubleField +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class LinearInterpolatorTest { + @Test + fun testInterpolation() { + val data = listOf( + 0.0 to 0.0, + 1.0 to 1.0, + 2.0 to 3.0, + 3.0 to 4.0 + ) + + //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) + val function = DoubleField.linearInterpolator.interpolate(data) + assertEquals(null, function(-1.0)) + assertEquals(0.5, function(0.5)) + assertEquals(2.0, function(1.5)) + assertEquals(3.0, function(2.0)) + } +} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt new file mode 100644 index 000000000..f748535e2 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* + * 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.interpolation + +import space.kscience.kmath.operations.DoubleField +import kotlin.math.PI +import kotlin.math.sin +import kotlin.test.Test +import kotlin.test.assertEquals + +internal class SplineInterpolatorTest { + @Test + fun testInterpolation() { + val data = (0..10).map { + val x = it.toDouble() / 5 * PI + x to sin(x) + } + + //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) + + val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) + + assertEquals(Double.NaN, function(-1.0)) + assertEquals(sin(0.5), function(0.5), 0.1) + assertEquals(sin(1.5), function(1.5), 0.1) + assertEquals(sin(2.0), function(2.0), 0.1) + } +} From 58e0715714487323a46f5b86e121a46782d356c5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 13 Jun 2022 12:15:14 +0300 Subject: [PATCH 083/174] Removed duplicates of copyright comments. --- .../space/kscience/kmath/integration/SplineIntegrator.kt | 5 ----- .../space/kscience/kmath/interpolation/SplineInterpolator.kt | 5 ----- .../kscience/kmath/interpolation/SplineInterpolatorTest.kt | 5 ----- 3 files changed, 15 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 80006c2de..0fcd4c6e5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.integration import space.kscience.kmath.functions.PiecewisePolynomial diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index 0bcbfd0c6..48c90ff23 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.interpolation import space.kscience.kmath.data.XYColumnarData diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index f748535e2..4c7d816d4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * 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.interpolation import space.kscience.kmath.operations.DoubleField From 85a1e8b33f3ed3683d1e68e722ef0cf89fc43cc5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 14 Jun 2022 16:27:32 +0300 Subject: [PATCH 084/174] New common test infrastructure --- build.gradle.kts | 14 ++- .../kscience/kmath/complex/Quaternion.kt | 79 ++++++++++---- ...aternionFieldTest.kt => QuaternionTest.kt} | 15 ++- .../kmath/geometry/Euclidean3DSpace.kt | 14 +++ .../{Projections.kt => projections.kt} | 2 + .../kscience/kmath/geometry/rotations3D.kt | 100 ++++++++++++++++++ .../kscience/kmath/geometry/RotationTest.kt | 35 ++++++ .../tensorflow/DoubleTensorFlowAlgebra.kt | 2 + settings.gradle.kts | 1 + test-utils/build.gradle.kts | 13 +++ .../commonMain/kotlin}/AlgebraicVerifier.kt | 0 .../src/commonMain/kotlin}/FieldVerifier.kt | 2 +- .../src/commonMain/kotlin}/RingVerifier.kt | 2 +- .../src/commonMain/kotlin}/SpaceVerifier.kt | 10 +- test-utils/src/commonMain/kotlin/asserts.kt | 20 ++++ 15 files changed, 279 insertions(+), 30 deletions(-) rename kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/{QuaternionFieldTest.kt => QuaternionTest.kt} (84%) rename kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/{Projections.kt => projections.kt} (97%) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt create mode 100644 kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt create mode 100644 test-utils/build.gradle.kts rename {kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils => test-utils/src/commonMain/kotlin}/AlgebraicVerifier.kt (100%) rename {kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils => test-utils/src/commonMain/kotlin}/FieldVerifier.kt (96%) rename {kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils => test-utils/src/commonMain/kotlin}/RingVerifier.kt (95%) rename {kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils => test-utils/src/commonMain/kotlin}/SpaceVerifier.kt (93%) create mode 100644 test-utils/src/commonMain/kotlin/asserts.kt diff --git a/build.gradle.kts b/build.gradle.kts index ab136bfbc..d8c591799 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,7 @@ allprojects { subprojects { if (name.startsWith("kmath")) apply() - plugins.withId("org.jetbrains.dokka"){ + plugins.withId("org.jetbrains.dokka") { tasks.withType { dependsOn(tasks["assemble"]) @@ -51,6 +51,18 @@ subprojects { } } } + + plugins.withId("org.jetbrains.kotlin.multiplatform") { + configure { + sourceSets { + val commonTest by getting { + dependencies { + implementation(projects.testUtils) + } + } + } + } + } } readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 85c945faf..359b66b20 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -24,9 +24,12 @@ import kotlin.math.* * @property y The third component. * @property z The fourth component. */ -public data class Quaternion( - val w: Double, val x: Double, val y: Double, val z: Double, -) { +public class Quaternion( + public val w: Double, + public val x: Double, + public val y: Double, + public val z: Double, +) : Buffer { init { require(!w.isNaN()) { "w-component of quaternion is not-a-number" } require(!x.isNaN()) { "x-component of quaternion is not-a-number" } @@ -39,12 +42,49 @@ public data class Quaternion( */ override fun toString(): String = "($w + $x * i + $y * j + $z * k)" - public companion object : MemorySpec { - override val objectSize: Int - get() = 32 + override val size: Int get() = 4 - override fun MemoryReader.read(offset: Int): Quaternion = - Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) + override fun get(index: Int): Double = when (index) { + 0 -> w + 1 -> x + 2 -> y + 3 -> z + else -> error("Index $index out of bounds [0,3]") + } + + override fun iterator(): Iterator = listOf(w, x, y, z).iterator() + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as Quaternion + + if (w != other.w) return false + if (x != other.x) return false + if (y != other.y) return false + if (z != other.z) return false + + return true + } + + override fun hashCode(): Int { + var result = w.hashCode() + result = 31 * result + x.hashCode() + result = 31 * result + y.hashCode() + result = 31 * result + z.hashCode() + return result + } + + public companion object : MemorySpec { + override val objectSize: Int get() = 32 + + override fun MemoryReader.read(offset: Int): Quaternion = Quaternion( + readDouble(offset), + readDouble(offset + 8), + readDouble(offset + 16), + readDouble(offset + 24) + ) override fun MemoryWriter.write(offset: Int, value: Quaternion) { writeDouble(offset, value.w) @@ -66,30 +106,22 @@ public fun Quaternion(w: Number, x: Number = 0.0, y: Number = 0.0, z: Number = 0 * This quaternion's conjugate. */ public val Quaternion.conjugate: Quaternion - get() = QuaternionField { z - x * i - y * j - z * k } + get() = Quaternion(w, -x, -y, -z) /** * This quaternion's reciprocal. */ public val Quaternion.reciprocal: Quaternion get() { - QuaternionField { - val n = norm(this@reciprocal) - return conjugate / (n * n) - } + val norm2 = (w * w + x * x + y * y + z * z) + return Quaternion(w / norm2, -x / norm2, -y / norm2, -z / norm2) } -/** - * Absolute value of the quaternion. - */ -public val Quaternion.r: Double - get() = sqrt(w * w + x * x + y * y + z * z) - /** * A field of [Quaternion]. */ @OptIn(UnstableKMathAPI::class) -public object QuaternionField : Field, Norm, PowerOperations, +public object QuaternionField : Field, Norm, PowerOperations, ExponentialOperations, NumbersAddOps, ScaleOperations { override val zero: Quaternion = Quaternion(0.0) override val one: Quaternion = Quaternion(1.0) @@ -217,7 +249,12 @@ public object QuaternionField : Field, Norm, Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z) override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) - override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) + override fun norm(arg: Quaternion): Double = sqrt( + arg.w.pow(2) + + arg.x.pow(2) + + arg.y.pow(2) + + arg.z.pow(2) + ) override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { "i" -> i diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt similarity index 84% rename from kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt rename to kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt index 6784f3516..fd4df736c 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt @@ -6,10 +6,23 @@ package space.kscience.kmath.complex import space.kscience.kmath.operations.invoke +import space.kscience.kmath.testutils.assertBufferEquals import kotlin.test.Test import kotlin.test.assertEquals -internal class QuaternionFieldTest { +internal class QuaternionTest { + + @Test + fun testNorm() { + assertEquals(2.0, QuaternionField.norm(Quaternion(1.0, 1.0, 1.0, 1.0))) + } + + @Test + fun testInverse() = QuaternionField { + val q = Quaternion(1.0, 2.0, -3.0, 4.0) + assertBufferEquals(one, q * q.reciprocal, 1e-4) + } + @Test fun testAddition() { assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) }) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index d3b3fb15e..c1fc74bf1 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer import kotlin.math.sqrt public interface Vector3D : Point, Vector { @@ -29,6 +30,19 @@ public interface Vector3D : Point, Vector { @Suppress("FunctionName") public fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) +public fun Buffer.asVector3D(): Vector3D = object : Vector3D { + init { + require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" } + } + + override val x: Double get() = this@asVector3D[0] + override val y: Double get() = this@asVector3D[1] + override val z: Double get() = this@asVector3D[2] + + override fun toString(): String = this@asVector3D.toString() + +} + public val Vector3D.r: Double get() = Euclidean3DSpace { norm() } private data class Vector3DImpl( diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Projections.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt similarity index 97% rename from kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Projections.kt rename to kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt index 5e299f450..6ffc43739 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Projections.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.geometry +//TODO move vector to receiver + /** * Project vector onto a line. * @param vector to project diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt new file mode 100644 index 000000000..374315610 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt @@ -0,0 +1,100 @@ +/* + * 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.geometry + +import space.kscience.kmath.complex.Quaternion +import space.kscience.kmath.complex.QuaternionField +import space.kscience.kmath.complex.reciprocal +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.linear.matrix +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.math.pow +import kotlin.math.sqrt + +internal fun Vector3D.toQuaternion(): Quaternion = Quaternion(0.0, x, y, z) + +/** + * Angle in radians denoted by this quaternion rotation + */ +public val Quaternion.theta: Double get() = kotlin.math.acos(w) * 2 + +/** + * An axis of quaternion rotation + */ +public val Quaternion.vector: Vector3D + get() { + val sint2 = sqrt(1 - w * w) + + return object : Vector3D { + override val x: Double get() = this@vector.x/sint2 + override val y: Double get() = this@vector.y/sint2 + override val z: Double get() = this@vector.z/sint2 + override fun toString(): String = listOf(x, y, z).toString() + } + } + +/** + * Rotate a vector in a [Euclidean3DSpace] + */ +public fun Euclidean3DSpace.rotate(vector: Vector3D, q: Quaternion): Vector3D = with(QuaternionField) { + val p = vector.toQuaternion() + (q * p * q.reciprocal).vector +} + +/** + * Use a composition of quaternions to create a rotation + */ +public fun Euclidean3DSpace.rotate(vector: Vector3D, composition: QuaternionField.() -> Quaternion): Vector3D = + rotate(vector, QuaternionField.composition()) + +public fun Euclidean3DSpace.rotate(vector: Vector3D, matrix: Matrix): Vector3D { + require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" } + return with(DoubleField.linearSpace) { matrix.dot(vector).asVector3D() } +} + +/** + * Convert a [Quaternion] to a rotation matrix + */ +@OptIn(UnstableKMathAPI::class) +public fun Quaternion.toRotationMatrix( + linearSpace: LinearSpace = DoubleField.linearSpace, +): Matrix { + val s = QuaternionField.norm(this).pow(-2) + return linearSpace.matrix(3, 3)( + 1.0 - 2 * s * (y * y + z * z), 2 * s * (x * y - z * w), 2 * s * (x * z + y * w), + 2 * s * (x * y + z * w), 1.0 - 2 * s * (x * x + z * z), 2 * s * (y * z - x * w), + 2 * s * (x * z - y * w), 2 * s * (y * z + x * w), 1.0 - 2 * s * (x * x + y * y) + ) +} + +/** + * taken from https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf + */ +public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix): Quaternion { + val t: Double + val q = if (matrix[2, 2] < 0) { + if (matrix[0, 0] > matrix[1, 1]) { + t = 1 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2] + Quaternion(t, matrix[0, 1] + matrix[1, 0], matrix[2, 0] + matrix[0, 2], matrix[1, 2] - matrix[2, 1]) + } else { + t = 1 - matrix[0, 0] + matrix[1, 1] - matrix[2, 2] + Quaternion(matrix[0, 1] + matrix[1, 0], t, matrix[1, 2] + matrix[2, 1], matrix[2, 0] - matrix[0, 2]) + } + } else { + if (matrix[0, 0] < -matrix[1, 1]) { + t = 1 - matrix[0, 0] - matrix[1, 1] + matrix[2, 2] + Quaternion(matrix[2, 0] + matrix[0, 2], matrix[1, 2] + matrix[2, 1], t, matrix[0, 1] - matrix[1, 0]) + } else { + t = 1 + matrix[0, 0] + matrix[1, 1] + matrix[2, 2] + Quaternion(matrix[1, 2] - matrix[2, 1], matrix[2, 0] - matrix[0, 2], matrix[0, 1] - matrix[1, 0], t) + } + } + return QuaternionField.invoke { q * (0.5 / sqrt(t)) } +} \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt new file mode 100644 index 000000000..ca7226fb6 --- /dev/null +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -0,0 +1,35 @@ +/* + * 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.geometry + +import space.kscience.kmath.complex.Quaternion +import space.kscience.kmath.testutils.assertBufferEquals +import kotlin.test.Test +import kotlin.test.assertEquals + +class RotationTest { + + @Test + fun rotations() = with(Euclidean3DSpace) { + val vector = Vector3D(1.0, 1.0, 1.0) + val q = Quaternion(1.0, 2.0, -3.0, 4.0) + val rotatedByQ = rotate(vector, q) + val matrix = q.toRotationMatrix() + val rotatedByM = rotate(vector,matrix) + + assertBufferEquals(rotatedByQ, rotatedByM, 1e-4) + } + + @Test + fun rotationConversion() { + + val q = Quaternion(1.0, 2.0, -3.0, 4.0) + + val matrix = q.toRotationMatrix() + + assertEquals(q, Quaternion.fromRotationMatrix(matrix)) + } +} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index ecfd8d098..ad7a978a0 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -7,6 +7,7 @@ import org.tensorflow.op.core.Constant import org.tensorflow.types.TFloat64 import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND @@ -74,6 +75,7 @@ public class DoubleTensorFlowAlgebra internal constructor( * * The resulting tensor is available outside of scope */ +@UnstableKMathAPI public fun DoubleField.produceWithTF( block: DoubleTensorFlowAlgebra.() -> StructureND, ): StructureND = Graph().use { graph -> diff --git a/settings.gradle.kts b/settings.gradle.kts index b14c594b4..e3c621e9a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,6 +20,7 @@ dependencyResolutionManagement { } include( + ":test-utils", ":kmath-memory", ":kmath-complex", ":kmath-core", diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts new file mode 100644 index 000000000..88c7ea9d0 --- /dev/null +++ b/test-utils/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") + id("ru.mipt.npm.gradle.native") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmath.kmathCore) + api(kotlin("test")) + } + } +} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt b/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt similarity index 100% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt rename to test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt b/test-utils/src/commonMain/kotlin/FieldVerifier.kt similarity index 96% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt rename to test-utils/src/commonMain/kotlin/FieldVerifier.kt index 20a7b6a72..f4ca7506b 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt +++ b/test-utils/src/commonMain/kotlin/FieldVerifier.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals import kotlin.test.assertNotEquals -internal class FieldVerifier>( +public class FieldVerifier>( algebra: A, a: T, b: T, c: T, x: Number, ) : RingVerifier(algebra, a, b, c, x) { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt b/test-utils/src/commonMain/kotlin/RingVerifier.kt similarity index 95% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt rename to test-utils/src/commonMain/kotlin/RingVerifier.kt index daf18834a..14606cb2c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt +++ b/test-utils/src/commonMain/kotlin/RingVerifier.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals -internal open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : +public open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : SpaceVerifier(algebra, a, b, c, x) where A : Ring, A : ScaleOperations { override fun verify() { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt b/test-utils/src/commonMain/kotlin/SpaceVerifier.kt similarity index 93% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt rename to test-utils/src/commonMain/kotlin/SpaceVerifier.kt index 951197fc6..d761a3775 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt +++ b/test-utils/src/commonMain/kotlin/SpaceVerifier.kt @@ -11,12 +11,12 @@ import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals import kotlin.test.assertNotEquals -internal open class SpaceVerifier( +public open class SpaceVerifier( override val algebra: S, - val a: T, - val b: T, - val c: T, - val x: Number, + public val a: T, + public val b: T, + public val c: T, + public val x: Number, ) : AlgebraicVerifier> where S : Ring, S : ScaleOperations { override fun verify() { algebra { diff --git a/test-utils/src/commonMain/kotlin/asserts.kt b/test-utils/src/commonMain/kotlin/asserts.kt new file mode 100644 index 000000000..8e7d1ae23 --- /dev/null +++ b/test-utils/src/commonMain/kotlin/asserts.kt @@ -0,0 +1,20 @@ +/* + * 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.testutils + +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices +import kotlin.test.assertEquals +import kotlin.test.fail + +public fun assertBufferEquals(expected: Buffer, result: Buffer, tolerance: Double = 1e-4) { + if (expected.size != result.size) { + fail("Expected size is ${expected.size}, but the result size is ${result.size}") + } + expected.indices.forEach { + assertEquals(expected[it], result[it], tolerance) + } +} \ No newline at end of file From b09127f090c2b9df283eae2bbf689a38bae9b8f0 Mon Sep 17 00:00:00 2001 From: Iaroslav Postovalov Date: Tue, 14 Jun 2022 22:52:47 +0700 Subject: [PATCH 085/174] Fix name clash in strict mode; replace eval with new Function --- .../space/kscience/kmath/estree/estree.kt | 2 +- .../kmath/estree/internal/ESTreeBuilder.kt | 28 +++++++------------ .../internal/estree/estree.extensions.kt | 5 +++- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt index a8b1aa2e1..240acf1d7 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt @@ -36,7 +36,7 @@ public fun MST.compileToExpression(algebra: Algebra): Expression ) } - return ESTreeBuilder { visit(typed) }.instance + return ESTreeBuilder { visit(typed) }.instance } /** diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 40c446da0..16a59d273 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -14,37 +14,28 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { @Suppress("UNUSED_VARIABLE") override fun invoke(arguments: Map): T { - //val e = executable - //val c = constants + val e = executable + val c = constants val a = js("{}") arguments.forEach { (key, value) -> a[key.identity] = value } - return executable.call(constants, a).unsafeCast() - //return js("e(c, a)").unsafeCast() + return js("e(c, a)").unsafeCast() } } + @Suppress("UNUSED_VARIABLE") val instance: Expression by lazy { val node = Program( sourceType = "script", - VariableDeclaration( - kind = "var", - VariableDeclarator( - id = Identifier("executable"), - init = FunctionExpression( - params = arrayOf(Identifier("constants"), Identifier("arguments")), - body = BlockStatement(ReturnStatement(bodyCallback())), - ), - ), - ), + ReturnStatement(bodyCallback()) ) - eval(generate(node)) - GeneratedExpression(js("executable"), constants.toTypedArray()) + val code = generate(node) + GeneratedExpression(js("new Function('constants', 'arguments_0', code)"), constants.toTypedArray()) } private val constants = mutableListOf() - fun constant(value: Any?) = when { + fun constant(value: Any?): BaseExpression = when { value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> SimpleLiteral(value) @@ -62,7 +53,8 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp } } - fun variable(name: Symbol): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name.identity)) + fun variable(name: Symbol): BaseExpression = + call(getOrFail, Identifier("arguments_0"), SimpleLiteral(name.identity)) fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( optional = false, diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt index 3aa31f921..5b1ce914e 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("unused") + package space.kscience.kmath.internal.estree internal fun Program(sourceType: String, vararg body: dynamic) = object : Program { @@ -28,9 +30,10 @@ internal fun Identifier(name: String) = object : Identifier { override var name = name } -internal fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression { +internal fun FunctionExpression(id: Identifier?, params: Array, body: BlockStatement) = object : FunctionExpression { override var params = params override var type = "FunctionExpression" + override var id: Identifier? = id override var body = body } From d0134bdbe9eb65b45f3764c775e657ee0186d163 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 14 Jun 2022 19:15:36 +0300 Subject: [PATCH 086/174] Sift 4. Cleaned up "numbered" case. Tests are in progress. --- .../kmath/operations/bufferOperation.kt | 9 + .../kmath/functions/ListPolynomial.kt | 24 +- .../kmath/functions/ListRationalFunction.kt | 34 +- .../kmath/functions/NumberedPolynomial.kt | 429 +++++++++++++++ .../functions/NumberedRationalFunction.kt | 239 ++++++++ .../kmath/functions/RationalFunction.kt | 8 + .../kscience/kmath/functions/listUtil.kt | 43 +- .../kmath/functions/numberedConstructors.kt | 478 ++++++++++++++++ .../kscience/kmath/functions/numberedUtil.kt | 515 ++++++++++++++++++ 9 files changed, 1724 insertions(+), 55 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 31b0c2841..762f08be1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -91,6 +91,15 @@ public inline fun Buffer.fold(initial: R, operation: (acc: R, T) return accumulator } +/** + * Fold given buffer according to indexed [operation] + */ +public inline fun Buffer.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R { + var accumulator = initial + for (index in this.indices) accumulator = operation(index, accumulator, get(index)) + return accumulator +} + /** * Zip two buffers using given [transform]. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index fce179fc8..42e3f7301 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -48,8 +48,8 @@ public data class ListPolynomial( } /** - * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the given [ring] - * of constants. + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. * * @param C the type of constants. Polynomials have them a coefficients in their terms. * @param A type of provided underlying ring of constants. It's [Ring] of [C]. @@ -313,6 +313,10 @@ public open class ListPolynomialSpace>( } ) } + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). @@ -332,42 +336,42 @@ public open class ListPolynomialSpace>( // 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. + * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided [argument]. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) } /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index f3e352bcd..e23baa548 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.Ring /** - * Represents rational function that stores its numerator and denominator as [ListPolynomial]s. + * Represents univariate rational function that stores its numerator and denominator as [ListPolynomial]s. */ public data class ListRationalFunction( public override val numerator: ListPolynomial, @@ -56,82 +56,82 @@ public class ListRationalFunctionSpace> ( * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: C): C = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunction(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunction(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ @Suppress("NOTHING_TO_INLINE") - public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { this.substitute(ring, it) } + public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: C): C = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ @Suppress("NOTHING_TO_INLINE") - public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = this.substitute(ring, argument) + public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt new file mode 100644 index 000000000..9304e66da --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -0,0 +1,429 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.structures.Buffer +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. + * + * @param C the type of constants. + */ +public data class NumberedPolynomial +@PublishedApi +internal constructor( + /** + * Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair + * "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of + * every variable in the monomial with multiplicity of the variable occurring in the monomial. For example + * coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + + * listOf(0, 1) to (-6), // (-6) x_2^1 + * ) + * ``` + * and also as + * ``` + * mapOf( + * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + + * listOf(0, 1) to (-6), // (-6) x_2^1 + * listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1 + * ) + * ``` + * It is not prohibited to put extra zero monomials into the map (as for `0 x_2 x_3` in the example). But the + * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + */ + public val coefficients: Map, C> +) : Polynomial { + override fun toString(): String = "NumberedPolynomial$coefficients" +} + +/** + * Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a + * [List] constructed with the provided [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class NumberedPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = + if (other == 0) this + else + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = + if (other == 0) zero + else NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) other + else + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = + if (this == 0) zero + else NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = + with(other.coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = + with(other.coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@minus)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyList() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = + with(coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = + with(coefficients) { + if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) + else NumberedPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyList() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = + NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): NumberedPolynomial = + NumberedPolynomialAsIs(mapOf(emptyList() to value)) + + /** + * Returns negation of the polynomial. + */ + override fun NumberedPolynomial.unaryMinus(): NumberedPolynomial = + NumberedPolynomialAsIs( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun NumberedPolynomial.times(other: NumberedPolynomial): NumberedPolynomial = + NumberedPolynomialAsIs( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = + (0..max(degs1.lastIndex, degs2.lastIndex)) + .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: NumberedPolynomial, exponent: UInt): NumberedPolynomial = super.power(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: NumberedPolynomial = NumberedPolynomialAsIs(emptyMap()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: NumberedPolynomial by lazy { + NumberedPolynomialAsIs( + mapOf( + emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... + ) + ) + } + + /** + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. + */ + public val NumberedPolynomial.lastVariable: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val NumberedPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And last index of the list is [lastVariable]. + */ + public val NumberedPolynomial.degrees: List + get() = + MutableList(lastVariable + 1) { 0u }.apply { + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + this[index] = max(this[index], deg) + } + } + } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> + degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + } ?: 0u + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(arguments: Map): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(arguments: Map>) : NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(arguments: Buffer): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun NumberedPolynomial.substitute(arguments: Buffer>) : NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = this.substituteFully(ring, arguments) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [arguments]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt new file mode 100644 index 000000000..a2986879d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -0,0 +1,239 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate rational function that stores its numerator and denominator as [NumberedPolynomial]s. + */ +public class NumberedRationalFunction internal constructor( + public override val numerator: NumberedPolynomial, + public override val denominator: NumberedPolynomial +) : RationalFunction> { + override fun toString(): String = "NumberedRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [NumberedPolynomial]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 NumberedRationalFunctionSpace> ( + public val ring: A, +) : + RationalFunctionalSpaceOverPolynomialSpace< + C, + NumberedPolynomial, + NumberedRationalFunction, + NumberedPolynomialSpace, + >, + PolynomialSpaceOfFractions< + C, + NumberedPolynomial, + NumberedRationalFunction, + >() { + + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ + public override val polynomialRing : NumberedPolynomialSpace = NumberedPolynomialSpace(ring) + /** + * Constructor of rational functions (of type [NumberedRationalFunction]) from numerator and denominator (of type [NumberedPolynomial]). + */ + protected override fun constructRationalFunction( + numerator: NumberedPolynomial, + denominator: NumberedPolynomial + ): NumberedRationalFunction = + NumberedRationalFunction(numerator, denominator) + + /** + * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, + * the result is `-1`. + */ + public val NumberedPolynomial.lastVariable: Int get() = polynomialRing { lastVariable } + /** + * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most + * exponents in which the variables are appeared in the polynomial. + * + * As consequence all values in the list are non-negative integers. Also, if the polynomial is constant, the list is empty. + * And last index of the list is [lastVariable]. + */ + public val NumberedPolynomial.degrees: List get() = polynomialRing { degrees } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun NumberedPolynomial.degreeBy(variable: Int): UInt = polynomialRing { degreeBy(variable) } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = polynomialRing { degreeBy(variables) } + /** + * Count of variables occurring in the polynomial with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedPolynomial.countOfVariables: Int get() = polynomialRing { countOfVariables } + + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val NumberedRationalFunction.lastVariable: Int + get() = polynomialRing { max(numerator.lastVariable, denominator.lastVariable) } + /** + * Count of variables occurring in the rational function with positive power. If there is no such variable, + * the result is `0`. + */ + public val NumberedRationalFunction.countOfVariables: Int + get() = + MutableList(lastVariable + 1) { false }.apply { + numerator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + denominator.coefficients.entries.forEach { (degs, _) -> + degs.forEachIndexed { index, deg -> + if (deg != 0u) this[index] = true + } + } + }.count { it } + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(argument: Buffer): NumberedRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided rational function [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided constant [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = substituteFully(ring, arguments) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedPolynomial.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.asFunctionOfPolynomial(): (Buffer>) -> NumberedRationalFunction = asFunctionOfPolynomialOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun NumberedRationalFunction.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [arguments]. + */ + @Suppress("NOTHING_TO_INLINE") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) + /** + * Substitutes provided [arguments] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("invokePolynomial") + public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 01911f980..338ae9935 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1076,6 +1076,14 @@ public abstract class PolynomialSpaceOfFractions< numerator * other.denominator, denominator * other.numerator ) + /** + * Raises [arg] to the integer power [exponent]. + */ + public override fun power(arg: R, exponent: UInt): R = + constructRationalFunction( + power(arg.numerator, exponent), + power(arg.denominator, exponent), + ) /** * Instance of zero rational function (zero of the rational functions ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 127dd8c7a..649fc48bd 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -147,12 +147,17 @@ public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C /** * Represent [this] polynomial as a regular context-less function. */ -public fun > ListPolynomial.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } +public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ -public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } +public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. @@ -162,12 +167,17 @@ public fun > ListRationalFunction.asFunctionOver(ring: A): (C /** * Represent [this] rational function as a regular context-less function. */ -public fun > ListRationalFunction.asPolynomialFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } +public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ -public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } +public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Returns algebraic derivative of received polynomial. @@ -242,27 +252,4 @@ public fun > ListPolynomial.integrate( ): 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 ListRationalFunction.derivative( - ring: A, -): ListRationalFunction where A : Ring, A : NumericAlgebra = 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 ListRationalFunction.nthDerivative( - ring: A, - order: Int, -): ListRationalFunction where A : Ring, A : NumericAlgebra = - if (order == 0) this else derivative(ring).nthDerivative(ring, order - 1) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt new file mode 100644 index 000000000..05fff3472 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -0,0 +1,478 @@ +/* + * 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.Ring + + +/** + * Returns the same degrees' description of the monomial, but without extra zero degrees on the end. + */ +internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@PublishedApi +internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return NumberedPolynomial(fixedCoefs) +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } + +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } + +/** + * Converts [this] constant to [NumberedPolynomial]. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomialAsIs(mapOf(emptyList() to this)) + +/** + * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@DslMarker +@UnstableKMathAPI +internal annotation class NumberedPolynomialConstructorDSL + +/** + * Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. + */ +@UnstableKMathAPI +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialTermSignatureBuilder { + /** + * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. + * Afterward the storage will be used as a resulting signature. + */ + private val signature: MutableList = ArrayList() + + /** + * Builds the resulting signature. + * + * In fact, it just returns [signature] as regular signature of type `List`. + */ + internal fun build(): List = signature + + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + public infix fun Int.inPowerOf(deg: UInt) { + if (this > signature.lastIndex) { + signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + signature.add(deg) + } else { + signature[this] += deg + } + } + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of variable #[this] of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg +} + +/** + * Builder of [NumberedPolynomial]. It should be used as an implicit context for lambdas that describe [NumberedPolynomial]. + */ +@UnstableKMathAPI +@NumberedPolynomialConstructorDSL +public class NumberedPolynomialBuilder( + /** + * Summation operation that will be used to sum coefficients of monomials of same signatures. + */ + private val add: (C, C) -> C, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int = 0 +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): NumberedPolynomial = NumberedPolynomial(coefficients) + + /** + * Declares monomial with [this] coefficient and provided [signature]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public infix fun C.with(signature: List) { + if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with) + else coefficients[signature] = this@with + } + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with NumberedPolynomialTermSignatureBuilder().apply(block).build() +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +@Suppress("FunctionName") +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) +/** + * Constructs [NumberedRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomial(denominatorCoefficients) + ) + +/** + * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) +/** + * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = + NumberedRationalFunction(numerator, polynomialOne) + +/** + * Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + polynomialOne + ) +/** + * Constructs [NumberedRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +@Suppress("FunctionName") +public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = + NumberedRationalFunction( + NumberedPolynomial(numeratorCoefficients), + NumberedPolynomialAsIs(mapOf(emptyList() to one)) + ) + +///** +// * Converts [this] coefficient to [NumberedRationalFunction]. +// */ +//context(A) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = +// NumberedRationalFunction( +// NumberedPolynomialAsIs(mapOf(emptyList() to this)), +// NumberedPolynomialAsIs(mapOf(emptyList() to one)) +// ) +///** +// * Converts [this] coefficient to [NumberedRationalFunction]. +// */ +//context(NumberedRationalFunctionSpace) +//public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = +// NumberedRationalFunction( +// NumberedPolynomialAsIs(mapOf(emptyList() to this)), +// NumberedPolynomialAsIs(mapOf(emptyList() to constantOne)) +// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt new file mode 100644 index 000000000..484cd11e3 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -0,0 +1,515 @@ +/* + * 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.Field +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName +import kotlin.math.max +import kotlin.math.min + + +/** + * Creates a [NumberedPolynomialSpace] over a received ring. + */ +public fun > A.numberedPolynomialSpace(): NumberedPolynomialSpace = + NumberedPolynomialSpace(this) + +/** + * Creates a [NumberedPolynomialSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedPolynomialSpace(block: NumberedPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedPolynomialSpace(this).block() +} + +/** + * Creates a [NumberedRationalFunctionSpace] over a received ring. + */ +public fun > A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace = + NumberedRationalFunctionSpace(this) + +/** + * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.numberedRationalFunctionSpace(block: NumberedRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return NumberedRationalFunctionSpace(this).block() +} + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { + NumberedPolynomial( + buildMap, Double>(coefficients.size) { + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * substitution.pow(deg.toInt()) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap, C>(coefficients.size) { + for ((degs, c) in coefficients) { + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = + ring.numberedPolynomialSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + acc + args.entries.fold(NumberedPolynomial(mapOf(newDegs to c))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() + acc + args.entries.fold(NumberedRationalFunction(NumberedPolynomial(mapOf(newDegs to c)))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substitute(args: Map): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substitute(args: Buffer): NumberedPolynomial = Double.algebra { + val lastSubstitutionVariable = args.size - 1 + NumberedPolynomial( + buildMap(coefficients.size) { + for ((degs, c) in coefficients) { + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * args[variable].pow(deg.toInt()) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer): NumberedPolynomial = ring { + val lastSubstitutionVariable = args.size - 1 + NumberedPolynomial( + buildMap, C>(coefficients.size) { + for ((degs, c) in coefficients) { + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + val newC = (0..min(lastDegsIndex, lastSubstitutionVariable)).fold(c) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + if (newDegs !in this) this[newDegs] = newC + else this[newDegs] = this[newDegs]!! + newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer>) : NumberedPolynomial = + ring.numberedPolynomialSpace { + val lastSubstitutionVariable = args.size - 1 + coefficients.entries.fold(zero) { acc, (degs, c) -> + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + acc + (0..min(lastDegsIndex, lastSubstitutionVariable)) + .fold(NumberedPolynomial(mapOf(newDegs to c))) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + val lastSubstitutionVariable = args.size - 1 + coefficients.entries.fold(zero) { acc, (degs, c) -> + val lastDegsIndex = degs.lastIndex + val newDegs = + if (lastDegsIndex <= lastSubstitutionVariable) emptyList() + else degs.toMutableList().apply { + for (i in 0..lastSubstitutionVariable) this[i] = 0u + } + acc + (0..min(lastDegsIndex, lastSubstitutionVariable)) + .fold(NumberedRationalFunction(NumberedPolynomial(mapOf(newDegs to c)))) { product, variable -> + val deg = degs[variable] + if (deg == 0u) product else product * power(args[variable], deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substitute(args: Buffer): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer): NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = + ring.numberedRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun NumberedPolynomial.substituteFully(args: Buffer): Double = Double.algebra { + val lastSubstitutionVariable = args.size - 1 + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + coefficients.entries.fold(.0) { acc, (degs, c) -> + acc + degs.foldIndexed(c) { variable, product, deg -> + if (deg == 0u) product else product * args[variable].pow(deg.toInt()) + } + } +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun NumberedPolynomial.substituteFully(ring: Ring, args: Buffer): C = ring { + val lastSubstitutionVariable = args.size - 1 + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + coefficients.entries.fold(zero) { acc, (degs, c) -> + acc + degs.foldIndexed(c) { variable, product, deg -> + if (deg == 0u) product else product * power(args[variable], deg) + } + } +} + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun NumberedRationalFunction.substituteFully(args: Buffer): Double = + numerator.substituteFully(args) / denominator.substituteFully(args) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun NumberedRationalFunction.substituteFully(ring: Field, args: Buffer): C = ring { + numerator.substituteFully(ring, args) / denominator.substituteFully(ring, args) +} + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfConstantOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfPolynomialOver(ring: A): (Buffer>) -> NumberedPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > NumberedPolynomial.asFunctionOfRationalFunctionOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfConstantOver(ring: A): (Buffer) -> C = { substituteFully(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfPolynomialOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > NumberedRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (Buffer>) -> NumberedRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.derivativeWithRespectTo( + ring: A, + variable: Int, +): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg > 0u -> deg - 1u + else -> return@forEach + } + }.cleanUp(), + multiplyByDoubling(c, degs[variable]) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + ring: A, + variable: Int, + order: UInt +): NumberedPolynomial = ring { + if (order == 0u) return this@nthDerivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > variable) return@forEach + put( + degs.mapIndexed { index, deg -> + when { + index != variable -> deg + deg >= order -> deg - order + else -> return@forEach + } + }.cleanUp(), + degs[variable].let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthDerivativeWithRespectTo( + ring: A, + variablesAndOrders: Map, +): NumberedPolynomial = ring { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.size > maxRespectedVariable) return@forEach + put( + degs.mapIndexed { index, deg -> + if (index !in filteredVariablesAndOrders) return@mapIndexed deg + val order = filteredVariablesAndOrders[index]!! + if (deg >= order) deg - order else return@forEach + }.cleanUp(), + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.antiderivativeWithRespectTo( + ring: A, + variable: Int, +): NumberedPolynomial = ring { + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, + c / multiplyByDoubling(one, degs[variable]) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + ring: A, + variable: Int, + order: UInt +): NumberedPolynomial = ring { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + 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 / multiplyByDoubling(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > NumberedPolynomial.nthAntiderivativeWithRespectTo( + ring: A, + variablesAndOrders: Map, +): NumberedPolynomial = ring { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + val maxRespectedVariable = filteredVariablesAndOrders.keys.maxOrNull()!! + NumberedPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + put( + List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index].let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + } + } + ) + } + } + ) +} \ No newline at end of file From b5031121ce9ef7ea0c0aae3796da8e736074a083 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 14 Jun 2022 19:31:13 +0300 Subject: [PATCH 087/174] up build tools --- gradle.properties | 2 +- .../kotlin/space/kscience/kmath/geometry/RotationTest.kt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9cdd7801c..5202289fa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,4 +12,4 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.11.6-kotlin-1.7.0 +toolsVersion=0.11.7-kotlin-1.7.0 diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt index ca7226fb6..abe26d398 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.geometry import space.kscience.kmath.complex.Quaternion import space.kscience.kmath.testutils.assertBufferEquals +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals @@ -24,6 +25,7 @@ class RotationTest { } @Test + @Ignore fun rotationConversion() { val q = Quaternion(1.0, 2.0, -3.0, 4.0) From a1267d84ac43ca18d543c44c81514a73f990d50c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 14 Jun 2022 20:58:13 +0300 Subject: [PATCH 088/174] Fix quaternion rotation tests --- .../kscience/kmath/complex/Quaternion.kt | 2 + .../space/kscience/kmath/nd/Structure2D.kt | 4 ++ .../kscience/kmath/geometry/rotations3D.kt | 60 ++++++++++++------- .../kscience/kmath/geometry/RotationTest.kt | 10 ++-- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 359b66b20..0305bfc88 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -117,6 +117,8 @@ public val Quaternion.reciprocal: Quaternion return Quaternion(w / norm2, -x / norm2, -y / norm2, -z / norm2) } +public fun Quaternion.normalized(): Quaternion = with(QuaternionField){ this@normalized / norm(this@normalized) } + /** * A field of [Quaternion]. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index cf8559869..a2fd83474 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -138,6 +138,10 @@ private class MutableStructure2DWrapper(val structure: MutableStructureND) override fun equals(other: Any?): Boolean = false override fun hashCode(): Int = 0 + + override fun toString(): String { + return StructureND.toString(structure) + } } /** diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt index 374315610..67c3666ed 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt @@ -14,7 +14,6 @@ import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.matrix import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke import kotlin.math.pow import kotlin.math.sqrt @@ -33,9 +32,9 @@ public val Quaternion.vector: Vector3D val sint2 = sqrt(1 - w * w) return object : Vector3D { - override val x: Double get() = this@vector.x/sint2 - override val y: Double get() = this@vector.y/sint2 - override val z: Double get() = this@vector.z/sint2 + override val x: Double get() = this@vector.x / sint2 + override val y: Double get() = this@vector.y / sint2 + override val z: Double get() = this@vector.z / sint2 override fun toString(): String = listOf(x, y, z).toString() } } @@ -75,26 +74,43 @@ public fun Quaternion.toRotationMatrix( } /** - * taken from https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf + * taken from https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ */ public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix): Quaternion { - val t: Double - val q = if (matrix[2, 2] < 0) { - if (matrix[0, 0] > matrix[1, 1]) { - t = 1 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2] - Quaternion(t, matrix[0, 1] + matrix[1, 0], matrix[2, 0] + matrix[0, 2], matrix[1, 2] - matrix[2, 1]) - } else { - t = 1 - matrix[0, 0] + matrix[1, 1] - matrix[2, 2] - Quaternion(matrix[0, 1] + matrix[1, 0], t, matrix[1, 2] + matrix[2, 1], matrix[2, 0] - matrix[0, 2]) - } + require(matrix.colNum == 3 && matrix.rowNum == 3) { "Rotation matrix should be 3x3 but is ${matrix.rowNum}x${matrix.colNum}" } + val trace = matrix[0, 0] + matrix[1, 1] + matrix[2, 2] + + return if (trace > 0) { + val s = sqrt(trace + 1.0) * 2 // S=4*qw + Quaternion( + w = 0.25 * s, + x = (matrix[2, 1] - matrix[1, 2]) / s, + y = (matrix[0, 2] - matrix[2, 0]) / s, + z = (matrix[1, 0] - matrix[0, 1]) / s, + ) + } else if ((matrix[0, 0] > matrix[1, 1]) && (matrix[0, 0] > matrix[2, 2])) { + val s = sqrt(1.0 + matrix[0, 0] - matrix[1, 1] - matrix[2, 2]) * 2 // S=4*qx + Quaternion( + w = (matrix[2, 1] - matrix[1, 2]) / s, + x = 0.25 * s, + y = (matrix[0, 1] + matrix[1, 0]) / s, + z = (matrix[0, 2] + matrix[2, 0]) / s, + ) + } else if (matrix[1, 1] > matrix[2, 2]) { + val s = sqrt(1.0 + matrix[1, 1] - matrix[0, 0] - matrix[2, 2]) * 2 // S=4*qy + Quaternion( + w = (matrix[0, 2] - matrix[2, 0]) / s, + x = (matrix[0, 1] + matrix[1, 0]) / s, + y = 0.25 * s, + z = (matrix[1, 2] + matrix[2, 1]) / s, + ) } else { - if (matrix[0, 0] < -matrix[1, 1]) { - t = 1 - matrix[0, 0] - matrix[1, 1] + matrix[2, 2] - Quaternion(matrix[2, 0] + matrix[0, 2], matrix[1, 2] + matrix[2, 1], t, matrix[0, 1] - matrix[1, 0]) - } else { - t = 1 + matrix[0, 0] + matrix[1, 1] + matrix[2, 2] - Quaternion(matrix[1, 2] - matrix[2, 1], matrix[2, 0] - matrix[0, 2], matrix[0, 1] - matrix[1, 0], t) - } + val s = sqrt(1.0 + matrix[2, 2] - matrix[0, 0] - matrix[1, 1]) * 2 // S=4*qz + Quaternion( + w = (matrix[1, 0] - matrix[0, 1]) / s, + x = (matrix[0, 2] + matrix[2, 0]) / s, + y = (matrix[1, 2] + matrix[2, 1]) / s, + z = 0.25 * s, + ) } - return QuaternionField.invoke { q * (0.5 / sqrt(t)) } } \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt index abe26d398..89b69d0f2 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -6,17 +6,16 @@ package space.kscience.kmath.geometry import space.kscience.kmath.complex.Quaternion +import space.kscience.kmath.complex.normalized import space.kscience.kmath.testutils.assertBufferEquals -import kotlin.test.Ignore import kotlin.test.Test -import kotlin.test.assertEquals class RotationTest { @Test fun rotations() = with(Euclidean3DSpace) { val vector = Vector3D(1.0, 1.0, 1.0) - val q = Quaternion(1.0, 2.0, -3.0, 4.0) + val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() val rotatedByQ = rotate(vector, q) val matrix = q.toRotationMatrix() val rotatedByM = rotate(vector,matrix) @@ -25,13 +24,12 @@ class RotationTest { } @Test - @Ignore fun rotationConversion() { - val q = Quaternion(1.0, 2.0, -3.0, 4.0) + val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() val matrix = q.toRotationMatrix() - assertEquals(q, Quaternion.fromRotationMatrix(matrix)) + assertBufferEquals(q, Quaternion.fromRotationMatrix(matrix)) } } \ No newline at end of file From b5a94923b574bb840214fde3e1af1875c64777ef Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 17 Jun 2022 01:53:40 +0300 Subject: [PATCH 089/174] Fixed problems with JVM names. Exposed internal NumberedPolynomial constructor with opt-in condition. Added and upgraded tests. Fixed small bugs (mistakes). Upgraded arithmetic operations a bit. --- .../kmath/functions/ListPolynomial.kt | 60 +- .../kmath/functions/NumberedPolynomial.kt | 60 +- .../functions/NumberedRationalFunction.kt | 12 +- .../space/kscience/kmath/functions/misc.kt | 21 +- .../kmath/functions/numberedConstructors.kt | 79 +- .../kscience/kmath/functions/numberedUtil.kt | 2 +- .../kmath/functions/ListPolynomialTest.kt | 94 +- .../functions/NumberedConstructorsTest.kt | 111 ++ .../kmath/functions/NumberedPolynomialTest.kt | 1368 +++++++++++++++++ .../kscience/kmath/test/misc/IntModulo.kt | 6 +- 10 files changed, 1714 insertions(+), 99 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 42e3f7301..b3f1eb8f7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -100,14 +100,17 @@ public open class ListPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - if (other == 0) zero - else ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) + when (other) { + 0 -> zero + 1 -> this + else -> ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -133,34 +136,39 @@ public open class ListPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + if (this@minus == 0) { + indices.forEach { this[it] = -this[it] } + } else { + (1..lastIndex).forEach { this[it] = -this[it] } val result = this@minus - getOrElse(0) { constantZero } - if(size == 0) add(result) + if (size == 0) add(result) else this[0] = result } - ) + } + ) /** * Returns product of the integer represented as a polynomial and the polynomial. * * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - if (this == 0) zero - else ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) + when (this) { + 0 -> zero + 1 -> other + else -> ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } /** * Converts the integer [value] to polynomial. @@ -192,7 +200,7 @@ public open class ListPolynomialSpace>( else ListPolynomial( toMutableList() .apply { - forEachIndexed { index, c -> if (index != 0) this[index] = -c } + (1 .. lastIndex).forEach { this[it] = -this[it] } val result = if (size == 0) this@minus else this@minus - get(0) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 9304e66da..02a3af683 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -98,14 +98,17 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun NumberedPolynomial.times(other: Int): NumberedPolynomial = - if (other == 0) zero - else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) + when (other) { + 0 -> zero + 1 -> this + else -> NumberedPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -130,16 +133,20 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) other - else - NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { + NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + if (this@minus == 0) { + forEach { (key, value) -> this[key] = -value } + } else { + forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } + val degs = emptyList() this[degs] = this@minus - getOrElse(degs) { constantZero } } + } ) /** * Returns product of the integer represented as a polynomial and the polynomial. @@ -147,14 +154,17 @@ public class NumberedPolynomialSpace>( * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: NumberedPolynomial): NumberedPolynomial = - if (this == 0) zero - else NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) + when (this) { + 0 -> zero + 1 -> other + else -> NumberedPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + } /** * Converts the integer [value] to polynomial. @@ -185,7 +195,7 @@ public class NumberedPolynomialSpace>( else NumberedPolynomialAsIs( toMutableMap() .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c } val degs = emptyList() @@ -266,7 +276,7 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } ) @@ -276,7 +286,7 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index a2986879d..92f507735 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -119,11 +119,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. @@ -134,11 +136,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] polynomial. @@ -149,11 +153,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. @@ -164,11 +170,13 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided polynomial [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided rational function [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided constant [arguments] into [this] polynomial. @@ -222,7 +230,7 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided [arguments] into [this] polynomial. */ @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") + @JvmName("invokeRationalFunction") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. @@ -234,6 +242,6 @@ public class NumberedRationalFunctionSpace> ( * Substitutes provided [arguments] into [this] rational function. */ @Suppress("NOTHING_TO_INLINE") - @JvmName("invokePolynomial") + @JvmName("invokeRationalFunction") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index 8b6fac39e..7d6fc84fa 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -6,8 +6,27 @@ package space.kscience.kmath.functions +/** + * Marks operations that are going to be optimized reimplementations by reducing number of boxings but currently is + * under development and is not stable (or even ready to use). + */ @RequiresOptIn( message = "It's copy of operation with optimized boxing. It's currently unstable.", level = RequiresOptIn.Level.ERROR ) -internal annotation class UnstablePolynomialBoxingOptimization \ No newline at end of file +internal annotation class UnstablePolynomialBoxingOptimization + +/** + * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to + * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is + * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. + */ +@RequiresOptIn( + message = "This declaration gives access to delicate internal structure of polynomials. " + + "It allows to optimize performance by skipping unnecessary arguments check. " + + "But at the same time makes it easy to make a mistake " + + "that will cause wrong computation result or even runtime error. " + + "Make sure you fully read and understand documentation.", + level = RequiresOptIn.Level.WARNING +) +internal annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 05fff3472..37d5d7fb6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -37,6 +37,38 @@ internal inline fun NumberedPolynomialAsIs(pairs: Collection @PublishedApi internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) +/** + * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) + +/** + * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + +/** + * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@Suppress("FunctionName", "NOTHING_TO_INLINE") +@DelicatePolynomialAPI +public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) + /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. * @@ -245,11 +277,12 @@ public class NumberedPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Int.inPowerOf(deg: UInt) { - if (this > signature.lastIndex) { - signature.addAll(List(this - signature.lastIndex - 1) { 0u }) + val index = this - 1 + if (index > signature.lastIndex) { + signature.addAll(List(index - signature.lastIndex - 1) { 0u }) signature.add(deg) } else { - signature[this] += deg + signature[index] += deg } } /** @@ -334,22 +367,26 @@ public class NumberedPolynomialBuilder( // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available -/** - * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. - * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as - * ``` - * Int.algebra { - * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 - * } - * } - * ``` - */ -@UnstableKMathAPI -@Suppress("FunctionName") -public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +///** +// * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. +// * +// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * ``` +// * Int.algebra { +// * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { +// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + +// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * } +// * } +// * ``` +// */ +// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: +// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. +// 2. Union types are implemented. Then all three functions should be rewritten +// as one with single union type as a (context) receiver. +//@UnstableKMathAPI +//@Suppress("FunctionName") +//public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * @@ -365,7 +402,7 @@ public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, */ @UnstableKMathAPI @Suppress("FunctionName") -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * @@ -381,7 +418,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi */ @UnstableKMathAPI @Suppress("FunctionName") -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 484cd11e3..fca9a8ab8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -86,7 +86,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map /** * Substitutes provided arguments [args] into [this] polynomial. - */ // TODO: To optimize boxing + */ // TODO: To optimize boxing @JvmName("substitutePolynomial") public fun NumberedPolynomial.substitute(ring: Ring, args: Map>) : NumberedPolynomial = ring.numberedPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index c9950fac5..c4a7cc564 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.test.misc.* @@ -28,25 +30,32 @@ class ListPolynomialTest { ListPolynomial(Rational(-2)) + 2, "test 3" ) - assertEquals( - ListPolynomial(), - ListPolynomial() + 0, + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 + 0, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) assertEquals( ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(-1)), ListPolynomial(Rational(-2)) + 1, - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(2)), ListPolynomial() + 2, - "test 7" + "test 8" ) } } @@ -68,25 +77,32 @@ class ListPolynomialTest { ListPolynomial(Rational(2)) - 2, "test 3" ) - assertEquals( - ListPolynomial(), - ListPolynomial() - 0, + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 - 0, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertEquals( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) assertEquals( ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(1)), ListPolynomial(Rational(2)) - 1, - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(-2)), ListPolynomial() - 2, - "test 7" + "test 8" ) } } @@ -103,6 +119,17 @@ class ListPolynomialTest { ListPolynomial(7, 0, 49, 21, 14) * 15, "test 2" ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) } } @Test @@ -123,25 +150,32 @@ class ListPolynomialTest { 2 + ListPolynomial(Rational(-2)), "test 3" ) - assertEquals( - ListPolynomial(), - 0 + ListPolynomial(), + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + 0 + polynomial_4, "test 4" ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) assertEquals( ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(-1)), 1 + ListPolynomial(Rational(-2)), - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(2)), 2 + ListPolynomial(), - "test 7" + "test 8" ) } } @@ -163,25 +197,30 @@ class ListPolynomialTest { -2 - ListPolynomial(Rational(-2)), "test 3" ) + assertEquals( + ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), + 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + "test 4" + ) assertEquals( ListPolynomial(), 0 - ListPolynomial(), - "test 4" + "test 5" ) assertEquals( ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" + "test 6" ) assertEquals( ListPolynomial(Rational(1)), -1 - ListPolynomial(Rational(-2)), - "test 6" + "test 7" ) assertEquals( ListPolynomial(Rational(-2)), -2 - ListPolynomial(), - "test 7" + "test 8" ) } } @@ -198,6 +237,17 @@ class ListPolynomialTest { 15 * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) } } @Test diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt new file mode 100644 index 000000000..14493aaae --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -0,0 +1,111 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NumberedConstructorsTest { + @Test + @UnstableKMathAPI + fun testBuilder() { + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } + (-6) { 2 inPowerOf 1u } + } + }, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { } + (-6) { } + } + }, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 inPowerOf 1u; 1 inPowerOf 1u } + (-6) { 1 inPowerOf 2u } + } + }, + "test 3" + ) + } + @Test + @UnstableKMathAPI + fun testFabric() { + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra { + NumberedPolynomial( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ) + }, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u, 0u, 3u) to 5, + listOf(0u, 1u) to -6, + ), + Int.algebra { + NumberedPolynomial( + listOf(2u, 0u, 3u, 0u) to 5, + listOf(0u, 1u, 0u, 0u) to -6, + ) + }, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to -1, + ), + Int.algebra { + NumberedPolynomial( + listOf(0u) to 5, + listOf(0u, 0u) to -6, + ) + }, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0, + ), + Int.algebra { + NumberedPolynomial( + listOf(0u) to 5, + listOf(0u, 0u) to -5, + ) + }, + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt new file mode 100644 index 000000000..537e3b85d --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -0,0 +1,1368 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.test.misc.* +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame + + +@UnstableKMathAPI +class NumberedPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + -3, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + polynomial_6 + 0, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + polynomial_7 + 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - 3, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + polynomial_6 - 0, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + polynomial_7 - 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * 27, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + } * 15, + "test 2" + ) + val polynomial = NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + -3 + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + val polynomial_5 = NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + val polynomial_6 = NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_6, + 0 + polynomial_6, + "test 6" + ) + val polynomial_7 = NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + assertSame( + polynomial_7, + 0 + polynomial_7, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(3, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 3 - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + 0 - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + 27 * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + 15 * NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + }, + "test 2" + ) + val polynomial = NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(-3), + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } + Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(3), + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + } - Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(27), + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + } * m(15), + "test 2" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(0), + "test 3" + ) + assertEquals( + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + } * m(1), + "test 4" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-3, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(-3) + NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + Rational(0) + NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(5, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(3, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 1) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(3) - NumberedPolynomial { + Rational(27, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 4" + ) + assertEquals( + NumberedPolynomial { + Rational(22, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(-22, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 5" + ) + assertEquals( + NumberedPolynomial { + Rational(0, 9) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(0, 9) with {} + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 6" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(8, 9) with { 1 pow 3u } + Rational(8, 7) with { 2 pow 4u } + }, + Rational(0) - NumberedPolynomial { + Rational(-8, 9) with { 1 pow 3u } + Rational(-8, 7) with { 2 pow 4u } + }, + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + m(34) with {} + m(2) with { 1 pow 3u } + m(1) with { 2 pow 1u } + m(20) with { 1 pow 1u } + m(2) with { 3 pow 2u } + }, + m(27) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + m(15) * NumberedPolynomial { + m(7) with {} + m(0) with { 1 pow 3u } + m(49) with { 2 pow 1u } + m(21) with { 1 pow 1u } + m(14) with { 3 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + m(0) with {} + m(0) with { 1 pow 3u } + m(0) with { 2 pow 1u } + m(0) with { 1 pow 1u } + m(0) with { 3 pow 2u } + }, + m(0) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + m(1) * NumberedPolynomial { + m(22) with {} + m(26) with { 1 pow 3u } + m(13) with { 2 pow 1u } + m(15) with { 1 pow 1u } + m(26) with { 3 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-5, 9) with { 1 pow 5u } + Rational(8, 9) with {} + Rational(8, 7) with { 7 pow 13u } + }, + -NumberedPolynomial { + Rational(5, 9) with { 1 pow 5u } + Rational(-8, 9) with {} + Rational(-8, 7) with { 7 pow 13u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-5, 9) with { 3 pow 7u } + Rational(8, 9) with {} + Rational(8, 7) with { 1 pow 3u } + Rational(0) with { 2 pow 4u } + Rational(0) with { 1 pow 5u } + }, + -NumberedPolynomial { + Rational(5, 9) with { 3 pow 7u } + Rational(-8, 9) with {} + Rational(-8, 7) with { 1 pow 3u } + Rational(0) with { 2 pow 4u } + Rational(0) with { 1 pow 5u } + }, + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(146, 63) with { 2 pow 1u } + Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } + Rational(61, 15) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(7, 9) with { 2 pow 2u } + Rational(5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(7, 9) with { 2 pow 2u } + Rational(5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(-20, 7) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(0) with { 1 pow 1u } + Rational(0) with { 1 pow 2u } + Rational(0) with { 2 pow 1u } + Rational(0) with { 1 pow 1u; 2 pow 1u } + Rational(0) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } + NumberedPolynomial { + Rational(-6, 4) with {} + Rational(2, 6) with { 1 pow 1u } + Rational(-10, 6) with { 1 pow 2u } + Rational(-17, 7) with { 2 pow 1u } + Rational(7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(-12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(-12, 7) with { 2 pow 2u } + Rational(10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(-9, 8) with { 1 pow 2u; 2 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.numberedPolynomialSpace { + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(146, 63) with { 2 pow 1u } + Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } + Rational(61, 15) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(-7, 9) with { 2 pow 2u } + Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 1" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(157, 63) with { 2 pow 2u } + Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } + Rational(11, 24) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(-7, 9) with { 2 pow 2u } + Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } + Rational(2, 3) with { 1 pow 2u; 2 pow 2u } + }, + "test 2" + ) + assertEquals( + NumberedPolynomial { + Rational(-17, 2) with {} + Rational(-1, 3) with { 1 pow 1u } + Rational(-25, 21) with { 1 pow 2u } + Rational(-1, 9) with { 2 pow 1u } + Rational(2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(20, 2) with {} + Rational(0, 9) with { 1 pow 1u } + Rational(20, 7) with { 1 pow 2u } + Rational(1, 9) with { 2 pow 1u } + Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } + Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + "test 3" + ) + assertEquals( + NumberedPolynomial { + Rational(0) with {} + Rational(0) with { 1 pow 1u } + Rational(0) with { 1 pow 2u } + Rational(0) with { 2 pow 1u } + Rational(0) with { 1 pow 1u; 2 pow 1u } + Rational(0) with { 1 pow 2u; 2 pow 1u } + Rational(0) with { 2 pow 2u } + Rational(0) with { 1 pow 1u; 2 pow 2u } + Rational(0) with { 1 pow 2u; 2 pow 2u } + }, + NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + } - NumberedPolynomial { + Rational(6, 4) with {} + Rational(-2, 6) with { 1 pow 1u } + Rational(10, 6) with { 1 pow 2u } + Rational(17, 7) with { 2 pow 1u } + Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } + Rational(12, 5) with { 1 pow 2u; 2 pow 1u } + Rational(12, 7) with { 2 pow 2u } + Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } + Rational(9, 8) with { 1 pow 2u; 2 pow 2u } + }, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).numberedPolynomialSpace { + // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr + assertEquals( + NumberedPolynomial { + m(1) with { 1 pow 3u } + m(1) with { 2 pow 3u } + m(1) with { 3 pow 3u } + m(0) with { 1 pow 1u; 2 pow 2u } + m(0) with { 2 pow 1u; 3 pow 2u } + m(0) with { 3 pow 1u; 1 pow 2u } + m(0) with { 1 pow 1u; 3 pow 2u } + m(0) with { 2 pow 1u; 1 pow 2u } + m(0) with { 3 pow 1u; 2 pow 2u } + m(-3) with { 1 pow 1u; 2 pow 1u; 3 pow 1u } + }, + NumberedPolynomial { + m(1) with { 1 pow 1u } + m(1) with { 2 pow 1u } + m(1) with { 3 pow 1u } + } * NumberedPolynomial { + m(1) with { 1 pow 2u } + m(1) with { 2 pow 2u } + m(1) with { 3 pow 2u } + m(-1) with { 1 pow 1u; 2 pow 1u } + m(-1) with { 2 pow 1u; 3 pow 1u } + m(-1) with { 3 pow 1u; 1 pow 1u } + }, + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + NumberedPolynomial { + m(0) with { 1 pow 2u } + m(0) with { 2 pow 2u } + m(0) with { 3 pow 2u } + m(0) with { 1 pow 1u; 2 pow 1u } + m(0) with { 2 pow 1u; 3 pow 1u } + m(0) with { 3 pow 1u; 1 pow 1u } + }, + NumberedPolynomial { + m(5) with { 1 pow 1u } + m(-25) with { 2 pow 1u } + m(10) with { 3 pow 1u } + } * NumberedPolynomial { + m(21) with { 1 pow 1u } + m(14) with { 2 pow 1u } + m(-7) with { 3 pow 1u } + }, + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index 89764db46..afd2b5add 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing import space.kscience.kmath.operations.Ring @@ -135,4 +136,7 @@ class IntModuloRing : Ring { fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) \ No newline at end of file + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus) +fun PolynomialSpaceOverRing.m(arg: Int) = IntModulo(arg, ring.modulus) \ No newline at end of file From 1ea336b70ea5a0f44722071b29193215c1460b14 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 17 Jun 2022 22:07:54 +0300 Subject: [PATCH 090/174] Added some test of NumberedPolynomial utilities. --- .../functions/NumberedPolynomialUtilTest.kt | 293 ++++++++++++++++++ .../kscience/kmath/test/misc/assertion.kt | 14 + 2 files changed, 307 insertions(+) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt new file mode 100644 index 000000000..ecad6198e --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -0,0 +1,293 @@ +/* + * 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.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertContentEquals +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NumberedPolynomialUtilTest { + @Test + fun test_substitute_Double_Map() { + assertContentEquals( + mapOf(emptyList() to 0.0), + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substitute(mapOf( + 0 to 1.0 + )).coefficients, + 0.001, + "test 1" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf()).coefficients, + 0.001, + "test 2" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.0 + )).coefficients, + 0.001, + "test 3" + ) + assertContentEquals( + mapOf( + listOf() to 1.433510890645169, + listOf(1u) to 0.6264844682514724, + listOf(2u) to 0.8405727903771333, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 1 to 0.8400458576651112 + )).coefficients, + 0.001, + "test 4" + ) + assertContentEquals( + mapOf( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.4846192734143442, + 1 to 0.8400458576651112, + )).coefficients, + 0.001, + "test 5" + ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 6" + ) + } + @Test + fun test_substitute_Constant() { + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to Rational(1) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + )), + "test 2" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(47639065216, 2562890625) + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + )), + "test 3" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 4" + ) + } + @Test + fun test_substitute_Polynomial() { + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(0u, 1u) to Rational(-92, 21), + listOf(0u, 2u) to Rational(-2627, 2352), + listOf(0u, 3u) to Rational(4565, 3136), + listOf(0u, 4u) to Rational(605, 1568), + listOf(1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(1445, 21), + listOf(1u, 2u) to Rational(-13145, 392), + listOf(1u, 3u) to Rational(-3025, 196), + listOf(2u) to Rational(175, 3), + listOf(2u, 1u) to Rational(2475, 28), + listOf(2u, 2u) to Rational(15125, 98), + listOf(3u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf(1u) to Rational(-5, 1), + listOf(0u, 1u) to Rational(2, 8), + ), + 1 to NumberedPolynomialAsIs( + listOf(1u) to Rational(0, 5), + listOf(0u, 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt new file mode 100644 index 000000000..52ecf416a --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -0,0 +1,14 @@ +/* + * 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.test.assertEquals + + +fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { + assertEquals(expected.keys, actual.keys, message) + for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) +} \ No newline at end of file From 680d23ddcb0c3e11ea779146f3d2ced2d8c741be Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 18 Jun 2022 01:25:14 +0300 Subject: [PATCH 091/174] Last sift. Cleaned up labeled structures. --- .../kmath/functions/LabeledPolynomial.kt | 621 ++++++++++++++++++ .../functions/LabeledRationalFunction.kt | 96 +++ .../kmath/functions/ListPolynomial.kt | 2 +- .../kmath/functions/NumberedPolynomial.kt | 11 +- .../kmath/functions/labeledConstructors.kt | 518 +++++++++++++++ .../kscience/kmath/functions/labeledUtil.kt | 327 +++++++++ .../kmath/functions/numberedConstructors.kt | 40 +- .../kscience/kmath/functions/numberedUtil.kt | 18 +- 8 files changed, 1584 insertions(+), 49 deletions(-) create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt new file mode 100644 index 000000000..b0c54502d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -0,0 +1,621 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName +import kotlin.math.max + + +/** + * Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [Map] that + * associates variables (of type [Symbol]) with their degree. + * + * @param C the type of constants. + */ +public data class LabeledPolynomial +@PublishedApi +internal constructor( + /** + * Map that contains coefficients of the polynomial. + * + * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the + * coefficient `a` and the key is a map that associates variables in the monomial with their degree in the monomial. + * For example, coefficients of a polynomial `5 a^2 c^3 - 6 b` can be represented as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6) + * ) + * ``` + * and also as + * ``` + * mapOf( + * mapOf( + * a to 2, + * c to 3 + * ) to 5, + * mapOf( + * b to 1 + * ) to (-6), + * mapOf( + * b to 1, + * c to 1 + * ) to 0 + * ) + * ``` + * where `a`, `b` and `c` are corresponding [Symbol] objects. + */ + public val coefficients: Map, C> +) : Polynomial { + override fun toString(): String = "LabeledPolynomial$coefficients" +} + +/** + * Arithmetic context for multivariate polynomials with coefficients stored as a [Map] and terms' signatures stored as a + * [Map] constructed with the provided [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class LabeledPolynomialSpace>( + public override val ring: A, +) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.plus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + emptyMap() to constantOne * other, + )) + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.minus(other: Int): LabeledPolynomial = + if (other == 0) LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to constantOne * other, + )) + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + public override operator fun Symbol.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne * other, + )) + + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.plus(other: Symbol): LabeledPolynomial = + if (this == 0) LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + emptyMap() to constantOne * this@plus, + )) + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.minus(other: Symbol): LabeledPolynomial = + if (this == 0) LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + emptyMap() to constantOne * this@minus, + )) + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun Int.times(other: Symbol): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne * this@times, + )) + + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = + if (other == 0) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = + if (other == 0) this + else with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to (-other).asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = + if (other == 0) zero + else LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) other + else with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } + + val degs = emptyMap() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = + if (this == 0) zero + else LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Converts the integer [value] to polynomial. + */ + public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) + + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.plus(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@plus to 1U) to constantOne, + emptyMap() to other, + )) + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.minus(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@minus to 1U) to -constantOne, + emptyMap() to other, + )) + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + public override operator fun Symbol.times(other: C): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this@times to 1U) to other, + )) + + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.plus(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to constantOne, + emptyMap() to this@plus, + )) + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.minus(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to -constantOne, + emptyMap() to this@minus, + )) + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + public override operator fun C.times(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(other to 1U) to this@times, + )) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = this@plus + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + this[degs] = this@minus - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } + other + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } + + val degs = emptyMap() + + this[degs] = getOrElse(degs) { constantZero } - other + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): LabeledPolynomial = + LabeledPolynomial(mapOf(emptyMap() to value)) + + /** + * Represents the variable as a monic monomial. + */ + public override operator fun Symbol.unaryPlus(): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + )) + /** + * Returns negation of representation of the variable as a monic monomial. + */ + public override operator fun Symbol.unaryMinus(): LabeledPolynomial = + LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to -constantOne, + )) + /** + * Returns sum of the variables represented as monic monomials. + */ + public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = + if (this == other) LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne * 2 + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to constantOne, + )) + /** + * Returns difference between the variables represented as monic monomials. + */ + public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = + if (this == other) zero + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U) to constantOne, + mapOf(other to 1U) to -constantOne, + )) + /** + * Returns product of the variables represented as monic monomials. + */ + public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = + if (this == other) LabeledPolynomialAsIs(mapOf( + mapOf(this to 2U) to constantOne + )) + else LabeledPolynomialAsIs(mapOf( + mapOf(this to 1U, other to 1U) to constantOne, + )) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(this@plus to 1U) + + this[degs] = constantOne + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = + with(other.coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(this@minus to 1U) + + forEach { (degs, c) -> if(degs != degs) this[degs] = -c } + + this[degs] = constantOne - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ + public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + other.coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + ) + + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + this[degs] = constantOne + getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = + with(coefficients) { + if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + else LabeledPolynomialAsIs( + toMutableMap() + .apply { + val degs = mapOf(other to 1U) + + this[degs] = constantOne - getOrElse(degs) { constantZero } + } + ) + } + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ + public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients + .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + ) + + /** + * Returns negation of the polynomial. + */ + override fun LabeledPolynomial.unaryMinus(): LabeledPolynomial = + LabeledPolynomialAsIs( + coefficients.mapValues { -it.value } + ) + /** + * Returns sum of the polynomials. + */ + override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } + } + ) + /** + * Returns difference of the polynomials. + */ + override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size + other.coefficients.size) { + other.coefficients.mapValuesTo(this) { it.value } + other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + } + ) + /** + * Returns product of the polynomials. + */ + override operator fun LabeledPolynomial.times(other: LabeledPolynomial): LabeledPolynomial = + LabeledPolynomialAsIs( + buildMap(coefficients.size * other.coefficients.size) { + for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { + val degs = degs1.toMutableMap() + degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val c = c1 * c2 + this[degs] = if (degs in this) this[degs]!! + c else c + } + } + ) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantZero)) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + override val LabeledPolynomial.degree: Int + get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.values.sum().toInt() } ?: -1 + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public override val LabeledPolynomial.degrees: Map + get() = + buildMap { + coefficients.entries.forEach { (degs, _) -> + degs.mapValuesTo(this) { (variable, deg) -> + max(getOrElse(variable) { 0u }, deg) + } + } + } + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public override fun LabeledPolynomial.degreeBy(variable: Symbol): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public override fun LabeledPolynomial.degreeBy(variables: Collection): UInt = + coefficients.entries.maxOfOrNull { (degs, _) -> degs.filterKeys { it in variables }.values.sum() } ?: 0u + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public override val LabeledPolynomial.variables: Set + get() = + buildSet { + coefficients.entries.forEach { (degs, _) -> addAll(degs.keys) } + } + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public override val LabeledPolynomial.countOfVariables: Int get() = variables.size + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledPolynomial.substitute(arguments: Map): LabeledPolynomial = substitute(ring, arguments) + /** + * Substitutes provided arguments [arguments] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledPolynomial.substitute(arguments: Map>) : LabeledPolynomial = substitute(ring, arguments) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt new file mode 100644 index 000000000..03f323813 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -0,0 +1,96 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.operations.Ring +import kotlin.jvm.JvmName + + +/** + * Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s. + */ +public class LabeledRationalFunction( + public override val numerator: LabeledPolynomial, + public override val denominator: LabeledPolynomial +) : RationalFunction> { + override fun toString(): String = "LabeledRationalFunction${numerator.coefficients}/${denominator.coefficients}" +} + +/** + * Arithmetic context for univariate rational functions with numerator and denominator represented as [LabeledPolynomial]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 LabeledRationalFunctionSpace>( + public val ring: A, +) : + MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + C, + Symbol, + LabeledPolynomial, + LabeledRationalFunction, + LabeledPolynomialSpace, + >, + MultivariatePolynomialSpaceOfFractions< + C, + Symbol, + LabeledPolynomial, + LabeledRationalFunction, + >() { + + /** + * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. + */ + override val polynomialRing : LabeledPolynomialSpace = LabeledPolynomialSpace(ring) + /** + * Constructor of rational functions (of type [LabeledRationalFunction]) from numerator and denominator (of type [LabeledPolynomial]). + */ + override fun constructRationalFunction( + numerator: LabeledPolynomial, + denominator: LabeledPolynomial + ): LabeledRationalFunction = + LabeledRationalFunction(numerator, denominator) + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Substitutes provided constant [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] polynomial. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") + public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided constant [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + public inline fun LabeledRationalFunction.substitute(argument: Map): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substitutePolynomial") + public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) + /** + * Substitutes provided rational function [argument] into [this] rational function. + */ + @Suppress("NOTHING_TO_INLINE") + @JvmName("substituteRationalFunction") + public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index b3f1eb8f7..8db93cbb1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -15,7 +15,7 @@ import kotlin.math.min /** * Represents univariate polynomial that stores its coefficients in a [List]. * - * @param coefficients constant is the leftmost coefficient. + * @param C the type of constants. */ public data class ListPolynomial( /** diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 02a3af683..eadeb68ab 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -12,7 +12,7 @@ import kotlin.math.max /** - * Represents univariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. + * Represents multivariate polynomial that stores its coefficients in a [Map] and terms' signatures in a [List]. * * @param C the type of constants. */ @@ -20,10 +20,11 @@ public data class NumberedPolynomial @PublishedApi internal constructor( /** - * Map that contains coefficients of the polynomial. Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as pair - * "key-value" in the map, where the value is the coefficients `a` and the key is a list that associates index of - * every variable in the monomial with multiplicity of the variable occurring in the monomial. For example - * coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * Map that contains coefficients of the polynomial. + * + * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the + * coefficient `a` and the key is a list that associates index of every variable in the monomial with their degree + * in the monomial. For example, coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as * ``` * mapOf( * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt new file mode 100644 index 000000000..47325c4bb --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -0,0 +1,518 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("FunctionName", "NOTHING_TO_INLINE") + +package space.kscience.kmath.functions + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Ring + + +/** + * Returns the same degrees' description of the monomial, but without zero degrees. + */ +internal fun Map.cleanUp() = filterValues { it > 0U } + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + */ +@PublishedApi +internal inline fun LabeledPolynomialAsIs(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. The map is used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * The collections will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". + * The array will be transformed to map with [toMap] and then will be used as is. + * + * **Be sure you read description of [LabeledPolynomial.coefficients]. Otherwise, you may make a mistake that will + * cause wrong computation result or even runtime error.** + */ +@DelicatePolynomialAPI +public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(pairs.toMap()) + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in coefs) { + val key = entry.key.cleanUp() + val value = entry.value + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { + val fixedCoefs = mutableMapOf, C>() + + for (entry in pairs) { + val key = entry.first.cleanUp() + val value = entry.second + fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value + } + + return LabeledPolynomial(fixedCoefs) +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, ::add) +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided coefficients map [coefs]. + * + * [coefs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, ::add) + +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } + +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } +/** + * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". + * + * [pairs] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } + +/** + * Converts [this] constant to [LabeledPolynomial]. + */ +public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to this)) + +///** +//// * Converts [this] variable to [LabeledPolynomial]. +//// */ +//context(A) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to one)) +///** +// * Converts [this] variable to [LabeledPolynomial]. +// */ +//context(LabeledPolynomialSpace) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) +///** +// * Converts [this] variable to [LabeledPolynomial]. +// */ +//context(LabeledRationalFunctionSpace) +//public inline fun > Symbol.asLabeledPolynomial() : LabeledPolynomial = LabeledPolynomial(mapOf(mapOf(this to 1u) to constantOne)) + +/** + * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. + * + * For example, polynomial `5 a^2 c^3 - 6 b` can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 + * } + * } + * ``` + */ +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialConstructorDSL + +/** + * Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. + */ +@UnstableKMathAPI +@LabeledPolynomialConstructorDSL +public class LabeledPolynomialTermSignatureBuilder { + /** + * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. + * Afterward the storage will be used as a resulting signature. + */ + private val signature: MutableMap = LinkedHashMap() + + /** + * Builds the resulting signature. + * + * In fact, it just returns [signature] as regular signature of type `List`. + */ + @PublishedApi + internal fun build(): Map = signature + + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + public infix fun Symbol.inPowerOf(deg: UInt) { + signature[this] = deg + } + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg + /** + * Declares power of [this] variable of degree [deg]. + * + * Declaring another power of the same variable will increase its degree by received degree. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg +} + +/** + * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. + */ +@UnstableKMathAPI +public class LabeledPolynomialBuilder( + /** + * Summation operation that will be used to sum coefficients of monomials of same signatures. + */ + private val add: (C, C) -> C, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int = 0 +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + + /** + * Declares monomial with [this] coefficient and provided [signature]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public infix fun C.with(signature: Map) { + coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + } + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + @Suppress("NOTHING_TO_INLINE") + public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + /** + * Declares monomial with [this] coefficient and signature constructed by [block]. + * + * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such + * coefficients is zero at any moment the monomial won't be removed but will be left as it is. + */ + public inline operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with LabeledPolynomialTermSignatureBuilder().apply(block).build() +} + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +///** +// * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. +// * +// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * ``` +// * Int.algebra { +// * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { +// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + +// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * } +// * } +// * ``` +// */ +// FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: +// 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. +// 2. Union types are implemented. Then all three functions should be rewritten +// as one with single union type as a (context) receiver. +//@UnstableKMathAPI +//public inline fun > A.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +/** + * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +public inline fun > LabeledPolynomialSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. + * + * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * ``` + * Int.algebra { + * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { + * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + + * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * } + * } + * ``` + */ +@UnstableKMathAPI +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) +/** + * Constructs [LabeledRationalFunction] with provided coefficients maps [numeratorCoefficients] and [denominatorCoefficients]. + * + * The maps will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. the maps' keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomial(denominatorCoefficients) + ) + +/** + * Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator. + */ +public fun > A.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, LabeledPolynomial(mapOf(emptyMap() to one))) +/** + * Constructs [LabeledRationalFunction] with provided [numerator] and unit denominator. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numerator: LabeledPolynomial): LabeledRationalFunction = + LabeledRationalFunction(numerator, polynomialOne) + +/** + * Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > LabeledRationalFunctionSpace.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + polynomialOne + ) +/** + * Constructs [LabeledRationalFunction] with provided coefficients map [numeratorCoefficients] for numerator and unit + * denominator. + * + * [numeratorCoefficients] will be "cleaned up": + * 1. Zeros at the ends of terms' signatures (e.g. [numeratorCoefficients]'s keys) will be removed. (See [cleanUp].) + * 1. Terms that happen to have the same signature will be summed up. + * 1. New map will be formed of resulting terms. + */ +public fun > A.LabeledRationalFunction(numeratorCoefficients: Map, C>): LabeledRationalFunction = + LabeledRationalFunction( + LabeledPolynomial(numeratorCoefficients), + LabeledPolynomialAsIs(mapOf(emptyMap() to one)) + ) + +///** +// * Converts [this] constant to [LabeledRationalFunction]. +// */ +//context(A) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(emptyMap() to this)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to one)) +// ) +///** +// * Converts [this] constant to [LabeledRationalFunction]. +// */ +//context(LabeledRationalFunctionSpace) +//public fun > C.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(emptyMap() to this)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) +// ) + +///** +// * Converts [this] variable to [LabeledRationalFunction]. +// */ +//context(A) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to one)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to one)) +// ) +///** +// * Converts [this] variable to [LabeledRationalFunction]. +// */ +//context(LabeledRationalFunctionSpace) +//public fun > Symbol.asLabeledRationalFunction() : LabeledRationalFunction = +// LabeledRationalFunction( +// LabeledPolynomialAsIs(mapOf(mapOf(this to 1u) to constantOne)), +// LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) +// ) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt new file mode 100644 index 000000000..39c781a14 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -0,0 +1,327 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.algebra +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.jvm.JvmName + + +/** + * Creates a [LabeledPolynomialSpace] over a received ring. + */ +public fun > A.labeledPolynomialSpace(): LabeledPolynomialSpace = + LabeledPolynomialSpace(this) + +/** + * Creates a [LabeledPolynomialSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledPolynomialSpace(block: LabeledPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledPolynomialSpace(this).block() +} +/** + * Creates a [LabeledRationalFunctionSpace] over a received ring. + */ +public fun > A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace = + LabeledRationalFunctionSpace(this) + +/** + * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. + */ +public inline fun , R> A.labeledRationalFunctionSpace(block: LabeledRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return LabeledRationalFunctionSpace(this).block() +} + +/** + * Substitutes provided Double arguments [args] into [this] Double polynomial. + */ +public fun LabeledPolynomial.substitute(args: Map): LabeledPolynomial = Double.algebra { + if (coefficients.isEmpty()) return this@substitute + LabeledPolynomial( + buildMap { + coefficients.forEach { (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ +public fun LabeledPolynomial.substitute(ring: Ring, args: Map): LabeledPolynomial = ring { + if (coefficients.isEmpty()) return this@substitute + LabeledPolynomial( + buildMap { + coefficients.forEach { (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + val newC = args.entries.fold(c) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + } + } + ) +} + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substitutePolynomial") +public fun LabeledPolynomial.substitute(ring: Ring, args: Map>) : LabeledPolynomial = + ring.labeledPolynomialSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + acc + args.entries.fold(LabeledPolynomial(mapOf(newDegs to c))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided arguments [args] into [this] polynomial. + */ // TODO: To optimize boxing +@JvmName("substituteRationalFunction") +public fun LabeledPolynomial.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + ring.labeledRationalFunctionSpace { + coefficients.entries.fold(zero) { acc, (degs, c) -> + val newDegs = degs.filterKeys { it !in args } + acc + args.entries.fold(LabeledRationalFunction(LabeledPolynomial(mapOf(newDegs to c)))) { product, (variable, substitution) -> + val deg = degs.getOrElse(variable) { 0u } + if (deg == 0u) product else product * power(substitution, deg) + } + } + } + +/** + * Substitutes provided Double arguments [args] into [this] Double rational function. + */ +public fun LabeledRationalFunction.substitute(args: Map): LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(args), denominator.substitute(args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map): LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize calculation +@JvmName("substitutePolynomial") +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + LabeledRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) + +/** + * Substitutes provided arguments [args] into [this] rational function. + */ // TODO: To optimize calculation +@JvmName("substituteRationalFunction") +public fun LabeledRationalFunction.substitute(ring: Ring, args: Map>) : LabeledRationalFunction = + ring.labeledRationalFunctionSpace { + numerator.substitute(ring, args) / denominator.substitute(ring, args) + } + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.derivativeWithRespectTo( + algebra: A, + variable: Symbol, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (variable !in degs) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > 1u -> put(vari, deg - 1u) + } + } + }, + multiplyByDoubling(c, degs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variable: Symbol, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (degs.getOrElse(variable) { 0u } < order) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + when { + vari != variable -> put(vari, deg) + deg > order -> put(vari, deg - order) + } + } + }, + degs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> multiplyByDoubling(acc, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthDerivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach + put( + buildMap { + degs.forEach { (vari, deg) -> + if (vari !in filteredVariablesAndOrders) put(vari, deg) + else { + val order = filteredVariablesAndOrders[vari]!! + if (deg > order) put(vari, deg - order) + } + } + }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + degs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> multiplyByDoubling(acc2, ord) } + } + } + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.antiderivativeWithRespectTo( + algebra: A, + variable: Symbol, +): LabeledPolynomial = algebra { + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, 1u) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + c / multiplyByDoubling(one, newDegs[variable]!!) + ) + } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial with respect to provided variable of specified order. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variable: Symbol, + order: UInt +): LabeledPolynomial = algebra { + if (order == 0u) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + newDegs[variable]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } + } + ) + } + } + ) +} + +/** + * Returns algebraic derivative of received polynomial with respect to provided variables of specified orders. + */ +@UnstableKMathAPI +public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo( + algebra: A, + variablesAndOrders: Map, +): LabeledPolynomial = algebra { + val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } + if (filteredVariablesAndOrders.isEmpty()) return this@nthAntiderivativeWithRespectTo + LabeledPolynomial( + buildMap(coefficients.size) { + coefficients + .forEach { (degs, c) -> + val newDegs = buildMap(degs.size + 1) { + for ((variable, order) in filteredVariablesAndOrders) put(variable, order) + for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) + } + put( + newDegs, + filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> + newDegs[index]!!.let { deg -> + (deg downTo deg - order + 1u) + .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + } + } + ) + } + } + ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 37d5d7fb6..4850e6cec 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("FunctionName", "NOTHING_TO_INLINE") + package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI @@ -17,7 +19,6 @@ internal fun List.cleanUp() = subList(0, indexOfLast { it != 0U } + 1) /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. The map is used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) @@ -25,7 +26,6 @@ internal inline fun NumberedPolynomialAsIs(coefs: Map, C>) : Numb * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". * The collections will be transformed to map with [toMap] and then will be used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -33,7 +33,6 @@ internal inline fun NumberedPolynomialAsIs(pairs: Collection * Constructs [NumberedPolynomial] with provided array of [pairs] of pairs "term's signature — term's coefficient". * The array will be transformed to map with [toMap] and then will be used as is. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @PublishedApi internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -43,7 +42,6 @@ internal inline fun NumberedPolynomialAsIs(vararg pairs: Pair, C> * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will * cause wrong computation result or even runtime error.** */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @DelicatePolynomialAPI public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) @@ -54,7 +52,6 @@ public inline fun NumberedPolynomialWithoutCheck(coefs: Map, C>) * **Be sure you read description of [NumberedPolynomial.coefficients]. Otherwise, you may make a mistake that will * cause wrong computation result or even runtime error.** */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") @DelicatePolynomialAPI public inline fun NumberedPolynomialWithoutCheck(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -65,7 +62,6 @@ public inline fun NumberedPolynomialWithoutCheck(pairs: Collection NumberedPolynomialWithoutCheck(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(pairs.toMap()) @@ -77,7 +73,6 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -98,7 +93,6 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -119,7 +113,6 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -142,7 +135,6 @@ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) /** * Constructs [NumberedPolynomial] with provided coefficients map [coefs]. @@ -152,7 +144,6 @@ public inline fun > A.NumberedPolynomial(coefs: Map, C> * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } /** @@ -163,7 +154,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } /** @@ -174,7 +164,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) /** @@ -185,7 +174,6 @@ public inline fun > A.NumberedPolynomial(pairs: Collection> NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -195,7 +183,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -206,7 +193,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -216,7 +202,6 @@ public inline fun > A.NumberedPolynomial(vararg pairs: Pair> NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -226,13 +211,11 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName", "NOTHING_TO_INLINE") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** * Converts [this] constant to [NumberedPolynomial]. */ -@Suppress("NOTHING_TO_INLINE") public inline fun C.asNumberedPolynomial() : NumberedPolynomial = NumberedPolynomialAsIs(mapOf(emptyList() to this)) /** @@ -269,6 +252,7 @@ public class NumberedPolynomialTermSignatureBuilder { * * In fact, it just returns [signature] as regular signature of type `List`. */ + @PublishedApi internal fun build(): List = signature /** @@ -344,8 +328,7 @@ public class NumberedPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: List) { - if (signature in coefficients) coefficients[signature] = add(coefficients[signature]!!, this@with) - else coefficients[signature] = this@with + coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with } /** * Declares monomial with [this] coefficient and signature constructed by [block]. @@ -361,7 +344,7 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + public inline operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this with NumberedPolynomialTermSignatureBuilder().apply(block).build() } @@ -385,7 +368,6 @@ public class NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//@Suppress("FunctionName") //public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. @@ -401,7 +383,6 @@ public class NumberedPolynomialBuilder( * ``` */ @UnstableKMathAPI -@Suppress("FunctionName") public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. @@ -417,7 +398,6 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * ``` */ @UnstableKMathAPI -@Suppress("FunctionName") public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -430,7 +410,6 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -444,7 +423,6 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>, denominatorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -454,13 +432,11 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF /** * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, NumberedPolynomial(mapOf(emptyList() to one))) /** * Constructs [NumberedRationalFunction] with provided [numerator] and unit denominator. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numerator: NumberedPolynomial): NumberedRationalFunction = NumberedRationalFunction(numerator, polynomialOne) @@ -473,7 +449,6 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > NumberedRationalFunctionSpace.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -488,7 +463,6 @@ public fun > NumberedRationalFunctionSpace.NumberedRationalF * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. */ -@Suppress("FunctionName") public fun > A.NumberedRationalFunction(numeratorCoefficients: Map, C>): NumberedRationalFunction = NumberedRationalFunction( NumberedPolynomial(numeratorCoefficients), @@ -496,7 +470,7 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map ) ///** -// * Converts [this] coefficient to [NumberedRationalFunction]. +// * Converts [this] constant to [NumberedRationalFunction]. // */ //context(A) //public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = @@ -505,7 +479,7 @@ public fun > A.NumberedRationalFunction(numeratorCoefficients: Map // NumberedPolynomialAsIs(mapOf(emptyList() to one)) // ) ///** -// * Converts [this] coefficient to [NumberedRationalFunction]. +// * Converts [this] constant to [NumberedRationalFunction]. // */ //context(NumberedRationalFunctionSpace) //public fun > C.asNumberedRationalFunction() : NumberedRationalFunction = diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index fca9a8ab8..06911feca 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -51,15 +51,14 @@ public inline fun , R> A.numberedRationalFunctionSpace(block: Num */ public fun NumberedPolynomial.substitute(args: Map): NumberedPolynomial = Double.algebra { NumberedPolynomial( - buildMap, Double>(coefficients.size) { + buildMap(coefficients.size) { for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitution.pow(deg.toInt()) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC } } ) @@ -70,15 +69,14 @@ public fun NumberedPolynomial.substitute(args: Map): Number */ public fun NumberedPolynomial.substitute(ring: Ring, args: Map): NumberedPolynomial = ring { NumberedPolynomial( - buildMap, C>(coefficients.size) { + buildMap(coefficients.size) { for ((degs, c) in coefficients) { val newDegs = degs.mapIndexed { index, deg -> if (index !in args) deg else 0u }.cleanUp() val newC = args.entries.fold(c) { product, (variable, substitution) -> val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC } } ) @@ -128,14 +126,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Map NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substituteRationalFunction") public fun NumberedRationalFunction.substitute(ring: Ring, args: Map>) : NumberedRationalFunction = ring.numberedRationalFunctionSpace { @@ -250,14 +248,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffe /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substitutePolynomial") public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = NumberedRationalFunction(numerator.substitute(ring, args), denominator.substitute(ring, args)) /** * Substitutes provided arguments [args] into [this] rational function. - */ // TODO: To optimize boxing + */ // TODO: To optimize calculation @JvmName("substituteRationalFunction") public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffer>) : NumberedRationalFunction = ring.numberedRationalFunctionSpace { From 9fc99a4c727eb6ca5870a36a38832bddd8415aea Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 25 Jun 2022 15:45:10 +0300 Subject: [PATCH 092/174] Removed extra copyright comment. --- .../space/kscience/kmath/functions/listConstructors.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index 35c736914..e95361724 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -3,11 +3,6 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring From 403ff93f4af2960facb25696ae5fc1f50e428711 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 25 Jun 2022 16:01:18 +0300 Subject: [PATCH 093/174] Moved optimizations to branch refactor/polynomials --- .../kmath/functions/listUtilOptimized.kt | 250 ------------------ .../space/kscience/kmath/functions/misc.kt | 10 - 2 files changed, 260 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt deleted file mode 100644 index 6eb3a1dc7..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtilOptimized.kt +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.math.max -import kotlin.math.min - - -// TODO: Optimized copies of substitution and invocation -@UnstablePolynomialBoxingOptimization -@Suppress("NOTHING_TO_INLINE") -internal inline fun copyTo( - origin: List, - originDegree: Int, - target: MutableList, -) { - for (deg in 0 .. originDegree) target[deg] = origin[deg] -} - -@UnstablePolynomialBoxingOptimization -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingToUpdater( - ring: Ring, - multiplicand: MutableList, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - updater: MutableList, - 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 -@Suppress("NOTHING_TO_INLINE") -internal inline fun multiplyAddingTo( - ring: Ring, - multiplicand: List, - multiplicandDegree: Int, - multiplier: List, - multiplierDegree: Int, - target: MutableList -) = 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 ListPolynomial.substitute2(ring: Ring, arg: ListPolynomial) : ListPolynomial = 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 = MutableList(thisDegree * argDegree + 1) { constantZero } - resultCoefs[0] = coefficients[thisDegree] - val resultCoefsUpdate: MutableList = 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(resultCoefs) -} - -/** - * Returns numerator (polynomial) of rational function gotten by substitution rational function [arg] to the polynomial instance. - * More concrete, if [arg] is a fraction `f(x)/g(x)` and the receiving instance is `p(x)`, then - * ``` - * p(f/g) * g^deg(p) - * ``` - * is returned. - * - * Used in [ListPolynomial.substitute] and [ListRationalFunction.substitute] for performance optimisation. - */ // TODO: Дописать -@UnstablePolynomialBoxingOptimization -internal fun ListPolynomial.substituteRationalFunctionTakeNumerator(ring: Ring, arg: ListRationalFunction): ListPolynomial = ring { - if (coefficients.isEmpty()) return ListPolynomial(emptyList()) - - val thisDegree = coefficients.lastIndex - if (thisDegree == -1) return ListPolynomial(emptyList()) - val thisDegreeLog2 = 31 - thisDegree.countLeadingZeroBits() - val numeratorDegree = arg.numerator.coefficients.lastIndex - val denominatorDegree = arg.denominator.coefficients.lastIndex - val argDegree = max(numeratorDegree, denominatorDegree) - val constantZero = zero - val powersOf2 = buildList(thisDegreeLog2 + 1) { - var result = 1 - for (exp in 0 .. thisDegreeLog2) { - add(result) - result = result shl 1 - } - } - val hashes = powersOf2.runningReduce { acc, i -> acc + i } - val numeratorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.numerator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * numeratorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * numeratorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * numeratorDegree + 1, - target = next, - ) - } - } - val denominatorPowers = buildList>(thisDegreeLog2 + 1) { - add(arg.denominator.coefficients) - repeat(thisDegreeLog2) { - val next = MutableList(powersOf2[it + 1] * denominatorDegree + 1) { constantZero } - add(next) - val last = last() - multiplyAddingTo( - ring = ring, - multiplicand = last, - multiplicandDegree = powersOf2[it] * denominatorDegree + 1, - multiplier = last, - multiplierDegree = powersOf2[it] * denominatorDegree + 1, - target = next, - ) - } - } - val levelResultCoefsPool = buildList>(thisDegreeLog2 + 1) { - repeat(thisDegreeLog2 + 1) { - add(MutableList(hashes[it] * argDegree) { constantZero }) - } - } - val edgedMultiplier = MutableList(0) { TODO() } - val edgedMultiplierUpdater = MutableList(0) { TODO() } - - fun MutableList.reset() { - for (i in indices) set(i, constantZero) - } - - fun processLevel(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - levelResultCoefs.reset() - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = (start + end) / 2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = (start + end) / 2, end = end), - multiplicandDegree = hashes[level] * argDegree, - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - } - - return levelResultCoefs - } - - fun processLevelEdged(level: Int, start: Int, end: Int) : List { - val levelResultCoefs = levelResultCoefsPool[level + 1] - - if (level == -1) { - levelResultCoefs[0] = coefficients[start] - } else { - val levelsPowerOf2 = powersOf2[level] - if (end - start >= levelsPowerOf2) { - multiplyAddingTo( - ring = ring, - multiplicand = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - multiplicandDegree = hashes[level] * argDegree, // TODO: Ввести переменную - multiplier = numeratorPowers[level], - multiplierDegree = powersOf2[level] * numeratorDegree, - target = levelResultCoefs - ) - multiplyAddingTo( - ring = ring, - multiplicand = processLevel(level = level - 1, start = start, end = start + levelsPowerOf2), - multiplicandDegree = hashes[level] * argDegree, - multiplier = edgedMultiplier, - multiplierDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - if (level != thisDegreeLog2) { - multiplyAddingToUpdater( - ring = ring, - multiplicand = edgedMultiplier, - multiplicandDegree = max((hashes[level] and thisDegree) - powersOf2[level] + 1, 0) * denominatorDegree, // TODO: Ввести переменную - multiplier = denominatorPowers[level], - multiplierDegree = powersOf2[level] * denominatorDegree, - updater = edgedMultiplierUpdater, - zero = constantZero - ) - } - } else { - copyTo( - origin = processLevelEdged(level = level - 1, start = start + levelsPowerOf2, end = end), - originDegree = hashes[level] * argDegree, // TODO: Ввести переменную - target = levelResultCoefs - ) - } - } - - return levelResultCoefs - } - - return ListPolynomial( - processLevelEdged( - level = thisDegreeLog2, - start = 0, - end = thisDegree + 1 - ) - ) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index 7d6fc84fa..aba246519 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -6,16 +6,6 @@ package space.kscience.kmath.functions -/** - * Marks operations that are going to be optimized reimplementations by reducing number of boxings but currently is - * under development and is not stable (or even ready to use). - */ -@RequiresOptIn( - message = "It's copy of operation with optimized boxing. It's currently unstable.", - level = RequiresOptIn.Level.ERROR -) -internal annotation class UnstablePolynomialBoxingOptimization - /** * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is From 3e917baaaf86ae8a7c73eda36c20dafbe418bda0 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 25 Jun 2022 21:23:32 +0300 Subject: [PATCH 094/174] Added examples for polynomials. Also: - Fixed bug in differentiation of NumberedPolynomials. - Fixed bug in addition and subtraction of LabeledPolynomials. - Added references to NumberedPolynomialWithoutCheck and LabeledPolynomialWithoutCheck. - Made NumberedRationalFunction and LabeledRationalFunction classes data. Made their constructor public. --- .../kscience/kmath/functions/polynomials.kt | 396 ++++++++++++++++++ .../kmath/functions/LabeledPolynomial.kt | 4 +- .../functions/LabeledRationalFunction.kt | 2 +- .../functions/NumberedRationalFunction.kt | 2 +- .../kmath/functions/labeledConstructors.kt | 24 ++ .../kmath/functions/numberedConstructors.kt | 22 + .../kscience/kmath/functions/numberedUtil.kt | 6 +- 7 files changed, 449 insertions(+), 7 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt new file mode 100644 index 000000000..273fe5cb9 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -0,0 +1,396 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.operations.algebra + + +/** + * Shows [ListPolynomial]s' and [ListRationalFunction]s' capabilities. + */ +fun listPolynomialsExample() { + // [ListPolynomial] is a representation of a univariate polynomial as a list of coefficients from the least term to + // the greatest term. For example, + val polynomial1: ListPolynomial = ListPolynomial(listOf(2, -3, 1)) + // represents polynomial 2 + (-3) x + x^2 + + // There are also shortcut fabrics: + val polynomial2: ListPolynomial = ListPolynomial(2, -3, 1) + println(polynomial1 == polynomial2) // true + // and even + val polynomial3: ListPolynomial = 57.asListPolynomial() + val polynomial4: ListPolynomial = ListPolynomial(listOf(57)) + println(polynomial3 == polynomial4) // true + + val polynomial5: ListPolynomial = ListPolynomial(3, -1) + // For every ring there can be provided a polynomial ring: + Int.algebra.listPolynomialSpace { + println(-polynomial5 == ListPolynomial(-3, 1)) // true + println(polynomial1 + polynomial5 == ListPolynomial(5, -4, 1)) // true + println(polynomial1 - polynomial5 == ListPolynomial(-1, -2, 1)) // true + println(polynomial1 * polynomial5 == ListPolynomial(6, -11, 6, -1)) // true + } + // You can even write + val x: ListPolynomial = ListPolynomial(0.0, 1.0) + val polynomial6: ListPolynomial = ListPolynomial(2.0, -3.0, 1.0) + Double.algebra.listPolynomialSpace { + println(2 - 3 * x + x * x == polynomial6) + println(2.0 - 3.0 * x + x * x == polynomial6) + } + + // Also there are some utilities for polynomials: + println(polynomial1.substitute(Int.algebra, 1) == 0) // true, because 2 + (-3) * 1 + 1^2 = 0 + println(polynomial1.substitute(Int.algebra, polynomial5) == polynomial1) // true, because 2 + (-3) * (3-x) + (3-x)^2 = 2 - 3x + x^2 + println(polynomial1.derivative(Int.algebra) == ListPolynomial(-3, 2)) // true, (2 - 3x + x^2)' = -3 + 2x + println(polynomial1.nthDerivative(Int.algebra, 2) == 2.asListPolynomial()) // true, (2 - 3x + x^2)'' = 2 + + // Lastly, there are rational functions and some other utilities: + Double.algebra.listRationalFunctionSpace { + val rationalFunction1: ListRationalFunction = ListRationalFunction(listOf(2.0, -3.0, 1.0), listOf(3.0, -1.0)) + // It's just (2 - 3x + x^2)/(3 - x) + + val rationalFunction2 : ListRationalFunction = ListRationalFunction(listOf(5.0, -4.0, 1.0), listOf(3.0, -1.0)) + // It's just (5 - 4x + x^2)/(3 - x) + + println(rationalFunction1 + 1 == rationalFunction2) + } +} + +/** + * Shows [NumberedPolynomial]s' and [NumberedRationalFunction]s' capabilities. + */ +fun numberedPolynomialsExample() { + // Consider polynomial + // 3 + 5 x_2 - 7 x_1^2 x_3 + // Consider, for example, its term -7 x_1^2 x_3. -7 is a coefficient of the term, whereas (2, 0, 1, 0, 0, ...) is + // description of degrees of variables x_1, x_2, ... in the term. Such description with removed leading zeros + // [2, 0, 1] is called "signature" of the term -7 x_1^2 x_3. + + val polynomial1: NumberedPolynomial + with(Int.algebra) { + // [NumberedPolynomial] is a representation of a multivariate polynomial, that stores terms in a map with terms' + // signatures as the map's keys and terms' coefficients as corresponding values. For example, + polynomial1 = NumberedPolynomial( + mapOf( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + ) + // represents polynomial 3 + 5 x_2 - 7 x_1^2 x_3 + + // This `NumberedPolynomial` function needs context of either ring of constant (as `Int.algebra` in this example) + // or space of NumberedPolynomials over it. To understand why it is like this see documentations of functions + // NumberedPolynomial and NumberedPolynomialWithoutCheck + + // There are also shortcut fabrics: + val polynomial2: NumberedPolynomial = NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + println(polynomial1 == polynomial2) // true + // and even + val polynomial3: NumberedPolynomial = 57.asNumberedPolynomial() // This one actually does not algebraic context! + val polynomial4: NumberedPolynomial = NumberedPolynomial(listOf() to 57) + println(polynomial3 == polynomial4) // true + + numberedPolynomialSpace { + // Also there is DSL for constructing NumberedPolynomials: + val polynomial5: NumberedPolynomial = NumberedPolynomial { + 3 {} + 5 { 2 inPowerOf 1u } + -7 with { 1 pow 2u; 3 pow 1u } + // `pow` and `inPowerOf` are the same + // `with` is omittable + } + println(polynomial1 == polynomial5) // true + + // Unfortunately the DSL does not work good in bare context of constants' ring, so for now it's disabled and + // works only in NumberedPolynomialSpace and NumberedRationalFunctionSpace + } + } + + val polynomial6: NumberedPolynomial = with(Int.algebra) { + NumberedPolynomial( + listOf() to 7, + listOf(0u, 1u) to -5, + listOf(2u, 0u, 1u) to 0, + listOf(0u, 0u, 0u, 4u) to 4, + ) + } + // For every ring there can be provided a polynomial ring: + Int.algebra.numberedPolynomialSpace { + println( + -polynomial6 == NumberedPolynomial { + (-7) {} + 5 { 2 pow 1u } + 0 { 1 pow 2u; 3 pow 1u } + (-4) { 4 pow 4u } + } + ) // true + println( + polynomial1 + polynomial6 == NumberedPolynomial { + 10 {} + 0 { 2 pow 1u } + (-7) { 1 pow 2u; 3 pow 1u } + 4 { 4 pow 4u } + } + ) // true + println( + polynomial1 - polynomial6 == NumberedPolynomial { + (-4) {} + 10 { 2 pow 1u } + (-7) { 1 pow 2u; 3 pow 1u } + (-4) { 4 pow 4u } + } + ) // true + + polynomial1 * polynomial6 // Multiplication works too + } + + Double.algebra.numberedPolynomialSpace { + // You can even write + val x_1: NumberedPolynomial = NumberedPolynomial { 1.0 { 1 pow 1u } } + val x_2: NumberedPolynomial = NumberedPolynomial { 1.0 { 2 pow 1u } } + val x_3: NumberedPolynomial = NumberedPolynomial { 1.0 { 3 pow 1u } } + val polynomial7: NumberedPolynomial = NumberedPolynomial { + 3.0 {} + 5.0 { 2 pow 1u } + (-7.0) { 1 pow 2u; 3 pow 1u } + } + Double.algebra.listPolynomialSpace { + println(3 + 5 * x_2 - 7 * x_1 * x_1 * x_3 == polynomial7) + println(3.0 + 5.0 * x_2 - 7.0 * x_1 * x_1 * x_3 == polynomial7) + } + } + + Int.algebra.numberedPolynomialSpace { + val x_4: NumberedPolynomial = NumberedPolynomial { 1 { 4 pow 1u } } + // Also there are some utilities for polynomials: + println(polynomial1.substitute(mapOf(0 to 1, 1 to -2, 2 to -1)) == 0.asNumberedPolynomial()) // true, + // because it's substitution x_1 -> 1, x_2 -> -2, x_3 -> -1, + // so 3 + 5 x_2 - 7 x_1^2 x_3 = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 + println( + polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial { + 3 {} + 5 { 4 pow 1u } + (-7) { 1 pow 2u; 3 pow 1u } + } + ) // true, because it's substitution x_2 -> x_4, so result is 3 + 5 x_4 - 7 x_1^2 x_3 + println( + polynomial1.derivativeWithRespectTo(Int.algebra, 1) == + NumberedPolynomial { 5 {} } + ) // true, d/dx_2 (3 + 5 x_2 - 7 x_1^2 x_3) = 5 + } + + // Lastly, there are rational functions and some other utilities: + Double.algebra.numberedRationalFunctionSpace { + val rationalFunction1: NumberedRationalFunction = NumberedRationalFunction( + NumberedPolynomial { + 2.0 {} + (-3.0) { 1 pow 1u } + 1.0 { 1 pow 2u } + }, + NumberedPolynomial { + 3.0 {} + (-1.0) { 1 pow 1u } + } + ) + // It's just (2 - 3x + x^2)/(3 - x) where x = x_1 + + val rationalFunction2: NumberedRationalFunction = NumberedRationalFunction( + NumberedPolynomial { + 5.0 {} + (-4.0) { 1 pow 1u } + 1.0 { 1 pow 2u } + }, + NumberedPolynomial { + 3.0 {} + (-1.0) { 1 pow 1u } + } + ) + // It's just (5 - 4x + x^2)/(3 - x) where x = x_1 + + println(rationalFunction1 + 1 == rationalFunction2) + } +} + +/** + * Shows [LabeledPolynomial]s' and [LabeledRationalFunction]s' capabilities. + */ +fun labeledPolynomialsExample() { + val x by symbol + val y by symbol + val z by symbol + val t by symbol + + // Consider polynomial + // 3 + 5 y - 7 x^2 z + // Consider, for example, its term -7 x^2 z. -7 is a coefficient of the term, whereas matching (x -> 2, z -> 3) is + // description of degrees of variables x_1, x_2, ... in the term. Such description is called "signature" of the + // term -7 x_1^2 x_3. + + val polynomial1: LabeledPolynomial + with(Int.algebra) { + // [LabeledPolynomial] is a representation of a multivariate polynomial, that stores terms in a map with terms' + // signatures as the map's keys and terms' coefficients as corresponding values. For example, + polynomial1 = LabeledPolynomial( + mapOf( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) + ) + // represents polynomial 3 + 5 y - 7 x^2 z + + // This `LabeledPolynomial` function needs context of either ring of constant (as `Int.algebra` in this example) + // or space of LabeledPolynomials over it. To understand why it is like this see documentations of functions + // LabeledPolynomial and LabeledPolynomialWithoutCheck + + // There are also shortcut fabrics: + val polynomial2: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) + println(polynomial1 == polynomial2) // true + // and even + val polynomial3: LabeledPolynomial = 57.asLabeledPolynomial() // This one actually does not algebraic context! + val polynomial4: LabeledPolynomial = LabeledPolynomial(mapOf() to 57) + println(polynomial3 == polynomial4) // true + + labeledPolynomialSpace { + // Also there is DSL for constructing NumberedPolynomials: + val polynomial5: LabeledPolynomial = LabeledPolynomial { + 3 {} + 5 { y inPowerOf 1u } + -7 with { x pow 2u; z pow 1u } + // `pow` and `inPowerOf` are the same + // `with` is omittable + } + println(polynomial1 == polynomial5) // true + + // Unfortunately the DSL does not work good in bare context of constants' ring, so for now it's disabled and + // works only in NumberedPolynomialSpace and NumberedRationalFunctionSpace + } + } + + val polynomial6: LabeledPolynomial = with(Int.algebra) { + LabeledPolynomial( + mapOf() to 7, + mapOf(y to 1u) to -5, + mapOf(x to 2u, z to 1u) to 0, + mapOf(t to 4u) to 4, + ) + } + // For every ring there can be provided a polynomial ring: + Int.algebra.labeledPolynomialSpace { + println( + -polynomial6 == LabeledPolynomial { + (-7) {} + 5 { y pow 1u } + 0 { x pow 2u; z pow 1u } + (-4) { t pow 4u } + } + ) // true + println( + polynomial1 + polynomial6 == LabeledPolynomial { + 10 {} + 0 { y pow 1u } + (-7) { x pow 2u; z pow 1u } + 4 { t pow 4u } + } + ) // true + println( + polynomial1 - polynomial6 == LabeledPolynomial { + (-4) {} + 10 { y pow 1u } + (-7) { x pow 2u; z pow 1u } + (-4) { t pow 4u } + } + ) // true + + polynomial1 * polynomial6 // Multiplication works too + } + + Double.algebra.labeledPolynomialSpace { + // You can even write + val polynomial7: LabeledPolynomial = LabeledPolynomial { + 3.0 {} + 5.0 { y pow 1u } + (-7.0) { x pow 2u; z pow 1u } + } + Double.algebra.listPolynomialSpace { + println(3 + 5 * y - 7 * x * x * z == polynomial7) + println(3.0 + 5.0 * y - 7.0 * x * x * z == polynomial7) + } + } + + Int.algebra.labeledPolynomialSpace { + // Also there are some utilities for polynomials: + println(polynomial1.substitute(mapOf(x to 1, y to -2, z to -1)) == 0.asLabeledPolynomial()) // true, + // because it's substitution x -> 1, y -> -2, z -> -1, + // so 3 + 5 y - 7 x^2 z = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 + println( + polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial { + 3 {} + 5 { t pow 1u } + (-7) { x pow 2u; z pow 1u } + } + ) // true, because it's substitution y -> t, so result is 3 + 5 t - 7 x^2 z + println( + polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial { 5 {} } + ) // true, d/dy (3 + 5 y - 7 x^2 z) = 5 + } + + // Lastly, there are rational functions and some other utilities: + Double.algebra.labeledRationalFunctionSpace { + val rationalFunction1: LabeledRationalFunction = LabeledRationalFunction( + LabeledPolynomial { + 2.0 {} + (-3.0) { x pow 1u } + 1.0 { x pow 2u } + }, + LabeledPolynomial { + 3.0 {} + (-1.0) { x pow 1u } + } + ) + // It's just (2 - 3x + x^2)/(3 - x) + + val rationalFunction2: LabeledRationalFunction = LabeledRationalFunction( + LabeledPolynomial { + 5.0 {} + (-4.0) { x pow 1u } + 1.0 { x pow 2u } + }, + LabeledPolynomial { + 3.0 {} + (-1.0) { x pow 1u } + } + ) + // It's just (5 - 4x + x^2)/(3 - x) + + println(rationalFunction1 + 1 == rationalFunction2) + } +} + +fun main() { + println("ListPolynomials:") + listPolynomialsExample() + println() + + println("NumberedPolynomials:") + numberedPolynomialsExample() + println() + + println("ListPolynomials:") + labeledPolynomialsExample() + println() +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index b0c54502d..061325b60 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -522,7 +522,7 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } } ) @@ -532,7 +532,7 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - other.coefficients.mapValuesTo(this) { it.value } + coefficients.mapValuesTo(this) { it.value } other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } } ) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 03f323813..1b0bbbec8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -13,7 +13,7 @@ import kotlin.jvm.JvmName /** * Represents multivariate rational function that stores its numerator and denominator as [LabeledPolynomial]s. */ -public class LabeledRationalFunction( +public data class LabeledRationalFunction( public override val numerator: LabeledPolynomial, public override val denominator: LabeledPolynomial ) : RationalFunction> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 92f507735..497755126 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -15,7 +15,7 @@ import kotlin.math.max /** * Represents multivariate rational function that stores its numerator and denominator as [NumberedPolynomial]s. */ -public class NumberedRationalFunction internal constructor( +public data class NumberedRationalFunction( public override val numerator: NumberedPolynomial, public override val denominator: NumberedPolynomial ) : RationalFunction> { diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 47325c4bb..7586b7012 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -73,6 +73,8 @@ public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -93,6 +95,8 @@ public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) - * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -113,6 +117,8 @@ public fun LabeledPolynomial(pairs: Collection, C>>, * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -135,6 +141,8 @@ public fun LabeledPolynomial(vararg pairs: Pair, C>, add: * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > A.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs, ::add) /** @@ -144,6 +152,8 @@ public inline fun > A.LabeledPolynomial(coefs: Map> LabeledPolynomialSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } @@ -154,6 +164,8 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(coefs: Map, C>) : LabeledPolynomial = LabeledPolynomial(coefs) { left: C, right: C -> left + right } @@ -164,6 +176,8 @@ public inline fun > LabeledRationalFunctionSpace.LabeledPoly * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > A.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs, ::add) @@ -174,6 +188,8 @@ public inline fun > A.LabeledPolynomial(pairs: Collection> LabeledPolynomialSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -183,6 +199,8 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(pairs: Collection, C>>) : LabeledPolynomial = LabeledPolynomial(pairs) { left: C, right: C -> left + right } @@ -193,6 +211,8 @@ public inline fun > LabeledRationalFunctionSpace.LabeledPoly * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > A.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -202,6 +222,8 @@ public inline fun > A.LabeledPolynomial(vararg pairs: Pair> LabeledPolynomialSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -211,6 +233,8 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see LabeledPolynomialWithoutCheck */ public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(vararg pairs: Pair, C>) : LabeledPolynomial = LabeledPolynomial(*pairs) { left: C, right: C -> left + right } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 4850e6cec..3cd398623 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -72,6 +72,8 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -92,6 +94,8 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -112,6 +116,8 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { val fixedCoefs = mutableMapOf, C>() @@ -134,6 +140,8 @@ public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > A.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs, ::add) /** @@ -143,6 +151,8 @@ public inline fun > A.NumberedPolynomial(coefs: Map, C> * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > NumberedPolynomialSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } @@ -153,6 +163,8 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Zeros at the ends of terms' signatures (e.g. [coefs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(coefs: Map, C>) : NumberedPolynomial = NumberedPolynomial(coefs) { left: C, right: C -> left + right } @@ -163,6 +175,8 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > A.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs, ::add) @@ -173,6 +187,8 @@ public inline fun > A.NumberedPolynomial(pairs: Collection> NumberedPolynomialSpace.NumberedPolynomial(pairs: Collection, C>>) : NumberedPolynomial = NumberedPolynomial(pairs) { left: C, right: C -> left + right } /** @@ -192,6 +208,8 @@ public inline fun > NumberedRationalFunctionSpace.NumberedPo * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > A.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -201,6 +219,8 @@ public inline fun > A.NumberedPolynomial(vararg pairs: Pair> NumberedPolynomialSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } /** @@ -210,6 +230,8 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * 1. Zeros at the ends of terms' signatures (e.g. [pairs] keys) will be removed. (See [cleanUp].) * 1. Terms that happen to have the same signature will be summed up. * 1. New map will be formed of resulting terms. + * + * @see NumberedPolynomialWithoutCheck */ public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(vararg pairs: Pair, C>) : NumberedPolynomial = NumberedPolynomial(*pairs) { left: C, right: C -> left + right } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 06911feca..96f5f480b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -353,7 +353,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - if (degs.size > variable) return@forEach + if (degs.lastIndex < variable) return@forEach put( degs.mapIndexed { index, deg -> when { @@ -383,7 +383,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - if (degs.size > variable) return@forEach + if (degs.lastIndex < variable) return@forEach put( degs.mapIndexed { index, deg -> when { @@ -417,7 +417,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - if (degs.size > maxRespectedVariable) return@forEach + if (degs.lastIndex < maxRespectedVariable) return@forEach put( degs.mapIndexed { index, deg -> if (index !in filteredVariablesAndOrders) return@mapIndexed deg From 630d16bbeefbd8d402732dd8410ea950c26a6ca6 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 26 Jun 2022 12:16:51 +0300 Subject: [PATCH 095/174] Added design notes. Also: - Changed `xxxPolynomialSpace()` and `xxxPolynomialSpace()` functions to `xxxPolynomialSpace` value properties. - Changed inconsistency of names `XxxRationalFunctionalSpaceYyy` and `XxxRationalFunctionSpaceYyy` in favor of second one. --- docs/polynomials.md | 172 ++++++++++++++++++ .../functions/LabeledRationalFunction.kt | 2 +- .../kmath/functions/ListRationalFunction.kt | 2 +- .../functions/NumberedRationalFunction.kt | 2 +- .../kmath/functions/RationalFunction.kt | 22 +-- .../kscience/kmath/functions/labeledUtil.kt | 8 +- .../kscience/kmath/functions/listUtil.kt | 12 +- .../kscience/kmath/functions/numberedUtil.kt | 8 +- 8 files changed, 200 insertions(+), 28 deletions(-) create mode 100644 docs/polynomials.md diff --git a/docs/polynomials.md b/docs/polynomials.md new file mode 100644 index 000000000..fe69948e5 --- /dev/null +++ b/docs/polynomials.md @@ -0,0 +1,172 @@ +# Polynomials and Rational Functions + +KMath provides a way to work with uni- and multivariate polynomials and rational functions. It includes full support of arithmetic operations of integers, **constants** (elements of ring polynomials are build over), variables (for certain multivariate implementations), polynomials and rational functions encapsulated in so-called **polynomial space** and **rational function space** and some other utilities such as algebraic differentiation and substitution. + +## Concrete realizations + +There are 3 approaches to represent polynomials: +1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.) +2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation: + 1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be represented as a finite sequence $(d_0; \dots; d_n)$. + 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. + +All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented. + +So here are a bit of details. Let `C` by type of constants. Then: +1. `ListPolynomial`, `ListPolynomialSpace`, `ListRationalFunction` and `ListRationalFunctionSpace` implement the first scenario. `ListPolynomial` stores polynomial $a_0 + \dots + a_n x^n $ as a coefficients list `listOf(a_0, ..., a_n)` (of type `List`). + + They also have variation `ScalableListPolynomialSpace` that replaces former polynomials and implements `ScaleOperations`. +2. `NumberedPolynomial`, `NumberedPolynomialSpace`, `NumberedRationalFunction` and `NumberedRationalFunctionSpace` implement second scenario. `NumberedPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `List`. To prevent ambiguity signatures should not end with zeros. +3. `LabeledPolynomial`, `LabeledPolynomialSpace`, `LabeledRationalFunction` and `LabeledRationalFunctionSpace` implement third scenario using common `Symbol` as variable type. `LabeledPolynomial` stores polynomials as structures of type `Map, C>`. Signatures are stored as `Map`. To prevent ambiguity each signature should not map any variable to zero. + +### Example: `ListPolynomial` + +For example, polynomial $2 - 3x + x^2 $ (with `Int` coefficients) is represented +```kotlin +val polynomial: ListPolynomial = ListPolynomial(listOf(2, -3, 1)) +// or +val polynomial: ListPolynomial = ListPolynomial(2, -3, 1) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.listPolynomialSpace { + ListPolynomial(2, -3, 1) + ListPolynomial(0, 6) == ListPolynomial(2, 3, 1) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +### Example: `NumberedPolynomial` + +For example, polynomial $3 + 5 x_1 - 7 x_0^2 x_2 $ (with `Int` coefficients) is represented +```kotlin +val polynomial: NumberedPolynomial = NumberedPolynomial( + mapOf( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) +) +// or +val polynomial: NumberedPolynomial = NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, +) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.numberedPolynomialSpace { + NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + NumberedPolynomial( + listOf(0u, 1u) to -5, + listOf(0u, 0u, 0u, 4u) to 4, + ) == NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +### Example: `LabeledPolynomial` + +For example, polynomial $3 + 5 y - 7 x^2 z $ (with `Int` coefficients) is represented +```kotlin +val polynomial: LabeledPolynomial = LabeledPolynomial( + mapOf( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) +) +// or +val polynomial: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, +) +``` + +All algebraic operations can be used in corresponding space: +```kotlin +val computationResult = Int.algebra.labeledPolynomialSpace { + LabeledPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) + LabeledPolynomial( + listOf(0u, 1u) to -5, + listOf(0u, 0u, 0u, 4u) to 4, + ) == LabeledPolynomial( + listOf() to 3, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) +} + +println(computationResult) // true +``` + +For more see [examples](../examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt). + +## Abstract entities (interfaces and abstract classes) + +```mermaid +classDiagram + Polynomial <|-- ListPolynomial + Polynomial <|-- NumberedPolynomial + Polynomial <|-- LabeledPolynomial + + RationalFunction <|-- ListRationalFunction + RationalFunction <|-- NumberedRationalFunction + RationalFunction <|-- LabeledRationalFunction + + Ring <|-- PolynomialSpace + PolynomialSpace <|-- MultivariatePolynomialSpace + PolynomialSpace <|-- PolynomialSpaceOverRing + + Ring <|-- RationalFunctionSpace + RationalFunctionSpace <|-- MultivariateRationalFunctionSpace + RationalFunctionSpace <|-- RationalFunctionSpaceOverRing + RationalFunctionSpace <|-- RationalFunctionSpaceOverPolynomialSpace + RationalFunctionSpace <|-- PolynomialSpaceOfFractions + RationalFunctionSpaceOverPolynomialSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace + MultivariateRationalFunctionSpace <|-- MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace + MultivariateRationalFunctionSpace <|-- MultivariatePolynomialSpaceOfFractions + PolynomialSpaceOfFractions <|-- MultivariatePolynomialSpaceOfFractions +``` + +There are implemented `Polynomial` and `RationalFunction` interfaces as abstractions of polynomials and rational functions respectively (although, there is not a lot of logic in them) and `PolynomialSpace` and `RationalFunctionSpace` (that implement `Ring` interface) as abstractions of polynomials' and rational functions' spaces respectively. More precisely, that means they allow to declare common logic of interaction with such objects and spaces: +- `Polynomial` does not provide any logic. It is marker interface. +- `RationalFunction` provides numerator and denominator of rational function and destructuring declaration for them. +- `PolynomialSpace` provides all possible arithmetic interactions of integers, constants (of type `C`), and polynomials (of type `P`) like addition, subtraction, multiplication, and some others and common properties like degree of polynomial. +- `RationalFunctionSpace` provides the same as `PolynomialSpace` but also for rational functions: all possible arithmetic interactions of integers, constants (of type `C`), polynomials (of type `P`), and rational functions (of type `R`) like addition, subtraction, multiplication, division (in some cases), and some others and common properties like degree of polynomial. + +Then to add abstraction of similar behaviour with variables (in multivariate case) there are implemented `MultivariatePolynomialSpace` and `MultivariateRationalFunctionSpace`. They just include variables (of type `V`) in the interactions of the entities. + +Also, to remove boilerplates there were provided helping subinterfaces and abstract subclasses: +- `PolynomialSpaceOverRing` allows to replace implementation of interactions of integers and constants with implementations from provided ring over constants (of type `A: Ring`). +- `RationalFunctionSpaceOverRing` — the same but for `RationalFunctionSpace`. +- `RationalFunctionSpaceOverPolynomialSpace` — the same but "the inheritance" includes interactions with polynomials from provided `PolynomialSpace`. +- `PolynomialSpaceOfFractions` is actually abstract subclass of `RationalFunctionSpace` that implements all fractions boilerplates with provided (`protected`) constructor of rational functions by polynomial numerator and denominator. +- `MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace` and `MultivariatePolynomialSpaceOfFractions` — the same stories of operators inheritance and fractions boilerplates respectively but in multivariate case. + +## Utilities + +For all kinds of polynomials there are provided (implementation details depend on kind of polynomials) such common utilities as: +1. differentiation and anti-differentiation, +2. substitution, invocation and functional representation. \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index 1b0bbbec8..b1d0dd4d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -30,7 +30,7 @@ public data class LabeledRationalFunction( public class LabeledRationalFunctionSpace>( public val ring: A, ) : - MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< + MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, Symbol, LabeledPolynomial, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index e23baa548..7434063f2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -28,7 +28,7 @@ public data class ListRationalFunction( public class ListRationalFunctionSpace> ( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionSpaceOverPolynomialSpace< C, ListPolynomial, ListRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 497755126..e61d6c55e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -32,7 +32,7 @@ public data class NumberedRationalFunction( public class NumberedRationalFunctionSpace> ( public val ring: A, ) : - RationalFunctionalSpaceOverPolynomialSpace< + RationalFunctionSpaceOverPolynomialSpace< C, NumberedPolynomial, NumberedRationalFunction, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 338ae9935..1782dba74 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -29,7 +29,7 @@ public interface RationalFunction> { * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpace, R: RationalFunction> : Ring { +public interface RationalFunctionSpace, R: RationalFunction> : Ring { /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * @@ -459,12 +459,12 @@ public interface RationalFunctionalSpace, R: RationalFunctio * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverRing< +public interface RationalFunctionSpaceOverRing< C, P: Polynomial, R: RationalFunction, A: Ring - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. @@ -561,12 +561,12 @@ public interface RationalFunctionalSpaceOverRing< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface RationalFunctionalSpaceOverPolynomialSpace< +public interface RationalFunctionSpaceOverPolynomialSpace< C, P: Polynomial, R: RationalFunction, AP: PolynomialSpace, - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Underlying polynomial ring. Its polynomial operations are inherited by local polynomial operations. @@ -797,7 +797,7 @@ public abstract class PolynomialSpaceOfFractions< C, P: Polynomial, R: RationalFunction, - > : RationalFunctionalSpace { + > : RationalFunctionSpace { /** * Constructor of rational functions (of type [R]) from numerator and denominator (of type [P]). @@ -1106,12 +1106,12 @@ public abstract class PolynomialSpaceOfFractions< * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariateRationalFunctionalSpace< +public interface MultivariateRationalFunctionSpace< C, V, P: Polynomial, R: RationalFunction - >: RationalFunctionalSpace { + >: RationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @@ -1335,13 +1335,13 @@ public interface MultivariateRationalFunctionalSpace< * @param AP the type of algebraic structure (precisely, of ring) provided for polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariateRationalFunctionalSpaceOverMultivariatePolynomialSpace< +public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, V, P: Polynomial, R: RationalFunction, AP: MultivariatePolynomialSpace, - > : RationalFunctionalSpaceOverPolynomialSpace, MultivariateRationalFunctionalSpace { + > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @@ -1517,7 +1517,7 @@ public abstract class MultivariatePolynomialSpaceOfFractions< V, P: Polynomial, R: RationalFunction, - > : MultivariateRationalFunctionalSpace, PolynomialSpaceOfFractions() { + > : MultivariateRationalFunctionSpace, PolynomialSpaceOfFractions() { /** * Returns sum of the variable represented as a rational function and the rational function. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt index 39c781a14..4002eb25a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -19,8 +19,8 @@ import kotlin.jvm.JvmName /** * Creates a [LabeledPolynomialSpace] over a received ring. */ -public fun > A.labeledPolynomialSpace(): LabeledPolynomialSpace = - LabeledPolynomialSpace(this) +public inline val > A.labeledPolynomialSpace: LabeledPolynomialSpace + get() = LabeledPolynomialSpace(this) /** * Creates a [LabeledPolynomialSpace]'s scope over a received ring. @@ -32,8 +32,8 @@ public inline fun , R> A.labeledPolynomialSpace(block: LabeledPol /** * Creates a [LabeledRationalFunctionSpace] over a received ring. */ -public fun > A.labeledRationalFunctionSpace(): LabeledRationalFunctionSpace = - LabeledRationalFunctionSpace(this) +public inline val > A.labeledRationalFunctionSpace: LabeledRationalFunctionSpace + get() = LabeledRationalFunctionSpace(this) /** * Creates a [LabeledRationalFunctionSpace]'s scope over a received ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 649fc48bd..4f3f6d88e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -16,8 +16,8 @@ import kotlin.math.pow /** * Creates a [ListPolynomialSpace] over a received ring. */ -public fun > A.listPolynomialSpace(): ListPolynomialSpace = - ListPolynomialSpace(this) +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) /** * Creates a [ListPolynomialSpace]'s scope over a received ring. @@ -30,8 +30,8 @@ public inline fun , R> A.listPolynomialSpace(block: ListPolynomia /** * Creates a [ScalableListPolynomialSpace] over a received scalable ring. */ -public fun A.scalableListPolynomialSpace(): ScalableListPolynomialSpace where A : Ring, A : ScaleOperations = - ScalableListPolynomialSpace(this) +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) /** * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. @@ -44,8 +44,8 @@ public inline fun A.scalableListPolynomialSpace(block: ScalableListPol /** * Creates a [ListRationalFunctionSpace] over a received ring. */ -public fun > A.listRationalFunctionSpace(): ListRationalFunctionSpace = - ListRationalFunctionSpace(this) +public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace + get() = ListRationalFunctionSpace(this) /** * Creates a [ListRationalFunctionSpace]'s scope over a received ring. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 96f5f480b..e485652f4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -21,8 +21,8 @@ import kotlin.math.min /** * Creates a [NumberedPolynomialSpace] over a received ring. */ -public fun > A.numberedPolynomialSpace(): NumberedPolynomialSpace = - NumberedPolynomialSpace(this) +public inline val > A.numberedPolynomialSpace: NumberedPolynomialSpace + get() = NumberedPolynomialSpace(this) /** * Creates a [NumberedPolynomialSpace]'s scope over a received ring. @@ -35,8 +35,8 @@ public inline fun , R> A.numberedPolynomialSpace(block: NumberedP /** * Creates a [NumberedRationalFunctionSpace] over a received ring. */ -public fun > A.numberedRationalFunctionSpace(): NumberedRationalFunctionSpace = - NumberedRationalFunctionSpace(this) +public inline val > A.numberedRationalFunctionSpace: NumberedRationalFunctionSpace + get() = NumberedRationalFunctionSpace(this) /** * Creates a [NumberedRationalFunctionSpace]'s scope over a received ring. From cb7291ccb00e5b167b69928360ae4fadafcaf0cd Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 26 Jun 2022 12:58:30 +0300 Subject: [PATCH 096/174] Little addition to polynomials design note. --- docs/polynomials.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/polynomials.md b/docs/polynomials.md index fe69948e5..b255acda1 100644 --- a/docs/polynomials.md +++ b/docs/polynomials.md @@ -8,7 +8,7 @@ There are 3 approaches to represent polynomials: 1. For univariate polynomials one can represent and store polynomial as a list of coefficients for each power of the variable. I.e. polynomial $a_0 + \dots + a_n x^n $ can be represented as a finite sequence $(a_0; \dots; a_n)$. (Compare to sequential definition of polynomials.) 2. For multivariate polynomials one can represent and store polynomial as a matching (in programming it is called "map" or "dictionary", in math it is called [functional relation](https://en.wikipedia.org/wiki/Binary_relation#Special_types_of_binary_relations)) of each "**term signature**" (that describes what variables and in what powers appear in the term) with corresponding coefficient of the term. But there are 2 possible approaches of term signature representation: 1. One can number all the variables, so term signature can be represented as a sequence describing powers of the variables. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural or zero $d_i $) can be represented as a finite sequence $(d_0; \dots; d_n)$. - 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. + 2. One can represent variables as objects ("**labels**"), so term signature can be also represented as a matching of each appeared variable with its power in the term. I.e. signature of term $c \\; x_0^{d_0} \dots x_n^{d_n} $ (for natural non-zero $d_i $) can be represented as a finite matching $(x_0 \to d_1; \dots; x_n \to d_n)$. All that three approaches are implemented by "list", "numbered", and "labeled" versions of polynomials and polynomial spaces respectively. Whereas all rational functions are represented as fractions with corresponding polynomial numerator and denominator, and rational functions' spaces are implemented in the same way as usual field of rational numbers (or more precisely, as any field of fractions over integral domain) should be implemented. From ed634013f67b71002919ef43a75555f1623d1945 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 27 Jun 2022 17:07:33 +0300 Subject: [PATCH 097/174] Removed extra suppresses. --- .../kmath/functions/LabeledPolynomial.kt | 2 -- .../functions/LabeledRationalFunction.kt | 6 ----- .../kmath/functions/ListPolynomial.kt | 7 ------ .../kmath/functions/ListRationalFunction.kt | 16 ------------- .../functions/NumberedRationalFunction.kt | 24 ------------------- .../kmath/functions/labeledConstructors.kt | 6 +---- .../kmath/functions/numberedConstructors.kt | 6 +---- 7 files changed, 2 insertions(+), 65 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 061325b60..f1859ac4b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -610,12 +610,10 @@ public class LabeledPolynomialSpace>( /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun LabeledPolynomial.substitute(arguments: Map): LabeledPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun LabeledPolynomial.substitute(arguments: Map>) : LabeledPolynomial = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index b1d0dd4d9..c34d1e46f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -62,35 +62,29 @@ public class LabeledRationalFunctionSpace>( /** * Substitutes provided constant [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun LabeledPolynomial.substitute(argument: Map): LabeledPolynomial = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun LabeledPolynomial.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun LabeledRationalFunction.substitute(argument: Map): LabeledRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun LabeledRationalFunction.substitute(argument: Map>): LabeledRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 8db93cbb1..3f470d5e7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -346,39 +346,32 @@ public open class ListPolynomialSpace>( /** * Evaluates value of [this] polynomial on provided [argument]. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [argument]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided [argument]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 7434063f2..40c6745d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -55,83 +55,67 @@ public class ListRationalFunctionSpace> ( /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.substitute(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.substitute(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunction(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListPolynomial.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.asFunctionOfPolynomial(): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } /** * Represent [this] rational function as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun ListRationalFunction.asFunctionOfRationalFunction(): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) /** * Evaluates value of [this] polynomial on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListPolynomial.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListRationalFunction.invoke(argument: ListPolynomial): ListRationalFunction = substitute(ring, argument) /** * Evaluates value of [this] rational function on provided argument. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun ListRationalFunction.invoke(argument: ListRationalFunction): ListRationalFunction = substitute(ring, argument) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index e61d6c55e..97dffebe1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -113,135 +113,111 @@ public class NumberedRationalFunctionSpace> ( /** * Substitutes provided constant [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(argument: Map): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.substitute(argument: Map): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(argument: Map>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(argument: Buffer): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided polynomial [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedPolynomial = substitute(ring, argument) /** * Substitutes provided rational function [argument] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedPolynomial.substitute(argument: Buffer>): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided constant [argument] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.substitute(argument: Buffer): NumberedRationalFunction = substitute(ring, argument) /** * Substitutes provided polynomial [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided rational function [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substituteRationalFunction") public inline fun NumberedRationalFunction.substitute(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided constant [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = substituteFully(ring, arguments) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.asFunctionOfPolynomial(): (Buffer>) -> NumberedRationalFunction = asFunctionOfPolynomialOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedRationalFunction.asFunctionOfRationalFunction(): (Buffer>) -> NumberedRationalFunction = asFunctionOfRationalFunctionOver(ring) /** * Evaluates value of [this] polynomial on provided [arguments]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) /** * Substitutes provided [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokeRationalFunction") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) /** * Substitutes provided [arguments] into [this] rational function. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokeRationalFunction") public inline operator fun NumberedRationalFunction.invoke(arguments: Buffer>): NumberedRationalFunction = substitute(ring, arguments) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 7586b7012..f3fa32334 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName", "NOTHING_TO_INLINE") +@file:Suppress("FunctionName") package space.kscience.kmath.functions @@ -309,21 +309,18 @@ public class LabeledPolynomialTermSignatureBuilder { * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Symbol.pow(deg: UInt): Unit = this inPowerOf deg /** * Declares power of [this] variable of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Symbol.`in`(deg: UInt): Unit = this inPowerOf deg /** * Declares power of [this] variable of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Symbol.of(deg: UInt): Unit = this inPowerOf deg } @@ -370,7 +367,6 @@ public class LabeledPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 3cd398623..0a0e6d902 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName", "NOTHING_TO_INLINE") +@file:Suppress("FunctionName") package space.kscience.kmath.functions @@ -296,21 +296,18 @@ public class NumberedPolynomialTermSignatureBuilder { * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Int.pow(deg: UInt): Unit = this inPowerOf deg /** * Declares power of variable #[this] of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Int.`in`(deg: UInt): Unit = this inPowerOf deg /** * Declares power of variable #[this] of degree [deg]. * * Declaring another power of the same variable will increase its degree by received degree. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun Int.of(deg: UInt): Unit = this inPowerOf deg } @@ -358,7 +355,6 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - @Suppress("NOTHING_TO_INLINE") public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. From 0ef2258665d3571b67a48933b43f0896b0ca80df Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 27 Jun 2022 17:11:39 +0300 Subject: [PATCH 098/174] Removed extra suppresses. --- .../kscience/kmath/functions/NumberedPolynomial.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index eadeb68ab..8bcfbae5b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -385,56 +385,46 @@ public class NumberedPolynomialSpace>( /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(arguments: Map): NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(arguments: Map>) : NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substitute(arguments: Buffer): NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("substitutePolynomial") public inline fun NumberedPolynomial.substitute(arguments: Buffer>) : NumberedPolynomial = substitute(ring, arguments) /** * Substitutes provided arguments [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.substituteFully(arguments: Buffer): C = this.substituteFully(ring, arguments) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunction(): (Buffer) -> C = asFunctionOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfConstant(): (Buffer) -> C = asFunctionOfConstantOver(ring) /** * Represent [this] polynomial as a regular context-less function. */ - @Suppress("NOTHING_TO_INLINE") public inline fun NumberedPolynomial.asFunctionOfPolynomial(): (Buffer>) -> NumberedPolynomial = asFunctionOfPolynomialOver(ring) /** * Evaluates value of [this] polynomial on provided [arguments]. */ - @Suppress("NOTHING_TO_INLINE") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer): C = substituteFully(ring, arguments) /** * Substitutes provided [arguments] into [this] polynomial. */ - @Suppress("NOTHING_TO_INLINE") @JvmName("invokePolynomial") public inline operator fun NumberedPolynomial.invoke(arguments: Buffer>): NumberedPolynomial = substitute(ring, arguments) } \ No newline at end of file From 043d292eca11f5ffea1ceb0f507a0bd101dbb399 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 27 Jun 2022 17:14:03 +0300 Subject: [PATCH 099/174] Added test. Fixed bug in NumberedPolynomial's DSL. --- .../kmath/functions/NumberedPolynomial.kt | 12 +- .../kmath/functions/numberedConstructors.kt | 1 + .../functions/NumberedConstructorsTest.kt | 20 +- .../kmath/functions/NumberedPolynomialTest.kt | 304 +++++++++++++++++- 4 files changed, 324 insertions(+), 13 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 8bcfbae5b..35d0c7448 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -331,13 +331,13 @@ public class NumberedPolynomialSpace>( * the result is `-1`. */ public val NumberedPolynomial.lastVariable: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.lastIndex } ?: -1 + get() = coefficients.keys.maxOfOrNull { degs -> degs.lastIndex } ?: -1 /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ override val NumberedPolynomial.degree: Int - get() = coefficients.entries.maxOfOrNull { (degs, _) -> degs.sum().toInt() } ?: -1 + get() = coefficients.keys.maxOfOrNull { degs -> degs.sum().toInt() } ?: -1 /** * List that associates indices of variables (that appear in the polynomial in positive exponents) with their most * exponents in which the variables are appeared in the polynomial. @@ -348,7 +348,7 @@ public class NumberedPolynomialSpace>( public val NumberedPolynomial.degrees: List get() = MutableList(lastVariable + 1) { 0u }.apply { - coefficients.entries.forEach { (degs, _) -> + coefficients.keys.forEach { degs -> degs.forEachIndexed { index, deg -> this[index] = max(this[index], deg) } @@ -358,13 +358,13 @@ public class NumberedPolynomialSpace>( * Counts degree of the polynomial by the specified [variable]. */ public fun NumberedPolynomial.degreeBy(variable: Int): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> degs.getOrElse(variable) { 0u } } ?: 0u + coefficients.keys.maxOfOrNull { degs -> degs.getOrElse(variable) { 0u } } ?: 0u /** * Counts degree of the polynomial by the specified [variables]. */ public fun NumberedPolynomial.degreeBy(variables: Collection): UInt = - coefficients.entries.maxOfOrNull { (degs, _) -> - degs.withIndex().filter { (index, _) -> index in variables }.sumOf { it.value } + coefficients.keys.maxOfOrNull { degs -> + degs.withIndex().fold(0u) { acc, (index, value) -> if (index in variables) acc + value else acc } } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 0a0e6d902..d561e06ba 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -283,6 +283,7 @@ public class NumberedPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Int.inPowerOf(deg: UInt) { + if (deg == 0u) return val index = this - 1 if (index > signature.lastIndex) { signature.addAll(List(index - signature.lastIndex - 1) { 0u }) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index 14493aaae..8d1b128cf 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -23,8 +23,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomial { - 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } - (-6) { 2 inPowerOf 1u } + 5 { 1 pow 2u; 3 pow 3u } + (-6) { 2 pow 1u } } }, "test 1" @@ -47,8 +47,20 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomial { - 5 { 1 inPowerOf 1u; 1 inPowerOf 1u } - (-6) { 1 inPowerOf 2u } + 5 { 1 pow 1u; 1 pow 1u } + (-6) { 1 pow 2u } + } + }, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to -1, + ), + Int.algebra.numberedPolynomialSpace { + NumberedPolynomial { + 5 { 1 pow 1u; 1 pow 1u } + (-6) { 1 pow 2u; 3 pow 0u } } }, "test 3" diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index 537e3b85d..223ff5d92 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -9,9 +9,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.* -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertSame +import kotlin.test.* @UnstableKMathAPI @@ -1365,4 +1363,304 @@ class NumberedPolynomialTest { ) } } + @Test + fun test_lastVariable() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + -1, + NumberedPolynomial {}.lastVariable, + "test 1" + ) + assertEquals( + -1, + NumberedPolynomial { + o {} + }.lastVariable, + "test 2" + ) + assertEquals( + 2, + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.lastVariable, + "test 3" + ) + assertEquals( + 3, + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.also { println(it) }.lastVariable, + "test 4" + ) + assertEquals( + 2, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.lastVariable, + "test 5" + ) + } + } + @Test + fun test_degree() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + -1, + NumberedPolynomial {}.degree, + "test 1" + ) + assertEquals( + 0, + NumberedPolynomial { + o {} + }.degree, + "test 2" + ) + assertEquals( + 6, + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.degree, + "test 3" + ) + assertEquals( + 4, + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.degree, + "test 4" + ) + assertEquals( + 3, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.degree, + "test 5" + ) + assertEquals( + 4, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.degree, + "test 6" + ) + } + } + @Test + fun test_countOfVariables() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + listOf(), + NumberedPolynomial {}.degrees, + "test 1" + ) + assertEquals( + listOf(), + NumberedPolynomial { + o {} + }.degrees, + "test 2" + ) + assertEquals( + listOf(1u, 2u, 3u), + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.degrees, + "test 3" + ) + assertEquals( + listOf(0u, 1u, 2u, 1u), + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.degrees, + "test 4" + ) + assertEquals( + listOf(2u, 1u, 1u), + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.degrees, + "test 5" + ) + assertEquals( + listOf(2u, 2u, 2u, 4u), + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.degrees, + "test 6" + ) + } + } + @Test + fun test_degreeBy() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + fun NumberedPolynomial.collectDegrees(limit: Int = lastVariable + 2): List = List(limit) { degreeBy(it) } + assertEquals( + listOf(0u), + NumberedPolynomial {}.collectDegrees(), + "test 1" + ) + assertEquals( + listOf(0u), + NumberedPolynomial { + o {} + }.collectDegrees(), + "test 2" + ) + assertEquals( + listOf(1u, 2u, 3u, 0u), + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.collectDegrees(), + "test 3" + ) + assertEquals( + listOf(0u, 1u, 2u, 1u, 0u), + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.collectDegrees(), + "test 4" + ) + assertEquals( + listOf(2u, 1u, 1u, 0u), + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.collectDegrees(), + "test 5" + ) + assertEquals( + listOf(2u, 2u, 2u, 4u, 0u), + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.collectDegrees(), + "test 6" + ) + } + } + @Test + fun test_degreeBy_Collection() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + fun NumberedPolynomial.checkDegreeBy(message: String? = null) { + val lastVariable = lastVariable + val indexCollectionSequence: Sequence> = sequence { + val appearances = MutableList(lastVariable + 2) { 0 } + while (true) { + yield( + buildList { + for ((variable, count) in appearances.withIndex()) repeat(count) { add(variable) } + } + ) + val indexChange = appearances.indexOfFirst { it < 4 } + if (indexChange == -1) break + appearances[indexChange] += 1 + for (index in 0 until indexChange) appearances[index] = 0 + } + } + for (indexCollection in indexCollectionSequence) { + val expected = coefficients.keys.maxOfOrNull { degs -> degs.slice(indexCollection.distinct().filter { it in degs.indices }).sum() } ?: 0u + val actual = degreeBy(indexCollection) + if (actual != expected) + fail("${message ?: ""} Incorrect answer for variable collection $indexCollection: expected $expected, actual $actual") + } + } + NumberedPolynomial {}.checkDegreeBy("test 1") + NumberedPolynomial { + o {} + }.checkDegreeBy("test 2") + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.checkDegreeBy("test 3") + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.checkDegreeBy("test 4") + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.checkDegreeBy("test 5") + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.checkDegreeBy("test 6") + } + } + @Test + fun test_degrees() { + val o = Rational(0) + RationalField.numberedPolynomialSpace { + assertEquals( + 0, + NumberedPolynomial {}.countOfVariables, + "test 1" + ) + assertEquals( + 0, + NumberedPolynomial { + o {} + }.countOfVariables, + "test 2" + ) + assertEquals( + 3, + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + }.countOfVariables, + "test 3" + ) + assertEquals( + 3, + NumberedPolynomial { + o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } + }.countOfVariables, + "test 4" + ) + assertEquals( + 3, + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + }.countOfVariables, + "test 5" + ) + assertEquals( + 4, + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 2 pow 1u; 3 pow 2u } + o { 1 pow 2u; 3 pow 1u } + o { 4 pow 4u } + }.countOfVariables, + "test 6" + ) + } + } } \ No newline at end of file From da46ea923c52c586cb9351d922281df6f1f36bf4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 28 Jun 2022 15:07:09 +0300 Subject: [PATCH 100/174] Extended test for NumberedPolynomial --- .../kmath/functions/NumberedPolynomialTest.kt | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index 223ff5d92..dac7c1a62 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -1456,7 +1456,7 @@ class NumberedPolynomialTest { } } @Test - fun test_countOfVariables() { + fun test_degrees() { val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( @@ -1612,7 +1612,7 @@ class NumberedPolynomialTest { } } @Test - fun test_degrees() { + fun test_countOfVariables() { val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( @@ -1663,4 +1663,80 @@ class NumberedPolynomialTest { ) } } + @Test + fun test_RF_countOfVariables() { + val o = Rational(0) + RationalField.numberedRationalFunctionSpace { + assertEquals( + 0, + NumberedRationalFunction( + NumberedPolynomial {} + ).countOfVariables, + "test 1" + ) + assertEquals( + 0, + NumberedRationalFunction( + NumberedPolynomial {}, + NumberedPolynomial {} + ).countOfVariables, + "test 2" + ) + assertEquals( + 0, + NumberedRationalFunction( + NumberedPolynomial { + o {} + } + ).countOfVariables, + "test 3" + ) + assertEquals( + 3, + NumberedRationalFunction( + NumberedPolynomial { + o { 1 pow 1u; 2 pow 2u; 3 pow 3u } + } + ).countOfVariables, + "test 4" + ) + assertEquals( + 3, + NumberedRationalFunction( + NumberedPolynomial { + o { 2 pow 1u; 4 pow 1u } + }, + NumberedPolynomial { + o { 1 pow 0u; 3 pow 2u; 5 pow 0u } + } + ).countOfVariables, + "test 5" + ) + assertEquals( + 3, + NumberedRationalFunction( + NumberedPolynomial { + o {} + o { 2 pow 1u } + o { 1 pow 2u; 3 pow 1u } + } + ).countOfVariables, + "test 6" + ) + assertEquals( + 4, + NumberedRationalFunction( + NumberedPolynomial { + o {} + o { 1 pow 1u; 2 pow 2u } + o { 1 pow 2u; 3 pow 1u } + }, NumberedPolynomial { + o { 2 pow 1u; 3 pow 2u } + o { 4 pow 4u } + } + ).countOfVariables, + "test 7" + ) + } + } } \ No newline at end of file From 64b33aed184e0f52a4f2938022cf6e0eae0e8591 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 29 Jun 2022 14:53:12 +0300 Subject: [PATCH 101/174] Remove extra suppresses. --- .../kotlin/space/kscience/kmath/test/misc/IntModulo.kt | 2 +- .../kotlin/space/kscience/kmath/test/misc/Rational.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index afd2b5add..b3bb4faf7 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -108,7 +108,7 @@ class IntModulo { override fun toString(): String = "$residue mod $modulus" } -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") class IntModuloRing : Ring { val modulus: Int diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt index 72bb5942c..4bdd60704 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -114,7 +114,7 @@ class Rational { override fun toString(): String = if (denominator == 1L) "$numerator" else "$numerator/$denominator" } -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO From c8b9951f46c27f7af85f43188af9eb9d6e3cb48d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 29 Jun 2022 14:54:49 +0300 Subject: [PATCH 102/174] Added for list utilities for rational functions. --- .../kmath/functions/ListPolynomialUtilTest.kt | 725 +++++++++++++++++- 1 file changed, 718 insertions(+), 7 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 69c1611f3..314044ba8 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -16,7 +17,7 @@ import kotlin.test.assertFailsWith @OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test - fun test_substitute_Double() { + fun test_Polynomial_substitute_Double() { assertEquals( 0.0, ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), @@ -49,7 +50,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_substitute_Constant() { + fun test_Polynomial_substitute_Constant() { assertEquals( Rational(0), ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), @@ -81,7 +82,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_substitute_Polynomial() { + fun test_Polynomial_substitute_Polynomial() { assertEquals( ListPolynomial(Rational(0)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), @@ -119,7 +120,717 @@ class ListPolynomialUtilTest { ) } @Test - fun test_derivative() { + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction() { + assertEquals( + ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), + ListPolynomial(Rational(1), Rational(-2), Rational(1)) + .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(66349, 243), + Rational(-17873, 405), + Rational(173533, 3780), + Rational(-91141, 567), + Rational(5773909, 105840), + Rational(-23243, 630), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(-130, 27), + Rational(115, 18), + Rational(-797, 54), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(-14, 9), + Rational(31, 14), + Rational(-5077, 980), + Rational(99, 35) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(25, 9), + Rational(-25, 6), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(0), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(0), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-898, 27), + Rational(271, 45), + Rational(-65, 12) , + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(5, 3), + Rational(-5, 4) , + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(0) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(56872, 243), + Rational(0, 1), + Rational(-90, 7), + Rational(-3718, 81), + Rational(9, 49), + Rational(0, 1), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(0, 1), + Rational(0, 1), + Rational(-286, 27), + Rational(0, 1), + Rational(0, 1), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(0), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(0), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(0), + Rational(0), + Rational(11, 3) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Double() { + assertEquals( + 0.0, + ListRationalFunction( + ListPolynomial(1.0, -2.0, 1.0), + ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) + ).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 2.693702616649797, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 2" + ) + assertEquals( + 2.692226268901378, + ListRationalFunction( + ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 3" + ) + assertEquals( + -0.7394904842099175, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) + ).substitute(-7.53452770353279), + 0.001, + "test 4" + ) + assertEquals( + 3.526835209398159, + ListRationalFunction( + ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), + ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Constant() { + assertEquals( + Rational(0), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(1149615, 61306), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 2" + ) + assertEquals( + Rational(3495, 586), + ListRationalFunction( + ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 3" + ) + assertEquals( + Rational(-88605, 77392), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), + ).substitute(RationalField, Rational(-7, 8)), + "test 4" + ) + assertEquals( + Rational(116145, 3794), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Polynomial() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-283303, 36), + Rational(-23593, 24), + Rational(368713, 192), + Rational(1455, 8), + Rational(-272171, 1536), + Rational(-2149, 192), + Rational(469, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(5797, 12), + Rational(595, 16), + Rational(-5285, 72), + Rational(-745, 192), + Rational(1105, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(-11, 12), + Rational(325, 192), + Rational(21, 32), + Rational(-1739, 1536), + Rational(227, 192), + Rational(-59, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(0, 1), + Rational(15, 16), + Rational(-265, 144), + Rational(-25, 192), + Rational(25, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(0, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(0, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(149723, 36), + Rational(8483, 24), + Rational(639, 64), + Rational(3, 32), + Rational(0), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(937, 12), + Rational(55, 16), + Rational(5, 144), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(0) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(0) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(0) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-216509, 18), + Rational(0, 1), + Rational(2673, 1), + Rational(0, 1), + Rational(-891, 4), + Rational(0, 1), + Rational(33, 4), + Rational(0, 1), + Rational(-11, 96) + ), + ListPolynomial( + Rational(1213, 3), + Rational(0, 1), + Rational(-135, 2), + Rational(0, 1), + Rational(15, 4), + Rational(0, 1), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(0), + Rational(0), + Rational(0), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(0), + Rational(0), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(0), + Rational(2, 4) + ) + ), + "test 5" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(1)) + ) + ), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(130087, 3888), + Rational(-2866333, 65610), + Rational(-5076229, 97200), + Rational(222136997, 3280500), + Rational(754719329, 20995200), + Rational(-12010283, 324000), + Rational(-2011967, 172800), + Rational(18607, 2880), + Rational(4705, 4096) + ), + ListPolynomial( + Rational(-143820355, 3779136), + Rational(73886869, 1574640), + Rational(1440175193, 15746400), + Rational(-5308968857, 52488000), + Rational(-186910083731, 2099520000), + Rational(125043463, 1555200), + Rational(5299123, 388800), + Rational(-213757, 15360), + Rational(1380785, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(5173, 18225), + Rational(904291, 364500), + Rational(283127, 43200), + Rational(37189, 5760), + Rational(147, 128) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(-163589, 911250), + Rational(-881831, 291600), + Rational(-10722229, 777600), + Rational(-640921, 46080), + Rational(86303, 9216) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(0), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(0), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(445, 16), + Rational(-2011, 54), + Rational(1359199, 72900), + Rational(-135733, 32805), + Rational(2254, 6561), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ), + ListPolynomial( + Rational(-2018387, 46656), + Rational(82316437, 1574640), + Rational(-9335047, 393660), + Rational(15765889, 3280500), + Rational(-242089, 656100), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(0) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(0) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(0) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(41635, 3888), + Rational(0, 1), + Rational(-279187, 11664), + Rational(0, 1), + Rational(103769, 3456), + Rational(0, 1), + Rational(-11017, 768), + Rational(0, 1), + Rational(4097, 4096) + ), + ListPolynomial( + Rational(-13811791, 3779136), + Rational(0, 1), + Rational(-9999395, 419904), + Rational(0, 1), + Rational(6376601, 124416), + Rational(0, 1), + Rational(-3668315, 82944), + Rational(0, 1), + Rational(2097089, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(0), + Rational(0), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(0), + Rational(0), + Rational(0), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(0), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(0), + Rational(1, 8) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_Polynomial_derivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), @@ -142,7 +853,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_nthDerivative() { + fun test_Polynomial_nthDerivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), @@ -188,7 +899,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_antiderivative() { + fun test_Polynomial_antiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), @@ -211,7 +922,7 @@ class ListPolynomialUtilTest { ) } @Test - fun test_nthAntiderivative() { + fun test_Polynomial_nthAntiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), From f147636e9d0402dd4c4d3b4c0e73e8a0c12a4d57 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 1 Jul 2022 14:46:05 +0300 Subject: [PATCH 103/174] Tests generation for numbered utilities in progress. --- .../space/kscience/kmath/functions/misc.kt | 4 +- .../functions/NumberedPolynomialUtilTest.kt | 2113 ++++++++++++++++- 2 files changed, 2074 insertions(+), 43 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index aba246519..76f1c294e 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -17,6 +17,6 @@ package space.kscience.kmath.functions "But at the same time makes it easy to make a mistake " + "that will cause wrong computation result or even runtime error. " + "Make sure you fully read and understand documentation.", - level = RequiresOptIn.Level.WARNING + level = RequiresOptIn.Level.ERROR ) -internal annotation class DelicatePolynomialAPI \ No newline at end of file +public annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index ecad6198e..8ece66145 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -8,13 +8,14 @@ package space.kscience.kmath.functions import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.test.misc.assertContentEquals +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals class NumberedPolynomialUtilTest { @Test - fun test_substitute_Double_Map() { + fun test_Polynomial_substitute_Double_Map() { assertContentEquals( mapOf(emptyList() to 0.0), NumberedPolynomialAsIs( @@ -53,6 +54,34 @@ class NumberedPolynomialUtilTest { 0.001, "test 2" ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 2'" + ) assertContentEquals( mapOf( listOf() to 0.8597048543814783, @@ -75,6 +104,29 @@ class NumberedPolynomialUtilTest { 0.001, "test 3" ) + assertContentEquals( + mapOf( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 0 to 0.0, + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 3'" + ) assertContentEquals( mapOf( listOf() to 1.433510890645169, @@ -97,6 +149,29 @@ class NumberedPolynomialUtilTest { 0.001, "test 4" ) + assertContentEquals( + mapOf( + listOf() to 1.433510890645169, + listOf(1u) to 0.6264844682514724, + listOf(2u) to 0.8405727903771333, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(mapOf( + 1 to 0.8400458576651112, + 5 to 0.9211194782050933 + )).coefficients, + 0.001, + "test 4'" + ) assertContentEquals( mapOf( listOf() to 1.934530767358133, @@ -120,15 +195,7 @@ class NumberedPolynomialUtilTest { ) assertContentEquals( mapOf( - listOf() to 0.8597048543814783, - listOf(1u) to 0.22997637465889875, - listOf(2u) to 0.32675302591924016, - listOf(0u, 1u) to 0.4561746111587508, - listOf(1u, 1u) to 0.5304946210170756, - listOf(2u, 1u) to 0.6244313712888998, - listOf(0u, 2u) to 0.2700930201481795, - listOf(1u, 2u) to -0.06962351375204712, - listOf(2u, 2u) to -0.015206988092131501, + listOf() to 1.934530767358133, ), NumberedPolynomialAsIs( listOf() to 0.8597048543814783, @@ -141,14 +208,16 @@ class NumberedPolynomialUtilTest { listOf(1u, 2u) to -0.06962351375204712, listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( + 0 to 0.4846192734143442, + 1 to 0.8400458576651112, 5 to 0.9211194782050933 )).coefficients, 0.001, - "test 6" + "test 5'" ) } @Test - fun test_substitute_Constant() { + fun test_Polynomial_substitute_Constant_Map() { assertEquals( NumberedPolynomialAsIs( listOf() to Rational(0) @@ -183,6 +252,167 @@ class NumberedPolynomialUtilTest { )), "test 2" ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 1 to Rational(12, 9), + 5 to Rational(57, 179), + )), + "test 2'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-67, 18), + listOf(1u) to Rational(-70, 9), + listOf(2u) to Rational(88, 9), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to Rational(12, 9), + )), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-67, 18), + listOf(1u) to Rational(-70, 9), + listOf(2u) to Rational(88, 9), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to Rational(12, 9), + 5 to Rational(57, 179), + )), + "test 3'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-83, 50), + listOf(0u, 1u) to Rational(29, 25), + listOf(0u, 2u) to Rational(3, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + )), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-83, 50), + listOf(0u, 1u) to Rational(29, 25), + listOf(0u, 2u) to Rational(3, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to Rational(-2, 5), + 5 to Rational(57, 179), + )), + "test 4'" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 5 to Rational(57, 179), + )), + "test 5'" + ) // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 assertEquals( NumberedPolynomialAsIs( @@ -202,37 +432,11 @@ class NumberedPolynomialUtilTest { 0 to Rational(-2, 5), 1 to Rational(12, 9), )), - "test 3" - ) - // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 - assertEquals( - NumberedPolynomialAsIs( - listOf(8u) to Rational(-3, 2), - listOf(7u, 1u) to Rational(8, 6), - listOf(6u, 2u) to Rational(14, 6), - listOf(5u, 3u) to Rational(-3, 1), - listOf(4u, 4u) to Rational(-19, 2), - listOf(3u, 5u) to Rational(9, 4), - listOf(2u, 6u) to Rational(5, 5), - listOf(1u, 7u) to Rational(18, 9), - listOf(0u, 8u) to Rational(5, 2), - ), - NumberedPolynomialAsIs( - listOf(8u) to Rational(-3, 2), - listOf(7u, 1u) to Rational(8, 6), - listOf(6u, 2u) to Rational(14, 6), - listOf(5u, 3u) to Rational(-3, 1), - listOf(4u, 4u) to Rational(-19, 2), - listOf(3u, 5u) to Rational(9, 4), - listOf(2u, 6u) to Rational(5, 5), - listOf(1u, 7u) to Rational(18, 9), - listOf(0u, 8u) to Rational(5, 2), - ).substitute(RationalField, mapOf()), - "test 4" + "test 6" ) } @Test - fun test_substitute_Polynomial() { + fun test_Polynomial_substitute_Polynomial_Map() { assertEquals( NumberedPolynomialAsIs( listOf() to Rational(0) @@ -248,7 +452,7 @@ class NumberedPolynomialUtilTest { )), "test 1" ) - // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-5%2F1+s+%2B+2%2F8+t%2C+y+%3D+11%2F7+t assertEquals( NumberedPolynomialAsIs( listOf() to Rational(-3, 2), @@ -289,5 +493,1832 @@ class NumberedPolynomialUtilTest { )), "test 2" ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + )), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 3'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = s, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(6817, 84), + listOf(2u) to Rational(-21445, 294), + listOf(3u) to Rational(-12151, 49), + listOf(4u) to Rational(-17789, 196), + listOf(5u) to Rational(1224, 7), + listOf(6u) to Rational(405, 2), + listOf(0u, 1u) to Rational(-156), + listOf(1u, 1u) to Rational(-2440, 7), + listOf(2u, 1u) to Rational(-1571, 112), + listOf(3u, 1u) to Rational(107515, 224), + listOf(4u, 1u) to Rational(64965, 112), + listOf(5u, 1u) to Rational(209, 56), + listOf(6u, 1u) to Rational(45, 4), + listOf(0u, 2u) to Rational(112), + listOf(1u, 2u) to Rational(1449, 8), + listOf(2u, 2u) to Rational(1306309, 3136), + listOf(3u, 2u) to Rational(483207, 1568), + listOf(4u, 2u) to Rational(1978437, 6272), + listOf(5u, 2u) to Rational(-18231, 224), + listOf(6u, 2u) to Rational(-6835, 32), + listOf(0u, 3u) to Rational(247, 2), + listOf(1u, 3u) to Rational(33771, 112), + listOf(2u, 3u) to Rational(2073, 7), + listOf(3u, 3u) to Rational(-23463, 224), + listOf(4u, 3u) to Rational(-33825, 112), + listOf(5u, 3u) to Rational(201, 224), + listOf(6u, 3u) to Rational(-95, 16), + listOf(0u, 4u) to Rational(361, 16), + listOf(1u, 4u) to Rational(3667, 56), + listOf(2u, 4u) to Rational(88729, 1568), + listOf(3u, 4u) to Rational(-2476, 49), + listOf(4u, 4u) to Rational(-23419, 196), + listOf(5u, 4u) to Rational(-323, 56), + listOf(6u, 4u) to Rational(1805, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + )), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(6817, 84), + listOf(2u) to Rational(-21445, 294), + listOf(3u) to Rational(-12151, 49), + listOf(4u) to Rational(-17789, 196), + listOf(5u) to Rational(1224, 7), + listOf(6u) to Rational(405, 2), + listOf(0u, 1u) to Rational(-156), + listOf(1u, 1u) to Rational(-2440, 7), + listOf(2u, 1u) to Rational(-1571, 112), + listOf(3u, 1u) to Rational(107515, 224), + listOf(4u, 1u) to Rational(64965, 112), + listOf(5u, 1u) to Rational(209, 56), + listOf(6u, 1u) to Rational(45, 4), + listOf(0u, 2u) to Rational(112), + listOf(1u, 2u) to Rational(1449, 8), + listOf(2u, 2u) to Rational(1306309, 3136), + listOf(3u, 2u) to Rational(483207, 1568), + listOf(4u, 2u) to Rational(1978437, 6272), + listOf(5u, 2u) to Rational(-18231, 224), + listOf(6u, 2u) to Rational(-6835, 32), + listOf(0u, 3u) to Rational(247, 2), + listOf(1u, 3u) to Rational(33771, 112), + listOf(2u, 3u) to Rational(2073, 7), + listOf(3u, 3u) to Rational(-23463, 224), + listOf(4u, 3u) to Rational(-33825, 112), + listOf(5u, 3u) to Rational(201, 224), + listOf(6u, 3u) to Rational(-95, 16), + listOf(0u, 4u) to Rational(361, 16), + listOf(1u, 4u) to Rational(3667, 56), + listOf(2u, 4u) to Rational(88729, 1568), + listOf(3u, 4u) to Rational(-2476, 49), + listOf(4u, 4u) to Rational(-23419, 196), + listOf(5u, 4u) to Rational(-323, 56), + listOf(6u, 4u) to Rational(1805, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 4'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = t + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(7, 3), + listOf(2u) to Rational(-35, 16), + listOf(3u) to Rational(-343, 6), + listOf(4u) to Rational(343, 3), + listOf(0u, 1u) to Rational(-19, 5), + listOf(1u, 1u) to Rational(-823, 120), + listOf(2u, 1u) to Rational(1232417, 6720), + listOf(3u, 1u) to Rational(-9863, 24), + listOf(4u, 1u) to Rational(385, 4), + listOf(0u, 2u) to Rational(2439, 350), + listOf(1u, 2u) to Rational(-5793, 40), + listOf(2u, 2u) to Rational(1172113, 3360), + listOf(3u, 2u) to Rational(-13531, 40), + listOf(4u, 2u) to Rational(2824, 7), + listOf(0u, 3u) to Rational(3417, 700), + listOf(1u, 3u) to Rational(1191, 200), + listOf(2u, 3u) to Rational(8383, 28), + listOf(3u, 3u) to Rational(-220279, 280), + listOf(4u, 3u) to Rational(49179, 196), + listOf(0u, 4u) to Rational(57, 35), + listOf(1u, 4u) to Rational(-33771, 700), + listOf(2u, 4u) to Rational(196279, 1225), + listOf(3u, 4u) to Rational(-32259, 140), + listOf(4u, 4u) to Rational(23868, 49), + listOf(0u, 5u) to Rational(333, 196), + listOf(1u, 5u) to Rational(-204, 35), + listOf(2u, 5u) to Rational(-307233, 2450), + listOf(3u, 5u) to Rational(-12492, 35), + listOf(4u, 5u) to Rational(4563, 28), + listOf(0u, 6u) to Rational(45, 98), + listOf(1u, 6u) to Rational(54, 7), + listOf(2u, 6u) to Rational(1809, 35), + listOf(3u, 6u) to Rational(162), + listOf(4u, 6u) to Rational(405, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(7, 3), + listOf(2u) to Rational(-35, 16), + listOf(3u) to Rational(-343, 6), + listOf(4u) to Rational(343, 3), + listOf(0u, 1u) to Rational(-19, 5), + listOf(1u, 1u) to Rational(-823, 120), + listOf(2u, 1u) to Rational(1232417, 6720), + listOf(3u, 1u) to Rational(-9863, 24), + listOf(4u, 1u) to Rational(385, 4), + listOf(0u, 2u) to Rational(2439, 350), + listOf(1u, 2u) to Rational(-5793, 40), + listOf(2u, 2u) to Rational(1172113, 3360), + listOf(3u, 2u) to Rational(-13531, 40), + listOf(4u, 2u) to Rational(2824, 7), + listOf(0u, 3u) to Rational(3417, 700), + listOf(1u, 3u) to Rational(1191, 200), + listOf(2u, 3u) to Rational(8383, 28), + listOf(3u, 3u) to Rational(-220279, 280), + listOf(4u, 3u) to Rational(49179, 196), + listOf(0u, 4u) to Rational(57, 35), + listOf(1u, 4u) to Rational(-33771, 700), + listOf(2u, 4u) to Rational(196279, 1225), + listOf(3u, 4u) to Rational(-32259, 140), + listOf(4u, 4u) to Rational(23868, 49), + listOf(0u, 5u) to Rational(333, 196), + listOf(1u, 5u) to Rational(-204, 35), + listOf(2u, 5u) to Rational(-307233, 2450), + listOf(3u, 5u) to Rational(-12492, 35), + listOf(4u, 5u) to Rational(4563, 28), + listOf(0u, 6u) to Rational(45, 98), + listOf(1u, 6u) to Rational(54, 7), + listOf(2u, 6u) to Rational(1809, 35), + listOf(3u, 6u) to Rational(162), + listOf(4u, 6u) to Rational(405, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 5'" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 6'" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction_Map() { + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-194071, 4900), + listOf(3u, 1u) to Rational(394811, 225), + listOf(2u, 2u) to Rational(-444183161, 66150), + listOf(1u, 3u) to Rational(70537618, 59535), + listOf(0u, 4u) to Rational(9655504, 2835), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(9, 1), + listOf(3u, 1u) to Rational(61, 1), + listOf(2u, 2u) to Rational(2137, 36), + listOf(1u, 3u) to Rational(-1342, 9), + listOf(0u, 4u) to Rational(484, 9), + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(17, 7), + listOf(0u, 1u) to Rational(-13, 1), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-18, 6), + listOf(0u, 1u) to Rational(11, 6), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(18, 5), + listOf(0u, 1u) to Rational(-16, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(-4, 1), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-66677, 3500), + listOf(1u) to Rational(-206281, 10500), + listOf(2u) to Rational(-412567, 7056), + listOf(3u) to Rational(-310081, 11025), + listOf(4u) to Rational(-575996, 15435), + listOf(0u, 1u) to Rational(-573701, 4200), + listOf(1u, 1u) to Rational(-2239001, 25200), + listOf(2u, 1u) to Rational(-8817889, 132300), + listOf(3u, 1u) to Rational(2317919, 44100), + listOf(4u, 1u) to Rational(1169471, 6615), + listOf(0u, 2u) to Rational(-4057819, 33600), + listOf(1u, 2u) to Rational(1373311, 12600), + listOf(2u, 2u) to Rational(32433493, 52920), + listOf(3u, 2u) to Rational(4998053, 33075), + listOf(4u, 2u) to Rational(-2147779, 8820), + listOf(0u, 3u) to Rational(2018481, 2240), + listOf(1u, 3u) to Rational(941713, 1440), + listOf(2u, 3u) to Rational(183749, 6615), + listOf(3u, 3u) to Rational(-4631023, 15876), + listOf(4u, 3u) to Rational(25609336, 178605), + listOf(0u, 4u) to Rational(11886431, 6720), + listOf(1u, 4u) to Rational(18433, 504), + listOf(2u, 4u) to Rational(-39613331, 45360), + listOf(3u, 4u) to Rational(681619, 5670), + listOf(4u, 4u) to Rational(-864841, 20412), + listOf(0u, 5u) to Rational(343535, 1008), + listOf(1u, 5u) to Rational(-33583, 72), + listOf(2u, 5u) to Rational(1194625, 9072), + listOf(3u, 5u) to Rational(-62917, 2268), + listOf(4u, 5u) to Rational(157645, 10206), + listOf(0u, 6u) to Rational(-1381, 3), + listOf(1u, 6u) to Rational(919, 36), + listOf(2u, 6u) to Rational(-3053, 36), + listOf(3u, 6u) to Rational(2125, 324), + listOf(4u, 6u) to Rational(-236, 243) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-66677, 3500), + listOf(1u) to Rational(-206281, 10500), + listOf(2u) to Rational(-412567, 7056), + listOf(3u) to Rational(-310081, 11025), + listOf(4u) to Rational(-575996, 15435), + listOf(0u, 1u) to Rational(-573701, 4200), + listOf(1u, 1u) to Rational(-2239001, 25200), + listOf(2u, 1u) to Rational(-8817889, 132300), + listOf(3u, 1u) to Rational(2317919, 44100), + listOf(4u, 1u) to Rational(1169471, 6615), + listOf(0u, 2u) to Rational(-4057819, 33600), + listOf(1u, 2u) to Rational(1373311, 12600), + listOf(2u, 2u) to Rational(32433493, 52920), + listOf(3u, 2u) to Rational(4998053, 33075), + listOf(4u, 2u) to Rational(-2147779, 8820), + listOf(0u, 3u) to Rational(2018481, 2240), + listOf(1u, 3u) to Rational(941713, 1440), + listOf(2u, 3u) to Rational(183749, 6615), + listOf(3u, 3u) to Rational(-4631023, 15876), + listOf(4u, 3u) to Rational(25609336, 178605), + listOf(0u, 4u) to Rational(11886431, 6720), + listOf(1u, 4u) to Rational(18433, 504), + listOf(2u, 4u) to Rational(-39613331, 45360), + listOf(3u, 4u) to Rational(681619, 5670), + listOf(4u, 4u) to Rational(-864841, 20412), + listOf(0u, 5u) to Rational(343535, 1008), + listOf(1u, 5u) to Rational(-33583, 72), + listOf(2u, 5u) to Rational(1194625, 9072), + listOf(3u, 5u) to Rational(-62917, 2268), + listOf(4u, 5u) to Rational(157645, 10206), + listOf(0u, 6u) to Rational(-1381, 3), + listOf(1u, 6u) to Rational(919, 36), + listOf(2u, 6u) to Rational(-3053, 36), + listOf(3u, 6u) to Rational(2125, 324), + listOf(4u, 6u) to Rational(-236, 243) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(3539, 700), + listOf(1u) to Rational(-307079, 6300), + listOf(2u) to Rational(451609, 15120), + listOf(3u) to Rational(35287733, 396900), + listOf(4u) to Rational(-37242617, 396900), + listOf(5u) to Rational(382747, 19845), + listOf(6u) to Rational(-2407, 3969), + listOf(0u, 1u) to Rational(-226, 175), + listOf(1u, 1u) to Rational(-74113, 1890), + listOf(2u, 1u) to Rational(250931, 1764), + listOf(3u, 1u) to Rational(30071473, 99225), + listOf(4u, 1u) to Rational(-286466, 1323), + listOf(5u, 1u) to Rational(-2285282, 9261), + listOf(6u, 1u) to Rational(17900, 441), + listOf(0u, 2u) to Rational(3817, 3150), + listOf(1u, 2u) to Rational(577568, 11025), + listOf(2u, 2u) to Rational(9073553, 99225), + listOf(3u, 2u) to Rational(-1415849, 79380), + listOf(4u, 2u) to Rational(-124715629, 277830), + listOf(5u, 2u) to Rational(-1328953, 1890), + listOf(6u, 2u) to Rational(-297148, 1323), + listOf(0u, 3u) to Rational(6043, 945), + listOf(1u, 3u) to Rational(160381, 6615), + listOf(2u, 3u) to Rational(-673249, 13230), + listOf(3u, 3u) to Rational(-319255, 2058), + listOf(4u, 3u) to Rational(-98144, 1029), + listOf(5u, 3u) to Rational(-320239, 5145), + listOf(6u, 3u) to Rational(400, 147), + listOf(0u, 4u) to Rational(163, 63), + listOf(1u, 4u) to Rational(-25183, 4410), + listOf(2u, 4u) to Rational(-21369, 1372), + listOf(3u, 4u) to Rational(127499, 30870), + listOf(4u, 4u) to Rational(86971, 12348), + listOf(5u, 4u) to Rational(-11129, 1470), + listOf(6u, 4u) to Rational(544, 147) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(3539, 700), + listOf(1u) to Rational(-307079, 6300), + listOf(2u) to Rational(451609, 15120), + listOf(3u) to Rational(35287733, 396900), + listOf(4u) to Rational(-37242617, 396900), + listOf(5u) to Rational(382747, 19845), + listOf(6u) to Rational(-2407, 3969), + listOf(0u, 1u) to Rational(-226, 175), + listOf(1u, 1u) to Rational(-74113, 1890), + listOf(2u, 1u) to Rational(250931, 1764), + listOf(3u, 1u) to Rational(30071473, 99225), + listOf(4u, 1u) to Rational(-286466, 1323), + listOf(5u, 1u) to Rational(-2285282, 9261), + listOf(6u, 1u) to Rational(17900, 441), + listOf(0u, 2u) to Rational(3817, 3150), + listOf(1u, 2u) to Rational(577568, 11025), + listOf(2u, 2u) to Rational(9073553, 99225), + listOf(3u, 2u) to Rational(-1415849, 79380), + listOf(4u, 2u) to Rational(-124715629, 277830), + listOf(5u, 2u) to Rational(-1328953, 1890), + listOf(6u, 2u) to Rational(-297148, 1323), + listOf(0u, 3u) to Rational(6043, 945), + listOf(1u, 3u) to Rational(160381, 6615), + listOf(2u, 3u) to Rational(-673249, 13230), + listOf(3u, 3u) to Rational(-319255, 2058), + listOf(4u, 3u) to Rational(-98144, 1029), + listOf(5u, 3u) to Rational(-320239, 5145), + listOf(6u, 3u) to Rational(400, 147), + listOf(0u, 4u) to Rational(163, 63), + listOf(1u, 4u) to Rational(-25183, 4410), + listOf(2u, 4u) to Rational(-21369, 1372), + listOf(3u, 4u) to Rational(127499, 30870), + listOf(4u, 4u) to Rational(86971, 12348), + listOf(5u, 4u) to Rational(-11129, 1470), + listOf(6u, 4u) to Rational(544, 147) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 5'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(0, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(0, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 6'" + ) + } + @Test + @Ignore + fun test_RationalFunction_substitute_Double_Map() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Constant_Map() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Polynomial_Map() { + // TODO + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction_Map() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substitute_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substitute_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substitute_Polynomial_Buffer() { + // TODO + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substitute_Polynomial_Buffer() { + // TODO + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substituteFully_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_substituteFully_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substituteFully_Double_Buffer() { + // TODO + } + @Test + @Ignore + fun test_RationalFunction_substituteFully_Constant_Buffer() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_derivativeWithRespectTo_variable() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthDerivativeWithRespectTo_variable_order() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthDerivativeWithRespectTo_variablesAndOrders() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_antiderivativeWithRespectTo_variable() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthAntiderivativeWithRespectTo_variable_order() { + // TODO + } + @Test + @Ignore + fun test_Polynomial_nthAntiderivativeWithRespectTo_variablesAndOrders() { + // TODO } } \ No newline at end of file From 672a3c1552332eb8530fbc71a50c72894ddd5073 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sun, 3 Jul 2022 15:47:12 +0300 Subject: [PATCH 104/174] Tests generation for numbered utilities in progress: finish map-wise substitutions. Also: - Upgrade operations on Rational. - Add new assertions. - Changed a bit FIXME comments. --- .../kmath/functions/ListPolynomialUtilTest.kt | 4 +- .../functions/NumberedPolynomialUtilTest.kt | 3248 ++++++++++++++++- .../kscience/kmath/test/misc/Rational.kt | 111 +- .../kscience/kmath/test/misc/assertion.kt | 34 + 4 files changed, 3321 insertions(+), 76 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 314044ba8..9d4f4411b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -121,7 +121,7 @@ class ListPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction() { assertEquals( @@ -589,7 +589,7 @@ class ListPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction() { assertEquals( diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 8ece66145..b6baed6af 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertContentEquals +import space.kscience.kmath.test.misc.assertEquals import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals @@ -16,20 +16,20 @@ import kotlin.test.assertEquals class NumberedPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double_Map() { - assertContentEquals( - mapOf(emptyList() to 0.0), + assertEquals( + NumberedPolynomialAsIs(emptyList() to 0.0), NumberedPolynomialAsIs( listOf() to 1.0, listOf(1u) to -2.0, listOf(2u) to 1.0, ).substitute(mapOf( 0 to 1.0 - )).coefficients, + )), 0.001, "test 1" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(1u) to 0.22997637465889875, listOf(2u) to 0.32675302591924016, @@ -50,12 +50,12 @@ class NumberedPolynomialUtilTest { listOf(0u, 2u) to 0.2700930201481795, listOf(1u, 2u) to -0.06962351375204712, listOf(2u, 2u) to -0.015206988092131501, - ).substitute(mapOf()).coefficients, + ).substitute(mapOf()), 0.001, "test 2" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(1u) to 0.22997637465889875, listOf(2u) to 0.32675302591924016, @@ -78,12 +78,12 @@ class NumberedPolynomialUtilTest { listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 2'" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(0u, 1u) to 0.4561746111587508, listOf(0u, 2u) to 0.2700930201481795, @@ -100,12 +100,12 @@ class NumberedPolynomialUtilTest { listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( 0 to 0.0 - )).coefficients, + )), 0.001, "test 3" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 0.8597048543814783, listOf(0u, 1u) to 0.4561746111587508, listOf(0u, 2u) to 0.2700930201481795, @@ -123,12 +123,12 @@ class NumberedPolynomialUtilTest { ).substitute(mapOf( 0 to 0.0, 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 3'" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.433510890645169, listOf(1u) to 0.6264844682514724, listOf(2u) to 0.8405727903771333, @@ -145,12 +145,12 @@ class NumberedPolynomialUtilTest { listOf(2u, 2u) to -0.015206988092131501, ).substitute(mapOf( 1 to 0.8400458576651112 - )).coefficients, + )), 0.001, "test 4" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.433510890645169, listOf(1u) to 0.6264844682514724, listOf(2u) to 0.8405727903771333, @@ -168,12 +168,12 @@ class NumberedPolynomialUtilTest { ).substitute(mapOf( 1 to 0.8400458576651112, 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 4'" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.934530767358133, ), NumberedPolynomialAsIs( @@ -189,12 +189,12 @@ class NumberedPolynomialUtilTest { ).substitute(mapOf( 0 to 0.4846192734143442, 1 to 0.8400458576651112, - )).coefficients, + )), 0.001, "test 5" ) - assertContentEquals( - mapOf( + assertEquals( + NumberedPolynomialAsIs( listOf() to 1.934530767358133, ), NumberedPolynomialAsIs( @@ -211,7 +211,7 @@ class NumberedPolynomialUtilTest { 0 to 0.4846192734143442, 1 to 0.8400458576651112, 5 to 0.9211194782050933 - )).coefficients, + )), 0.001, "test 5'" ) @@ -1086,7 +1086,7 @@ class NumberedPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction_Map() { assertEquals( @@ -2206,26 +2206,3198 @@ class NumberedPolynomialUtilTest { ) } @Test - @Ignore fun test_RationalFunction_substitute_Double_Map() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs(emptyList() to 0.0), + NumberedPolynomialAsIs(emptyList() to 1.0), + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ), + NumberedPolynomialAsIs( + listOf() to 1.0, + ) + ).substitute(mapOf( + 0 to 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf()), + 0.001, + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 5 to 0.9211194782050933 + )), + 0.001, + "test 2'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 151.1502229133916, + listOf(0u, 1u) to -262.3790170577034, + listOf(0u, 2u) to 102.5097937392923, + ), + NumberedPolynomialAsIs( + listOf() to -367.9969733169944, + listOf(0u, 1u) to 112.4911133334554, + listOf(0u, 2u) to -469.755906895345, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + )), + 0.001, + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 151.1502229133916, + listOf(0u, 1u) to -262.3790170577034, + listOf(0u, 2u) to 102.5097937392923, + ), + NumberedPolynomialAsIs( + listOf() to -367.9969733169944, + listOf(0u, 1u) to 112.4911133334554, + listOf(0u, 2u) to -469.755906895345, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + 5 to 0.9211194782050933 + )), + 0.001, + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 14.24074356896978, + listOf(1u) to -17.71987055153461, + listOf(2u) to -2.288056483312383, + ), + NumberedPolynomialAsIs( + listOf() to 7.480604285873397, + listOf(1u) to -8.43478016688617, + listOf(2u) to -9.88934943900592, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 1 to 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 14.24074356896978, + listOf(1u) to -17.71987055153461, + listOf(2u) to -2.288056483312383, + ), + NumberedPolynomialAsIs( + listOf() to 7.480604285873397, + listOf(1u) to -8.43478016688617, + listOf(2u) to -9.88934943900592, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 1 to 0.795265651276015, + 5 to 0.9211194782050933 + )), + 0.001, + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + 1 to 0.795265651276015, + )), + 0.001, + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + 0 to -8.11707689492641, + 1 to 0.795265651276015, + 5 to 0.9211194782050933 + )), + 0.001, + "test 5'" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Constant_Map() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + 0 to Rational(1) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + 1 to Rational(-13, 7), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + 1 to Rational(-13, 7), + 5 to Rational(-16, 4), + )), + "test 2'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(4191, 490), + listOf(1u) to Rational(14975, 1176), + listOf(2u) to Rational(-10429, 1176) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-775, 147), + listOf(1u) to Rational(-155, 49), + listOf(2u) to Rational(-757, 280) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 1 to Rational(-13, 7), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(4191, 490), + listOf(1u) to Rational(14975, 1176), + listOf(2u) to Rational(-10429, 1176) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-775, 147), + listOf(1u) to Rational(-155, 49), + listOf(2u) to Rational(-757, 280) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 1 to Rational(-13, 7), + 5 to Rational(-16, 4), + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-939, 200), + listOf(0u, 1u) to Rational(123, 50), + listOf(0u, 2u) to Rational(1059, 200) + ), + NumberedPolynomialAsIs( + listOf() to Rational(121, 25), + listOf(0u, 1u) to Rational(-949, 375), + listOf(0u, 2u) to Rational(-1423, 200) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-939, 200), + listOf(0u, 1u) to Rational(123, 50), + listOf(0u, 2u) to Rational(1059, 200) + ), + NumberedPolynomialAsIs( + listOf() to Rational(121, 25), + listOf(0u, 1u) to Rational(-949, 375), + listOf(0u, 2u) to Rational(-1423, 200) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 0 to Rational(7, 5), + 5 to Rational(-16, 4), + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + 5 to Rational(-16, 4), + )), + "test 5'" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Polynomial_Map() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(211, 4), + listOf(2u) to Rational(88, 3), + listOf(3u) to Rational(-63, 8), + listOf(4u) to Rational(441, 16), + listOf(0u, 1u) to Rational(-671, 15), + listOf(1u, 1u) to Rational(-551, 21), + listOf(2u, 1u) to Rational(279, 25), + listOf(3u, 1u) to Rational(231, 20), + listOf(0u, 2u) to Rational(-1436, 1575), + listOf(1u, 2u) to Rational(2471, 250), + listOf(2u, 2u) to Rational(-4919, 100), + listOf(0u, 3u) to Rational(-1464, 125), + listOf(1u, 3u) to Rational(-264, 25), + listOf(0u, 4u) to Rational(576, 25), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(-9, 4), + listOf(2u) to Rational(943, 8), + listOf(3u) to Rational(117, 8), + listOf(4u) to Rational(147, 16), + listOf(0u, 1u) to Rational(289, 90), + listOf(1u, 1u) to Rational(-2692, 15), + listOf(2u, 1u) to Rational(-1629, 140), + listOf(3u, 1u) to Rational(77, 20), + listOf(0u, 2u) to Rational(6187, 75), + listOf(1u, 2u) to Rational(-2879, 175), + listOf(2u, 2u) to Rational(-4919, 300), + listOf(0u, 3u) to Rational(336, 25), + listOf(1u, 3u) to Rational(-88, 25), + listOf(0u, 4u) to Rational(192, 25), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 2), + listOf(0u, 1u) to Rational(8, 5), + ), + 1 to NumberedPolynomialAsIs( + listOf(1u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-3, 1), + ) + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(493, 6), + listOf(1u) to Rational(-15991, 210), + listOf(2u) to Rational(2734, 63), + listOf(3u) to Rational(-8213, 245), + listOf(4u) to Rational(1843, 147), + listOf(5u) to Rational(-432, 245), + listOf(6u) to Rational(4, 49), + listOf(0u, 1u) to Rational(-66, 1), + listOf(1u, 1u) to Rational(-92924, 2205), + listOf(2u, 1u) to Rational(-257461, 2205), + listOf(3u, 1u) to Rational(58658, 2205), + listOf(4u, 1u) to Rational(-87884, 2205), + listOf(5u, 1u) to Rational(2726, 105), + listOf(6u, 1u) to Rational(-52, 21), + listOf(0u, 2u) to Rational(-17569, 147), + listOf(1u, 2u) to Rational(368819, 735), + listOf(2u, 2u) to Rational(-644626, 6615), + listOf(3u, 2u) to Rational(221738, 945), + listOf(4u, 2u) to Rational(-18022, 945), + listOf(5u, 2u) to Rational(-1201, 315), + listOf(6u, 2u) to Rational(1327, 63), + listOf(0u, 3u) to Rational(240, 7), + listOf(1u, 3u) to Rational(-868, 9), + listOf(2u, 3u) to Rational(-8936, 315), + listOf(3u, 3u) to Rational(-77146, 315), + listOf(4u, 3u) to Rational(-4072, 315), + listOf(5u, 3u) to Rational(-2218, 15), + listOf(6u, 3u) to Rational(-104, 3), + listOf(0u, 4u) to Rational(100, 3), + listOf(1u, 4u) to Rational(-725, 3), + listOf(2u, 4u) to Rational(459, 1), + listOf(3u, 4u) to Rational(-2071, 15), + listOf(4u, 4u) to Rational(2831, 15), + listOf(5u, 4u) to Rational(632, 5), + listOf(6u, 4u) to Rational(16, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1255, 9), + listOf(1u) to Rational(-24781, 126), + listOf(2u) to Rational(1195, 14), + listOf(3u) to Rational(-1931, 147), + listOf(4u) to Rational(439, 147), + listOf(5u) to Rational(-172, 343), + listOf(6u) to Rational(4, 147), + listOf(0u, 1u) to Rational(-183, 1), + listOf(1u, 1u) to Rational(-30988, 441), + listOf(2u, 1u) to Rational(-56137, 294), + listOf(3u, 1u) to Rational(204308, 1029), + listOf(4u, 1u) to Rational(-3263, 441), + listOf(5u, 1u) to Rational(2662, 441), + listOf(6u, 1u) to Rational(-52, 63), + listOf(0u, 2u) to Rational(-87119, 294), + listOf(1u, 2u) to Rational(1077919, 686), + listOf(2u, 2u) to Rational(-35209, 147), + listOf(3u, 2u) to Rational(15041, 147), + listOf(4u, 2u) to Rational(240889, 1323), + listOf(5u, 2u) to Rational(27778, 1323), + listOf(6u, 2u) to Rational(1327, 189), + listOf(0u, 3u) to Rational(1620, 7), + listOf(1u, 3u) to Rational(-25716, 49), + listOf(2u, 3u) to Rational(-32078, 49), + listOf(3u, 3u) to Rational(-704038, 441), + listOf(4u, 3u) to Rational(-30190, 63), + listOf(5u, 3u) to Rational(-5414, 63), + listOf(6u, 3u) to Rational(-104, 9), + listOf(0u, 4u) to Rational(225, 1), + listOf(1u, 4u) to Rational(-10560, 7), + listOf(2u, 4u) to Rational(44176, 21), + listOf(3u, 4u) to Rational(28996, 21), + listOf(4u, 4u) to Rational(2405, 7), + listOf(5u, 4u) to Rational(1240, 21), + listOf(6u, 4u) to Rational(16, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(493, 6), + listOf(1u) to Rational(-15991, 210), + listOf(2u) to Rational(2734, 63), + listOf(3u) to Rational(-8213, 245), + listOf(4u) to Rational(1843, 147), + listOf(5u) to Rational(-432, 245), + listOf(6u) to Rational(4, 49), + listOf(0u, 1u) to Rational(-66, 1), + listOf(1u, 1u) to Rational(-92924, 2205), + listOf(2u, 1u) to Rational(-257461, 2205), + listOf(3u, 1u) to Rational(58658, 2205), + listOf(4u, 1u) to Rational(-87884, 2205), + listOf(5u, 1u) to Rational(2726, 105), + listOf(6u, 1u) to Rational(-52, 21), + listOf(0u, 2u) to Rational(-17569, 147), + listOf(1u, 2u) to Rational(368819, 735), + listOf(2u, 2u) to Rational(-644626, 6615), + listOf(3u, 2u) to Rational(221738, 945), + listOf(4u, 2u) to Rational(-18022, 945), + listOf(5u, 2u) to Rational(-1201, 315), + listOf(6u, 2u) to Rational(1327, 63), + listOf(0u, 3u) to Rational(240, 7), + listOf(1u, 3u) to Rational(-868, 9), + listOf(2u, 3u) to Rational(-8936, 315), + listOf(3u, 3u) to Rational(-77146, 315), + listOf(4u, 3u) to Rational(-4072, 315), + listOf(5u, 3u) to Rational(-2218, 15), + listOf(6u, 3u) to Rational(-104, 3), + listOf(0u, 4u) to Rational(100, 3), + listOf(1u, 4u) to Rational(-725, 3), + listOf(2u, 4u) to Rational(459, 1), + listOf(3u, 4u) to Rational(-2071, 15), + listOf(4u, 4u) to Rational(2831, 15), + listOf(5u, 4u) to Rational(632, 5), + listOf(6u, 4u) to Rational(16, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1255, 9), + listOf(1u) to Rational(-24781, 126), + listOf(2u) to Rational(1195, 14), + listOf(3u) to Rational(-1931, 147), + listOf(4u) to Rational(439, 147), + listOf(5u) to Rational(-172, 343), + listOf(6u) to Rational(4, 147), + listOf(0u, 1u) to Rational(-183, 1), + listOf(1u, 1u) to Rational(-30988, 441), + listOf(2u, 1u) to Rational(-56137, 294), + listOf(3u, 1u) to Rational(204308, 1029), + listOf(4u, 1u) to Rational(-3263, 441), + listOf(5u, 1u) to Rational(2662, 441), + listOf(6u, 1u) to Rational(-52, 63), + listOf(0u, 2u) to Rational(-87119, 294), + listOf(1u, 2u) to Rational(1077919, 686), + listOf(2u, 2u) to Rational(-35209, 147), + listOf(3u, 2u) to Rational(15041, 147), + listOf(4u, 2u) to Rational(240889, 1323), + listOf(5u, 2u) to Rational(27778, 1323), + listOf(6u, 2u) to Rational(1327, 189), + listOf(0u, 3u) to Rational(1620, 7), + listOf(1u, 3u) to Rational(-25716, 49), + listOf(2u, 3u) to Rational(-32078, 49), + listOf(3u, 3u) to Rational(-704038, 441), + listOf(4u, 3u) to Rational(-30190, 63), + listOf(5u, 3u) to Rational(-5414, 63), + listOf(6u, 3u) to Rational(-104, 9), + listOf(0u, 4u) to Rational(225, 1), + listOf(1u, 4u) to Rational(-10560, 7), + listOf(2u, 4u) to Rational(44176, 21), + listOf(3u, 4u) to Rational(28996, 21), + listOf(4u, 4u) to Rational(2405, 7), + listOf(5u, 4u) to Rational(1240, 21), + listOf(6u, 4u) to Rational(16, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-409, 6), + listOf(1u) to Rational(-376, 9), + listOf(2u) to Rational(-1781, 81), + listOf(3u) to Rational(-128, 27), + listOf(4u) to Rational(-8, 9), + listOf(0u, 1u) to Rational(18701, 210), + listOf(1u, 1u) to Rational(614183, 7560), + listOf(2u, 1u) to Rational(90941, 1890), + listOf(3u, 1u) to Rational(1802, 135), + listOf(4u, 1u) to Rational(112, 45), + listOf(0u, 2u) to Rational(181421, 315), + listOf(1u, 2u) to Rational(77813, 378), + listOf(2u, 2u) to Rational(598583, 7560), + listOf(3u, 2u) to Rational(85, 27), + listOf(4u, 2u) to Rational(2, 5), + listOf(0u, 3u) to Rational(130997, 315), + listOf(1u, 3u) to Rational(1093, 420), + listOf(2u, 3u) to Rational(9551, 2520), + listOf(3u, 3u) to Rational(-14, 45), + listOf(4u, 3u) to Rational(22, 45), + listOf(0u, 4u) to Rational(-2801, 9), + listOf(1u, 4u) to Rational(4033, 90), + listOf(2u, 4u) to Rational(6429, 80), + listOf(3u, 4u) to Rational(2851, 90), + listOf(4u, 4u) to Rational(293, 45), + listOf(0u, 5u) to Rational(-220, 1), + listOf(1u, 5u) to Rational(127, 1), + listOf(2u, 5u) to Rational(202, 5), + listOf(3u, 5u) to Rational(-63, 5), + listOf(4u, 5u) to Rational(-12, 5), + listOf(0u, 6u) to Rational(100, 1), + listOf(1u, 6u) to Rational(-80, 1), + listOf(2u, 6u) to Rational(-24, 1), + listOf(3u, 6u) to Rational(16, 1), + listOf(4u, 6u) to Rational(4, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(5407, 9), + listOf(1u) to Rational(9568, 27), + listOf(2u) to Rational(4996, 27), + listOf(3u) to Rational(352, 9), + listOf(4u) to Rational(22, 3), + listOf(0u, 1u) to Rational(104411, 126), + listOf(1u, 1u) to Rational(6001, 126), + listOf(2u, 1u) to Rational(-796, 21), + listOf(3u, 1u) to Rational(-5389, 126), + listOf(4u, 1u) to Rational(-166, 21), + listOf(0u, 2u) to Rational(-35327, 126), + listOf(1u, 2u) to Rational(53, 252), + listOf(2u, 2u) to Rational(849197, 6048), + listOf(3u, 2u) to Rational(22361, 252), + listOf(4u, 2u) to Rational(773, 42), + listOf(0u, 3u) to Rational(-6067, 21), + listOf(1u, 3u) to Rational(39049, 126), + listOf(2u, 3u) to Rational(80303, 1008), + listOf(3u, 3u) to Rational(-3035, 63), + listOf(4u, 3u) to Rational(-209, 21), + listOf(0u, 4u) to Rational(3113, 21), + listOf(1u, 4u) to Rational(-22345, 126), + listOf(2u, 4u) to Rational(-30931, 1008), + listOf(3u, 4u) to Rational(5837, 126), + listOf(4u, 4u) to Rational(229, 21), + listOf(0u, 5u) to Rational(-2120, 21), + listOf(1u, 5u) to Rational(451, 7), + listOf(2u, 5u) to Rational(422, 21), + listOf(3u, 5u) to Rational(-181, 21), + listOf(4u, 5u) to Rational(-40, 21), + listOf(0u, 6u) to Rational(100, 3), + listOf(1u, 6u) to Rational(-80, 3), + listOf(2u, 6u) to Rational(-8, 1), + listOf(3u, 6u) to Rational(16, 3), + listOf(4u, 6u) to Rational(4, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-409, 6), + listOf(1u) to Rational(-376, 9), + listOf(2u) to Rational(-1781, 81), + listOf(3u) to Rational(-128, 27), + listOf(4u) to Rational(-8, 9), + listOf(0u, 1u) to Rational(18701, 210), + listOf(1u, 1u) to Rational(614183, 7560), + listOf(2u, 1u) to Rational(90941, 1890), + listOf(3u, 1u) to Rational(1802, 135), + listOf(4u, 1u) to Rational(112, 45), + listOf(0u, 2u) to Rational(181421, 315), + listOf(1u, 2u) to Rational(77813, 378), + listOf(2u, 2u) to Rational(598583, 7560), + listOf(3u, 2u) to Rational(85, 27), + listOf(4u, 2u) to Rational(2, 5), + listOf(0u, 3u) to Rational(130997, 315), + listOf(1u, 3u) to Rational(1093, 420), + listOf(2u, 3u) to Rational(9551, 2520), + listOf(3u, 3u) to Rational(-14, 45), + listOf(4u, 3u) to Rational(22, 45), + listOf(0u, 4u) to Rational(-2801, 9), + listOf(1u, 4u) to Rational(4033, 90), + listOf(2u, 4u) to Rational(6429, 80), + listOf(3u, 4u) to Rational(2851, 90), + listOf(4u, 4u) to Rational(293, 45), + listOf(0u, 5u) to Rational(-220, 1), + listOf(1u, 5u) to Rational(127, 1), + listOf(2u, 5u) to Rational(202, 5), + listOf(3u, 5u) to Rational(-63, 5), + listOf(4u, 5u) to Rational(-12, 5), + listOf(0u, 6u) to Rational(100, 1), + listOf(1u, 6u) to Rational(-80, 1), + listOf(2u, 6u) to Rational(-24, 1), + listOf(3u, 6u) to Rational(16, 1), + listOf(4u, 6u) to Rational(4, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(5407, 9), + listOf(1u) to Rational(9568, 27), + listOf(2u) to Rational(4996, 27), + listOf(3u) to Rational(352, 9), + listOf(4u) to Rational(22, 3), + listOf(0u, 1u) to Rational(104411, 126), + listOf(1u, 1u) to Rational(6001, 126), + listOf(2u, 1u) to Rational(-796, 21), + listOf(3u, 1u) to Rational(-5389, 126), + listOf(4u, 1u) to Rational(-166, 21), + listOf(0u, 2u) to Rational(-35327, 126), + listOf(1u, 2u) to Rational(53, 252), + listOf(2u, 2u) to Rational(849197, 6048), + listOf(3u, 2u) to Rational(22361, 252), + listOf(4u, 2u) to Rational(773, 42), + listOf(0u, 3u) to Rational(-6067, 21), + listOf(1u, 3u) to Rational(39049, 126), + listOf(2u, 3u) to Rational(80303, 1008), + listOf(3u, 3u) to Rational(-3035, 63), + listOf(4u, 3u) to Rational(-209, 21), + listOf(0u, 4u) to Rational(3113, 21), + listOf(1u, 4u) to Rational(-22345, 126), + listOf(2u, 4u) to Rational(-30931, 1008), + listOf(3u, 4u) to Rational(5837, 126), + listOf(4u, 4u) to Rational(229, 21), + listOf(0u, 5u) to Rational(-2120, 21), + listOf(1u, 5u) to Rational(451, 7), + listOf(2u, 5u) to Rational(422, 21), + listOf(3u, 5u) to Rational(-181, 21), + listOf(4u, 5u) to Rational(-40, 21), + listOf(0u, 6u) to Rational(100, 3), + listOf(1u, 6u) to Rational(-80, 3), + listOf(2u, 6u) to Rational(-8, 1), + listOf(3u, 6u) to Rational(16, 3), + listOf(4u, 6u) to Rational(4, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 5'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + 5 to NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 6'" + ) } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Map() { // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-17166109, 793800), + listOf(3u, 1u) to Rational(-930960143, 5556600), + listOf(2u, 2u) to Rational(-144665109691, 350065800), + listOf(1u, 3u) to Rational(-17232577, 52920), + listOf(0u, 4u) to Rational(-68141, 1323), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(-57522533, 14288400), + listOf(3u, 1u) to Rational(-13085162953, 300056400), + listOf(2u, 2u) to Rational(-92093367341, 525098700), + listOf(1u, 3u) to Rational(-1979342797, 6667920), + listOf(0u, 4u) to Rational(-3082727, 21168), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(11, 5), + listOf(0u, 1u) to Rational(8, 4), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(1, 9), + listOf(0u, 1u) to Rational(11, 7), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(-4, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 6), + listOf(0u, 1u) to Rational(12, 8), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 3'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(2303, 64), + listOf(1u) to Rational(31843, 192), + listOf(2u) to Rational(118891, 576), + listOf(3u) to Rational(94453, 168), + listOf(4u) to Rational(-179203, 1512), + listOf(5u) to Rational(-16979, 126), + listOf(6u) to Rational(-13499, 12), + listOf(0u, 1u) to Rational(-4767, 64), + listOf(1u, 1u) to Rational(-58689, 256), + listOf(2u, 1u) to Rational(-757333, 4032), + listOf(3u, 1u) to Rational(-4921205, 4032), + listOf(4u, 1u) to Rational(-2930815, 4032), + listOf(5u, 1u) to Rational(-398803, 1512), + listOf(6u, 1u) to Rational(18835, 36), + listOf(0u, 2u) to Rational(224101, 960), + listOf(1u, 2u) to Rational(9139699, 40320), + listOf(2u, 2u) to Rational(3848803, 5760), + listOf(3u, 2u) to Rational(93102371, 241920), + listOf(4u, 2u) to Rational(-65821229, 141120), + listOf(5u, 2u) to Rational(-15675899, 7056), + listOf(6u, 2u) to Rational(10459, 189), + listOf(0u, 3u) to Rational(2411, 16), + listOf(1u, 3u) to Rational(1294543, 10080), + listOf(2u, 3u) to Rational(-1740199, 1440), + listOf(3u, 3u) to Rational(-266994841, 282240), + listOf(4u, 3u) to Rational(-41261893, 211680), + listOf(5u, 3u) to Rational(1717357, 3528), + listOf(6u, 3u) to Rational(69, 14), + listOf(0u, 4u) to Rational(13231, 360), + listOf(1u, 4u) to Rational(4858831, 25200), + listOf(2u, 4u) to Rational(15565759, 75600), + listOf(3u, 4u) to Rational(-15583391, 35280), + listOf(4u, 4u) to Rational(-13345747, 11760), + listOf(5u, 4u) to Rational(140103, 686), + listOf(6u, 4u) to Rational(-765, 49) + ), + NumberedPolynomialAsIs( + listOf() to Rational(31409, 576), + listOf(1u) to Rational(-337099, 1728), + listOf(2u) to Rational(-211429, 1728), + listOf(3u) to Rational(-259241, 432), + listOf(4u) to Rational(-13777, 36), + listOf(5u) to Rational(-41389, 72), + listOf(6u) to Rational(-7679, 48), + listOf(0u, 1u) to Rational(-3269, 12), + listOf(1u, 1u) to Rational(629569, 864), + listOf(2u, 1u) to Rational(53867, 324), + listOf(3u, 1u) to Rational(2290577, 1728), + listOf(4u, 1u) to Rational(101507, 216), + listOf(5u, 1u) to Rational(213109, 288), + listOf(6u, 1u) to Rational(17927, 144), + listOf(0u, 2u) to Rational(314587, 1080), + listOf(1u, 2u) to Rational(-109771, 144), + listOf(2u, 2u) to Rational(-6469, 16), + listOf(3u, 2u) to Rational(-298291681, 181440), + listOf(4u, 2u) to Rational(-59147357, 48384), + listOf(5u, 2u) to Rational(-4982365, 6048), + listOf(6u, 2u) to Rational(-18727, 576), + listOf(0u, 3u) to Rational(12379, 90), + listOf(1u, 3u) to Rational(-542911, 1620), + listOf(2u, 3u) to Rational(143123, 1260), + listOf(3u, 3u) to Rational(9859177, 30240), + listOf(4u, 3u) to Rational(9312529, 20160), + listOf(5u, 3u) to Rational(207001, 672), + listOf(6u, 3u) to Rational(203, 24), + listOf(0u, 4u) to Rational(9442, 675), + listOf(1u, 4u) to Rational(-13729, 300), + listOf(2u, 4u) to Rational(-3490471, 25200), + listOf(3u, 4u) to Rational(-333031, 840), + listOf(4u, 4u) to Rational(-7572211, 47040), + listOf(5u, 4u) to Rational(-1189, 56), + listOf(6u, 4u) to Rational(-405, 196) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(2303, 64), + listOf(1u) to Rational(31843, 192), + listOf(2u) to Rational(118891, 576), + listOf(3u) to Rational(94453, 168), + listOf(4u) to Rational(-179203, 1512), + listOf(5u) to Rational(-16979, 126), + listOf(6u) to Rational(-13499, 12), + listOf(0u, 1u) to Rational(-4767, 64), + listOf(1u, 1u) to Rational(-58689, 256), + listOf(2u, 1u) to Rational(-757333, 4032), + listOf(3u, 1u) to Rational(-4921205, 4032), + listOf(4u, 1u) to Rational(-2930815, 4032), + listOf(5u, 1u) to Rational(-398803, 1512), + listOf(6u, 1u) to Rational(18835, 36), + listOf(0u, 2u) to Rational(224101, 960), + listOf(1u, 2u) to Rational(9139699, 40320), + listOf(2u, 2u) to Rational(3848803, 5760), + listOf(3u, 2u) to Rational(93102371, 241920), + listOf(4u, 2u) to Rational(-65821229, 141120), + listOf(5u, 2u) to Rational(-15675899, 7056), + listOf(6u, 2u) to Rational(10459, 189), + listOf(0u, 3u) to Rational(2411, 16), + listOf(1u, 3u) to Rational(1294543, 10080), + listOf(2u, 3u) to Rational(-1740199, 1440), + listOf(3u, 3u) to Rational(-266994841, 282240), + listOf(4u, 3u) to Rational(-41261893, 211680), + listOf(5u, 3u) to Rational(1717357, 3528), + listOf(6u, 3u) to Rational(69, 14), + listOf(0u, 4u) to Rational(13231, 360), + listOf(1u, 4u) to Rational(4858831, 25200), + listOf(2u, 4u) to Rational(15565759, 75600), + listOf(3u, 4u) to Rational(-15583391, 35280), + listOf(4u, 4u) to Rational(-13345747, 11760), + listOf(5u, 4u) to Rational(140103, 686), + listOf(6u, 4u) to Rational(-765, 49) + ), + NumberedPolynomialAsIs( + listOf() to Rational(31409, 576), + listOf(1u) to Rational(-337099, 1728), + listOf(2u) to Rational(-211429, 1728), + listOf(3u) to Rational(-259241, 432), + listOf(4u) to Rational(-13777, 36), + listOf(5u) to Rational(-41389, 72), + listOf(6u) to Rational(-7679, 48), + listOf(0u, 1u) to Rational(-3269, 12), + listOf(1u, 1u) to Rational(629569, 864), + listOf(2u, 1u) to Rational(53867, 324), + listOf(3u, 1u) to Rational(2290577, 1728), + listOf(4u, 1u) to Rational(101507, 216), + listOf(5u, 1u) to Rational(213109, 288), + listOf(6u, 1u) to Rational(17927, 144), + listOf(0u, 2u) to Rational(314587, 1080), + listOf(1u, 2u) to Rational(-109771, 144), + listOf(2u, 2u) to Rational(-6469, 16), + listOf(3u, 2u) to Rational(-298291681, 181440), + listOf(4u, 2u) to Rational(-59147357, 48384), + listOf(5u, 2u) to Rational(-4982365, 6048), + listOf(6u, 2u) to Rational(-18727, 576), + listOf(0u, 3u) to Rational(12379, 90), + listOf(1u, 3u) to Rational(-542911, 1620), + listOf(2u, 3u) to Rational(143123, 1260), + listOf(3u, 3u) to Rational(9859177, 30240), + listOf(4u, 3u) to Rational(9312529, 20160), + listOf(5u, 3u) to Rational(207001, 672), + listOf(6u, 3u) to Rational(203, 24), + listOf(0u, 4u) to Rational(9442, 675), + listOf(1u, 4u) to Rational(-13729, 300), + listOf(2u, 4u) to Rational(-3490471, 25200), + listOf(3u, 4u) to Rational(-333031, 840), + listOf(4u, 4u) to Rational(-7572211, 47040), + listOf(5u, 4u) to Rational(-1189, 56), + listOf(6u, 4u) to Rational(-405, 196) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 1 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 4'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-506213, 2800), + listOf(1u) to Rational(9859, 315), + listOf(2u) to Rational(17384377, 11340), + listOf(3u) to Rational(-9662, 63), + listOf(4u) to Rational(-12563, 4), + listOf(0u, 1u) to Rational(-486293, 22400), + listOf(1u, 1u) to Rational(-6530947, 25200), + listOf(2u, 1u) to Rational(866125, 18144), + listOf(3u, 1u) to Rational(2948747, 2520), + listOf(4u, 1u) to Rational(1196611, 2016), + listOf(0u, 2u) to Rational(-20266021, 117600), + listOf(1u, 2u) to Rational(26656339, 44100), + listOf(2u, 2u) to Rational(19499183, 18144), + listOf(3u, 2u) to Rational(-19801849, 7560), + listOf(4u, 2u) to Rational(-2639635, 1296), + listOf(0u, 3u) to Rational(-5017697, 29400), + listOf(1u, 3u) to Rational(-606007, 1575), + listOf(2u, 3u) to Rational(127494487, 132300), + listOf(3u, 3u) to Rational(166567, 105), + listOf(4u, 3u) to Rational(486403, 18144), + listOf(0u, 4u) to Rational(-32182, 735), + listOf(1u, 4u) to Rational(2420671, 8820), + listOf(2u, 4u) to Rational(-12619193, 26460), + listOf(3u, 4u) to Rational(-6823067, 5670), + listOf(4u, 4u) to Rational(-2311693, 13608), + listOf(0u, 5u) to Rational(-13324, 245), + listOf(1u, 5u) to Rational(1966, 35), + listOf(2u, 5u) to Rational(1052719, 2520), + listOf(3u, 5u) to Rational(19153, 270), + listOf(4u, 5u) to Rational(701, 54), + listOf(0u, 6u) to Rational(4647, 196), + listOf(1u, 6u) to Rational(2197, 28), + listOf(2u, 6u) to Rational(-43853, 336), + listOf(3u, 6u) to Rational(-301, 3), + listOf(4u, 6u) to Rational(34, 3) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2843, 1600), + listOf(1u) to Rational(-1483, 240), + listOf(2u) to Rational(110623, 1296), + listOf(3u) to Rational(1265, 72), + listOf(4u) to Rational(-5011, 16), + listOf(0u, 1u) to Rational(47743, 1800), + listOf(1u, 1u) to Rational(619229, 32400), + listOf(2u, 1u) to Rational(-5978369, 58320), + listOf(3u, 1u) to Rational(-86081, 1620), + listOf(4u, 1u) to Rational(6325, 72), + listOf(0u, 2u) to Rational(110951, 3360), + listOf(1u, 2u) to Rational(-9550649, 302400), + listOf(2u, 2u) to Rational(6542933, 85050), + listOf(3u, 2u) to Rational(4708291, 38880), + listOf(4u, 2u) to Rational(-433327, 1296), + listOf(0u, 3u) to Rational(56143, 600), + listOf(1u, 3u) to Rational(94243, 720), + listOf(2u, 3u) to Rational(-46779139, 226800), + listOf(3u, 3u) to Rational(-6948253, 12960), + listOf(4u, 3u) to Rational(-260261, 486), + listOf(0u, 4u) to Rational(-3205317, 19600), + listOf(1u, 4u) to Rational(-201253, 1050), + listOf(2u, 4u) to Rational(332192677, 302400), + listOf(3u, 4u) to Rational(351511, 360), + listOf(4u, 4u) to Rational(-40547, 81), + listOf(0u, 5u) to Rational(-65421, 1960), + listOf(1u, 5u) to Rational(-10118, 35), + listOf(2u, 5u) to Rational(-4341709, 10080), + listOf(3u, 5u) to Rational(-91703, 360), + listOf(4u, 5u) to Rational(-85, 9), + listOf(0u, 6u) to Rational(-25965, 784), + listOf(1u, 6u) to Rational(3351, 16), + listOf(2u, 6u) to Rational(595159, 1344), + listOf(3u, 6u) to Rational(-1381, 12), + listOf(4u, 6u) to Rational(-155, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-506213, 2800), + listOf(1u) to Rational(9859, 315), + listOf(2u) to Rational(17384377, 11340), + listOf(3u) to Rational(-9662, 63), + listOf(4u) to Rational(-12563, 4), + listOf(0u, 1u) to Rational(-486293, 22400), + listOf(1u, 1u) to Rational(-6530947, 25200), + listOf(2u, 1u) to Rational(866125, 18144), + listOf(3u, 1u) to Rational(2948747, 2520), + listOf(4u, 1u) to Rational(1196611, 2016), + listOf(0u, 2u) to Rational(-20266021, 117600), + listOf(1u, 2u) to Rational(26656339, 44100), + listOf(2u, 2u) to Rational(19499183, 18144), + listOf(3u, 2u) to Rational(-19801849, 7560), + listOf(4u, 2u) to Rational(-2639635, 1296), + listOf(0u, 3u) to Rational(-5017697, 29400), + listOf(1u, 3u) to Rational(-606007, 1575), + listOf(2u, 3u) to Rational(127494487, 132300), + listOf(3u, 3u) to Rational(166567, 105), + listOf(4u, 3u) to Rational(486403, 18144), + listOf(0u, 4u) to Rational(-32182, 735), + listOf(1u, 4u) to Rational(2420671, 8820), + listOf(2u, 4u) to Rational(-12619193, 26460), + listOf(3u, 4u) to Rational(-6823067, 5670), + listOf(4u, 4u) to Rational(-2311693, 13608), + listOf(0u, 5u) to Rational(-13324, 245), + listOf(1u, 5u) to Rational(1966, 35), + listOf(2u, 5u) to Rational(1052719, 2520), + listOf(3u, 5u) to Rational(19153, 270), + listOf(4u, 5u) to Rational(701, 54), + listOf(0u, 6u) to Rational(4647, 196), + listOf(1u, 6u) to Rational(2197, 28), + listOf(2u, 6u) to Rational(-43853, 336), + listOf(3u, 6u) to Rational(-301, 3), + listOf(4u, 6u) to Rational(34, 3) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2843, 1600), + listOf(1u) to Rational(-1483, 240), + listOf(2u) to Rational(110623, 1296), + listOf(3u) to Rational(1265, 72), + listOf(4u) to Rational(-5011, 16), + listOf(0u, 1u) to Rational(47743, 1800), + listOf(1u, 1u) to Rational(619229, 32400), + listOf(2u, 1u) to Rational(-5978369, 58320), + listOf(3u, 1u) to Rational(-86081, 1620), + listOf(4u, 1u) to Rational(6325, 72), + listOf(0u, 2u) to Rational(110951, 3360), + listOf(1u, 2u) to Rational(-9550649, 302400), + listOf(2u, 2u) to Rational(6542933, 85050), + listOf(3u, 2u) to Rational(4708291, 38880), + listOf(4u, 2u) to Rational(-433327, 1296), + listOf(0u, 3u) to Rational(56143, 600), + listOf(1u, 3u) to Rational(94243, 720), + listOf(2u, 3u) to Rational(-46779139, 226800), + listOf(3u, 3u) to Rational(-6948253, 12960), + listOf(4u, 3u) to Rational(-260261, 486), + listOf(0u, 4u) to Rational(-3205317, 19600), + listOf(1u, 4u) to Rational(-201253, 1050), + listOf(2u, 4u) to Rational(332192677, 302400), + listOf(3u, 4u) to Rational(351511, 360), + listOf(4u, 4u) to Rational(-40547, 81), + listOf(0u, 5u) to Rational(-65421, 1960), + listOf(1u, 5u) to Rational(-10118, 35), + listOf(2u, 5u) to Rational(-4341709, 10080), + listOf(3u, 5u) to Rational(-91703, 360), + listOf(4u, 5u) to Rational(-85, 9), + listOf(0u, 6u) to Rational(-25965, 784), + listOf(1u, 6u) to Rational(3351, 16), + listOf(2u, 6u) to Rational(595159, 1344), + listOf(3u, 6u) to Rational(-1381, 12), + listOf(4u, 6u) to Rational(-155, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 0 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 5'" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + 5 to NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 6'" + ) } @Test @Ignore @@ -2244,7 +5416,7 @@ class NumberedPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction_Buffer() { // TODO @@ -2266,7 +5438,7 @@ class NumberedPolynomialUtilTest { } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should make denominator r^deg(p), + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Buffer() { // TODO diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt index 4bdd60704..071701593 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -41,66 +41,105 @@ class Rational { 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: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false ) + } operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), - denominator + denominator, + toCheckInput = false ) operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, - denominator + denominator, + toCheckInput = false ) - operator fun minus(other: Rational): Rational = - Rational( - numerator * other.denominator - denominator * other.numerator, - denominator * other.denominator + operator fun minus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false ) + } operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), - denominator + denominator, + toCheckInput = false ) operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, - denominator + denominator, + toCheckInput = false ) - operator fun times(other: Rational): Rational = - Rational( - numerator * other.numerator, - denominator * other.denominator + operator fun times(other: Rational): Rational { + val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) + val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) + return Rational( + (numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd), + (denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd), + toCheckInput = false ) - operator fun times(other: Int): Rational = - Rational( - numerator * other.toLong(), - denominator + } + operator fun times(other: Int): Rational { + val other = other.toLong() + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false ) - operator fun times(other: Long): Rational = - Rational( - numerator * other, - denominator + } + operator fun times(other: Long): Rational { + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false ) - operator fun div(other: Rational): Rational = - Rational( - numerator * other.denominator, - denominator * other.numerator + } + operator fun div(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val numeratorsGcd = gcd(numerator, other.numerator) + return Rational( + (numerator / numeratorsGcd) * (other.denominator / denominatorsGcd), + (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) - operator fun div(other: Int): Rational = - Rational( - numerator, - denominator * other.toLong() + } + operator fun div(other: Int): Rational { + val other = other.toLong() + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false ) - operator fun div(other: Long): Rational = - Rational( - numerator, - denominator * other + } + operator fun div(other: Long): Rational { + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false ) + } override fun equals(other: Any?): Boolean = when (other) { is Rational -> numerator == other.numerator && denominator == other.denominator diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt index 52ecf416a..bf8675675 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -5,10 +5,44 @@ package space.kscience.kmath.test.misc +import space.kscience.kmath.functions.NumberedPolynomial +import space.kscience.kmath.functions.NumberedRationalFunction import kotlin.test.assertEquals fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { assertEquals(expected.keys, actual.keys, message) for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) +} + +fun assertEquals( + expected: NumberedPolynomial, + actual: NumberedPolynomial, + absoluteTolerance: Double, + message: String? = null +) = assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message +) + +fun assertEquals( + expected: NumberedRationalFunction, + actual: NumberedRationalFunction, + absoluteTolerance: Double, + message: String? = null +) { + assertEquals( + expected.numerator, + actual.numerator, + absoluteTolerance, + message + ) + assertEquals( + expected.denominator, + actual.denominator, + absoluteTolerance, + message + ) } \ No newline at end of file From 102e83b4780209da177053d587aed35aabf7f811 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 02:24:46 +0300 Subject: [PATCH 105/174] Tests generation for numbered utilities in progress: finish substitutions. --- .../kscience/kmath/functions/numberedUtil.kt | 6 +- .../functions/NumberedPolynomialUtilTest.kt | 3786 ++++++++++++++++- .../kscience/kmath/test/misc/assertion.kt | 14 +- 3 files changed, 3780 insertions(+), 26 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index e485652f4..9397c1956 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -262,12 +262,14 @@ public fun NumberedRationalFunction.substitute(ring: Ring, args: Buffe numerator.substitute(ring, args) / denominator.substitute(ring, args) } +internal const val fullSubstitutionExceptionMessage: String = "Fully substituting buffer should cover all variables of the polynomial." + /** * Substitutes provided Double arguments [args] into [this] Double polynomial. */ public fun NumberedPolynomial.substituteFully(args: Buffer): Double = Double.algebra { val lastSubstitutionVariable = args.size - 1 - require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { fullSubstitutionExceptionMessage } coefficients.entries.fold(.0) { acc, (degs, c) -> acc + degs.foldIndexed(c) { variable, product, deg -> if (deg == 0u) product else product * args[variable].pow(deg.toInt()) @@ -280,7 +282,7 @@ public fun NumberedPolynomial.substituteFully(args: Buffer): Dou */ public fun NumberedPolynomial.substituteFully(ring: Ring, args: Buffer): C = ring { val lastSubstitutionVariable = args.size - 1 - require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { "Fully substituting buffer should cover all variables of the polynomial." } + require(coefficients.keys.all { it.lastIndex <= lastSubstitutionVariable }) { fullSubstitutionExceptionMessage } coefficients.entries.fold(zero) { acc, (degs, c) -> acc + degs.foldIndexed(c) { variable, product, deg -> if (deg == 0u) product else product * power(args[variable], deg) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index b6baed6af..9e49f1315 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -5,14 +5,19 @@ package space.kscience.kmath.functions +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.test.misc.assertEquals +import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals +fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() + class NumberedPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double_Map() { @@ -4104,7 +4109,6 @@ class NumberedPolynomialUtilTest { // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Map() { - // TODO assertEquals( NumberedRationalFunction( NumberedPolynomialAsIs( @@ -5400,68 +5404,3804 @@ class NumberedPolynomialUtilTest { ) } @Test - @Ignore fun test_Polynomial_substitute_Double_Buffer() { - // TODO + assertEquals( + NumberedPolynomialAsIs(emptyList() to 0.0), + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substitute(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf()), + 0.001, + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(0u, 1u) to 0.4561746111587508, + listOf(0u, 2u) to 0.2700930201481795, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.0, + )), + 0.001, + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.047895694399743, + listOf(0u, 1u) to 0.859913883275481, + listOf(0u, 2u) to 0.2327806735363575, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + )), + 0.001, + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + )), + 0.001, + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933 + )), + 0.001, + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to 1.934530767358133, + ), + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substitute(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933, + 0.4752854632152105 + )), + 0.001, + "test 7" + ) } @Test - @Ignore fun test_Polynomial_substitute_Constant_Buffer() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf()), + "test 2" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-83, 50), + listOf(0u, 1u) to Rational(29, 25), + listOf(0u, 2u) to Rational(3, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + )), + "test 3" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(143, 150) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + Rational(57, 179), + )), + "test 5" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(47639065216, 2562890625) + ), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 6" + ) } @Test - @Ignore fun test_Polynomial_substitute_Polynomial_Buffer() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-5%2F1+s+%2B+2%2F8+t%2C+y+%3D+11%2F7+t + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(0u, 1u) to Rational(-92, 21), + listOf(0u, 2u) to Rational(-2627, 2352), + listOf(0u, 3u) to Rational(4565, 3136), + listOf(0u, 4u) to Rational(605, 1568), + listOf(1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(1445, 21), + listOf(1u, 2u) to Rational(-13145, 392), + listOf(1u, 3u) to Rational(-3025, 196), + listOf(2u) to Rational(175, 3), + listOf(2u, 1u) to Rational(2475, 28), + listOf(2u, 2u) to Rational(15125, 98), + listOf(3u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-5, 1), + listOf(0u, 1u) to Rational(2, 8), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(0, 5), + listOf(0u, 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 3), + listOf(1u) to Rational(5, 2), + listOf(2u) to Rational(13, 7), + listOf(0u, 1u) to Rational(16, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(6, 1), + listOf(0u, 2u) to Rational(-14, 3), + listOf(1u, 2u) to Rational(-2, 7), + listOf(2u, 2u) to Rational(-10, 8), + ) + )), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(129, 4), + listOf(1u) to Rational(48583, 336), + listOf(2u) to Rational(-913477, 1568), + listOf(3u) to Rational(-967567, 672), + listOf(4u) to Rational(4722043, 1344), + listOf(5u) to Rational(8855, 2), + listOf(6u) to Rational(-311971, 32), + listOf(7u) to Rational(-17325, 4), + listOf(8u) to Rational(19845, 2), + listOf(0u, 1u) to Rational(-827, 4), + listOf(1u, 1u) to Rational(191927, 840), + listOf(2u, 1u) to Rational(9592627, 2352), + listOf(3u, 1u) to Rational(-105400711, 53760), + listOf(4u, 1u) to Rational(-10054101459, 439040), + listOf(5u, 1u) to Rational(2127351, 128), + listOf(6u, 1u) to Rational(116680973, 3136), + listOf(7u, 1u) to Rational(-220445, 7), + listOf(8u, 1u) to Rational(-2655, 4), + listOf(0u, 2u) to Rational(30567, 100), + listOf(1u, 2u) to Rational(-156284953, 39200), + listOf(2u, 2u) to Rational(-57661541711, 6585600), + listOf(3u, 2u) to Rational(131931579, 3136), + listOf(4u, 2u) to Rational(98818124791, 3512320), + listOf(5u, 2u) to Rational(-94458855053, 878080), + listOf(6u, 2u) to Rational(13937705305, 1229312), + listOf(7u, 2u) to Rational(335706887, 21952), + listOf(8u, 2u) to Rational(23549165, 1568), + listOf(0u, 3u) to Rational(111367, 1400), + listOf(1u, 3u) to Rational(4937369, 700), + listOf(2u, 3u) to Rational(-4449423711, 274400), + listOf(3u, 3u) to Rational(-351873325703, 4390400), + listOf(4u, 3u) to Rational(23495875029, 307328), + listOf(5u, 3u) to Rational(17576300919, 878080), + listOf(6u, 3u) to Rational(230316993, 12544), + listOf(7u, 3u) to Rational(-191130515, 21952), + listOf(8u, 3u) to Rational(332435, 392), + listOf(0u, 4u) to Rational(-275084, 1225), + listOf(1u, 4u) to Rational(-266774603, 137200), + listOf(2u, 4u) to Rational(2176279167121, 30732800), + listOf(3u, 4u) to Rational(10904913303, 2195200), + listOf(4u, 4u) to Rational(-10769286147, 2195200), + listOf(5u, 4u) to Rational(-26277119793, 439040), + listOf(6u, 4u) to Rational(25859735869, 6146560), + listOf(7u, 4u) to Rational(38906289, 2744), + listOf(8u, 4u) to Rational(-3072025, 392), + listOf(0u, 5u) to Rational(9573, 98), + listOf(1u, 5u) to Rational(-4154651399, 548800), + listOf(2u, 5u) to Rational(3446069019, 548800), + listOf(3u, 5u) to Rational(-7851500623, 137200), + listOf(4u, 5u) to Rational(-53205142903, 1920800), + listOf(5u, 5u) to Rational(-31953611, 3430), + listOf(6u, 5u) to Rational(1447380313, 109760), + listOf(7u, 5u) to Rational(764158625, 21952), + listOf(8u, 5u) to Rational(1153515, 784), + listOf(0u, 6u) to Rational(1722351, 7840), + listOf(1u, 6u) to Rational(-164554821, 109760), + listOf(2u, 6u) to Rational(-79096147243, 7683200), + listOf(3u, 6u) to Rational(-624721089, 15680), + listOf(4u, 6u) to Rational(11147305567, 548800), + listOf(5u, 6u) to Rational(8318333679, 109760), + listOf(6u, 6u) to Rational(32981871553, 1536640), + listOf(7u, 6u) to Rational(-225359619, 21952), + listOf(8u, 6u) to Rational(-3973995, 392), + listOf(0u, 7u) to Rational(67203, 784), + listOf(1u, 7u) to Rational(39281469, 54880), + listOf(2u, 7u) to Rational(70162551, 27440), + listOf(3u, 7u) to Rational(413630709, 54880), + listOf(4u, 7u) to Rational(4640410269, 192080), + listOf(5u, 7u) to Rational(802712247, 54880), + listOf(6u, 7u) to Rational(-473517603, 27440), + listOf(7u, 7u) to Rational(-17055459, 1568), + listOf(8u, 7u) to Rational(-12825, 14), + listOf(0u, 8u) to Rational(16245, 1568), + listOf(1u, 8u) to Rational(503253, 2744), + listOf(2u, 8u) to Rational(125292591, 96040), + listOf(3u, 8u) to Rational(12033171, 2744), + listOf(4u, 8u) to Rational(154352673, 27440), + listOf(5u, 8u) to Rational(-1302291, 392), + listOf(6u, 8u) to Rational(-20265741, 1960), + listOf(7u, 8u) to Rational(-26163, 56), + listOf(8u, 8u) to Rational(146205, 32), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-9, 2), + listOf(1u) to Rational(2, 7), + listOf(2u) to Rational(9, 1), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-1, 8), + listOf(2u, 1u) to Rational(2, 8), + listOf(0u, 2u) to Rational(19, 4), + listOf(1u, 2u) to Rational(15, 7), + listOf(2u, 2u) to Rational(-19, 4), + ), + )), + "test 4" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = t + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(7, 3), + listOf(2u) to Rational(-35, 16), + listOf(3u) to Rational(-343, 6), + listOf(4u) to Rational(343, 3), + listOf(0u, 1u) to Rational(-19, 5), + listOf(1u, 1u) to Rational(-823, 120), + listOf(2u, 1u) to Rational(1232417, 6720), + listOf(3u, 1u) to Rational(-9863, 24), + listOf(4u, 1u) to Rational(385, 4), + listOf(0u, 2u) to Rational(2439, 350), + listOf(1u, 2u) to Rational(-5793, 40), + listOf(2u, 2u) to Rational(1172113, 3360), + listOf(3u, 2u) to Rational(-13531, 40), + listOf(4u, 2u) to Rational(2824, 7), + listOf(0u, 3u) to Rational(3417, 700), + listOf(1u, 3u) to Rational(1191, 200), + listOf(2u, 3u) to Rational(8383, 28), + listOf(3u, 3u) to Rational(-220279, 280), + listOf(4u, 3u) to Rational(49179, 196), + listOf(0u, 4u) to Rational(57, 35), + listOf(1u, 4u) to Rational(-33771, 700), + listOf(2u, 4u) to Rational(196279, 1225), + listOf(3u, 4u) to Rational(-32259, 140), + listOf(4u, 4u) to Rational(23868, 49), + listOf(0u, 5u) to Rational(333, 196), + listOf(1u, 5u) to Rational(-204, 35), + listOf(2u, 5u) to Rational(-307233, 2450), + listOf(3u, 5u) to Rational(-12492, 35), + listOf(4u, 5u) to Rational(4563, 28), + listOf(0u, 6u) to Rational(45, 98), + listOf(1u, 6u) to Rational(54, 7), + listOf(2u, 6u) to Rational(1809, 35), + listOf(3u, 6u) to Rational(162), + listOf(4u, 6u) to Rational(405, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(0, 6), + listOf(1u) to Rational(14, 8), + listOf(2u) to Rational(-14, 2), + listOf(0u, 1u) to Rational(-3, 5), + listOf(1u, 1u) to Rational(11, 1), + listOf(2u, 1u) to Rational(3, 7), + listOf(0u, 2u) to Rational(-3, 7), + listOf(1u, 2u) to Rational(-18, 5), + listOf(2u, 2u) to Rational(-9, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_Polynomial_substitute_RationalFunction_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-194071, 4900), + listOf(3u, 1u) to Rational(394811, 225), + listOf(2u, 2u) to Rational(-444183161, 66150), + listOf(1u, 3u) to Rational(70537618, 59535), + listOf(0u, 4u) to Rational(9655504, 2835), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(9, 1), + listOf(3u, 1u) to Rational(61, 1), + listOf(2u, 2u) to Rational(2137, 36), + listOf(1u, 3u) to Rational(-1342, 9), + listOf(0u, 4u) to Rational(484, 9), + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(17, 7), + listOf(0u, 1u) to Rational(-13, 1), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-18, 6), + listOf(0u, 1u) to Rational(11, 6), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(18, 5), + listOf(0u, 1u) to Rational(-16, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(-4, 1), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 9), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(10, 9), + listOf(0u, 1u) to Rational(13, 3), + listOf(1u, 1u) to Rational(-12, 4), + listOf(2u, 1u) to Rational(3, 6), + listOf(0u, 2u) to Rational(2, 9), + listOf(1u, 2u) to Rational(7, 3), + listOf(2u, 2u) to Rational(16, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 2), + listOf(1u) to Rational(6, 2), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 1), + listOf(1u, 1u) to Rational(-11, 3), + listOf(2u, 1u) to Rational(7, 5), + listOf(0u, 2u) to Rational(8, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(17, 4), + ) + ) + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-6443599, 10000), + listOf(1u) to Rational(166251223, 210000), + listOf(2u) to Rational(-4606805099, 3528000), + listOf(3u) to Rational(51204379, 19600), + listOf(4u) to Rational(-529045460659, 277830000), + listOf(5u) to Rational(2630836709, 1488375), + listOf(6u) to Rational(-42675691369, 25004700), + listOf(7u) to Rational(495825223, 1250235), + listOf(8u) to Rational(-22531756, 1750329), + listOf(0u, 1u) to Rational(-2526552797, 420000), + listOf(1u, 1u) to Rational(31108840471, 2520000), + listOf(2u, 1u) to Rational(-4789740847, 1102500), + listOf(3u, 1u) to Rational(186594307807, 11340000), + listOf(4u, 1u) to Rational(-11677815943, 1488375), + listOf(5u, 1u) to Rational(-181118486447, 27783000), + listOf(6u, 1u) to Rational(-16123292162, 14586075), + listOf(7u, 1u) to Rational(-140339343808, 26254935), + listOf(8u, 1u) to Rational(4570171616, 5250987), + listOf(0u, 2u) to Rational(-181436530573, 10080000), + listOf(1u, 2u) to Rational(6700437957491, 105840000), + listOf(2u, 2u) to Rational(-3527267461, 1417500), + listOf(3u, 2u) to Rational(-38084563451, 5556600), + listOf(4u, 2u) to Rational(-565662040631, 13891500), + listOf(5u, 2u) to Rational(-35479071126397, 583443000), + listOf(6u, 2u) to Rational(-11717559078469, 525098700), + listOf(7u, 2u) to Rational(-2043385293517, 225042300), + listOf(8u, 2u) to Rational(-3644439630451, 551353635), + listOf(0u, 3u) to Rational(-1760423269, 126000), + listOf(1u, 3u) to Rational(310176758299, 2352000), + listOf(2u, 3u) to Rational(-907229584837, 21168000), + listOf(3u, 3u) to Rational(-16717135885963, 95256000), + listOf(4u, 3u) to Rational(-43762928025353, 333396000), + listOf(5u, 3u) to Rational(-328427480571607, 3000564000), + listOf(6u, 3u) to Rational(-7722675917197, 210039480), + listOf(7u, 3u) to Rational(1713350137019, 1225230300), + listOf(8u, 3u) to Rational(156695935643, 31505922), + listOf(0u, 4u) to Rational(18362364269, 1008000), + listOf(1u, 4u) to Rational(955674858553, 10584000), + listOf(2u, 4u) to Rational(-71937470607371, 444528000), + listOf(3u, 4u) to Rational(-34097985615163, 95256000), + listOf(4u, 4u) to Rational(-340736178775883, 2000376000), + listOf(5u, 4u) to Rational(-511324523441897, 10501974000), + listOf(6u, 4u) to Rational(-125375649409151, 8821658160), + listOf(7u, 4u) to Rational(-2813518533421, 1575296100), + listOf(8u, 4u) to Rational(-17044089109, 5250987), + listOf(0u, 5u) to Rational(600086461, 20160), + listOf(1u, 5u) to Rational(-18959931367, 423360), + listOf(2u, 5u) to Rational(-9178804929607, 44452800), + listOf(3u, 5u) to Rational(-1460114275979, 5334336), + listOf(4u, 5u) to Rational(-342533479090169, 4200789600), + listOf(5u, 5u) to Rational(20335453022963, 4200789600), + listOf(6u, 5u) to Rational(-21649775090197, 6301184400), + listOf(7u, 5u) to Rational(-197301716069, 131274675), + listOf(8u, 5u) to Rational(18711357470, 15752961), + listOf(0u, 6u) to Rational(621417991, 100800), + listOf(1u, 6u) to Rational(-159236792977, 2116800), + listOf(2u, 6u) to Rational(-6602528890883, 66679200), + listOf(3u, 6u) to Rational(-1086091664047, 19051200), + listOf(4u, 6u) to Rational(3769375009003, 1680315840), + listOf(5u, 6u) to Rational(-12920385574769, 1050197400), + listOf(6u, 6u) to Rational(-90219591809287, 6301184400), + listOf(7u, 6u) to Rational(656361553391, 1575296100), + listOf(8u, 6u) to Rational(757900793, 2250423), + listOf(0u, 7u) to Rational(-100770017, 15120), + listOf(1u, 7u) to Rational(-316364851, 17640), + listOf(2u, 7u) to Rational(-85118560057, 6667920), + listOf(3u, 7u) to Rational(6286563719, 416745), + listOf(4u, 7u) to Rational(26803885301, 1714608), + listOf(5u, 7u) to Rational(-13767154393, 4286520), + listOf(6u, 7u) to Rational(-3875138933, 1224720), + listOf(7u, 7u) to Rational(65193755, 333396), + listOf(8u, 7u) to Rational(90974351, 2500470), + listOf(0u, 8u) to Rational(-3182197, 1260), + listOf(1u, 8u) to Rational(24899923, 8820), + listOf(2u, 8u) to Rational(-19999556, 19845), + listOf(3u, 8u) to Rational(3276587, 3969), + listOf(4u, 8u) to Rational(13719549239, 5000940), + listOf(5u, 8u) to Rational(-961839938, 1250235), + listOf(6u, 8u) to Rational(-198184871, 833490), + listOf(7u, 8u) to Rational(230659711, 5000940), + listOf(8u, 8u) to Rational(292447, 35721) + ), + NumberedPolynomialAsIs( + listOf() to Rational(9, 100), + listOf(1u) to Rational(-21, 50), + listOf(2u) to Rational(293, 700), + listOf(3u) to Rational(29, 210), + listOf(4u) to Rational(3233, 8820), + listOf(5u) to Rational(-289, 441), + listOf(6u) to Rational(-1, 9), + listOf(7u) to Rational(-20, 441), + listOf(8u) to Rational(100, 441), + listOf(0u, 1u) to Rational(-57, 80), + listOf(1u, 1u) to Rational(-121, 400), + listOf(2u, 1u) to Rational(37117, 8400), + listOf(3u, 1u) to Rational(-4853, 3150), + listOf(4u, 1u) to Rational(1166203, 132300), + listOf(5u, 1u) to Rational(-2708, 567), + listOf(6u, 1u) to Rational(-287159, 416745), + listOf(7u, 1u) to Rational(-478204, 83349), + listOf(8u, 1u) to Rational(176320, 83349), + listOf(0u, 2u) to Rational(-6239, 6400), + listOf(1u, 2u) to Rational(264211, 11200), + listOf(2u, 2u) to Rational(-1591999, 100800), + listOf(3u, 2u) to Rational(12450091, 529200), + listOf(4u, 2u) to Rational(9230759, 226800), + listOf(5u, 2u) to Rational(18995554, 2083725), + listOf(6u, 2u) to Rational(136706258, 6251175), + listOf(7u, 2u) to Rational(-120907496, 3750705), + listOf(8u, 2u) to Rational(117200176, 15752961), + listOf(0u, 3u) to Rational(5653, 320), + listOf(1u, 3u) to Rational(-130853, 8400), + listOf(2u, 3u) to Rational(-20939327, 151200), + listOf(3u, 3u) to Rational(2566691, 25200), + listOf(4u, 3u) to Rational(-68441519, 476280), + listOf(5u, 3u) to Rational(2462904247, 12502350), + listOf(6u, 3u) to Rational(353667161, 18753525), + listOf(7u, 3u) to Rational(-1689134372, 26254935), + listOf(8u, 3u) to Rational(35084104, 2250423), + listOf(0u, 4u) to Rational(-3587, 300), + listOf(1u, 4u) to Rational(-10513243, 33600), + listOf(2u, 4u) to Rational(30766733, 176400), + listOf(3u, 4u) to Rational(-65680021, 198450), + listOf(4u, 4u) to Rational(-8108910547, 20003760), + listOf(5u, 4u) to Rational(2922125159, 6251175), + listOf(6u, 4u) to Rational(-4245279943, 131274675), + listOf(7u, 4u) to Rational(-371946872, 3750705), + listOf(8u, 4u) to Rational(61286752, 2250423), + listOf(0u, 5u) to Rational(-20477, 160), + listOf(1u, 5u) to Rational(215741, 1120), + listOf(2u, 5u) to Rational(30785843, 31752), + listOf(3u, 5u) to Rational(-357495959, 317520), + listOf(4u, 5u) to Rational(-1611242993, 10001880), + listOf(5u, 5u) to Rational(345925495, 500094), + listOf(6u, 5u) to Rational(-755948411, 3750705), + listOf(7u, 5u) to Rational(-108643496, 1250235), + listOf(8u, 5u) to Rational(1122512, 35721), + listOf(0u, 6u) to Rational(358037, 2880), + listOf(1u, 6u) to Rational(3895837, 3360), + listOf(2u, 6u) to Rational(359419201, 1270080), + listOf(3u, 6u) to Rational(-158522587, 105840), + listOf(4u, 6u) to Rational(10909002599, 20003760), + listOf(5u, 6u) to Rational(76846972, 138915), + listOf(6u, 6u) to Rational(-327696553, 1250235), + listOf(7u, 6u) to Rational(-1687328, 35721), + listOf(8u, 6u) to Rational(1016836, 35721), + listOf(0u, 7u) to Rational(658, 3), + listOf(1u, 7u) to Rational(48035, 168), + listOf(2u, 7u) to Rational(-5777875, 5292), + listOf(3u, 7u) to Rational(-7893899, 10584), + listOf(4u, 7u) to Rational(10191652, 11907), + listOf(5u, 7u) to Rational(2920121, 23814), + listOf(6u, 7u) to Rational(-2699780, 11907), + listOf(7u, 7u) to Rational(4556, 441), + listOf(8u, 7u) to Rational(3440, 189), + listOf(0u, 8u) to Rational(64, 1), + listOf(1u, 8u) to Rational(-808, 7), + listOf(2u, 8u) to Rational(-360895, 1764), + listOf(3u, 8u) to Rational(257657, 882), + listOf(4u, 8u) to Rational(3779917, 15876), + listOf(5u, 8u) to Rational(-610279, 3969), + listOf(6u, 8u) to Rational(-25091, 441), + listOf(7u, 8u) to Rational(9560, 567), + listOf(8u, 8u) to Rational(400, 81) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(18, 5), + listOf(1u) to Rational(-17, 5), + listOf(2u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(-5, 1), + listOf(2u, 1u) to Rational(-9, 1), + listOf(0u, 2u) to Rational(-8, 8), + listOf(1u, 2u) to Rational(2, 7), + listOf(2u, 2u) to Rational(-13, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-4, 8), + listOf(1u) to Rational(15, 9), + listOf(2u) to Rational(-10, 9), + listOf(0u, 1u) to Rational(5, 3), + listOf(1u, 1u) to Rational(4, 1), + listOf(2u, 1u) to Rational(-2, 7), + listOf(0u, 2u) to Rational(2, 2), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(-18, 9), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-66677, 3500), + listOf(1u) to Rational(-206281, 10500), + listOf(2u) to Rational(-412567, 7056), + listOf(3u) to Rational(-310081, 11025), + listOf(4u) to Rational(-575996, 15435), + listOf(0u, 1u) to Rational(-573701, 4200), + listOf(1u, 1u) to Rational(-2239001, 25200), + listOf(2u, 1u) to Rational(-8817889, 132300), + listOf(3u, 1u) to Rational(2317919, 44100), + listOf(4u, 1u) to Rational(1169471, 6615), + listOf(0u, 2u) to Rational(-4057819, 33600), + listOf(1u, 2u) to Rational(1373311, 12600), + listOf(2u, 2u) to Rational(32433493, 52920), + listOf(3u, 2u) to Rational(4998053, 33075), + listOf(4u, 2u) to Rational(-2147779, 8820), + listOf(0u, 3u) to Rational(2018481, 2240), + listOf(1u, 3u) to Rational(941713, 1440), + listOf(2u, 3u) to Rational(183749, 6615), + listOf(3u, 3u) to Rational(-4631023, 15876), + listOf(4u, 3u) to Rational(25609336, 178605), + listOf(0u, 4u) to Rational(11886431, 6720), + listOf(1u, 4u) to Rational(18433, 504), + listOf(2u, 4u) to Rational(-39613331, 45360), + listOf(3u, 4u) to Rational(681619, 5670), + listOf(4u, 4u) to Rational(-864841, 20412), + listOf(0u, 5u) to Rational(343535, 1008), + listOf(1u, 5u) to Rational(-33583, 72), + listOf(2u, 5u) to Rational(1194625, 9072), + listOf(3u, 5u) to Rational(-62917, 2268), + listOf(4u, 5u) to Rational(157645, 10206), + listOf(0u, 6u) to Rational(-1381, 3), + listOf(1u, 6u) to Rational(919, 36), + listOf(2u, 6u) to Rational(-3053, 36), + listOf(3u, 6u) to Rational(2125, 324), + listOf(4u, 6u) to Rational(-236, 243) + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(1, 4), + listOf(1u) to Rational(-5, 3), + listOf(2u) to Rational(35, 9), + listOf(3u) to Rational(-100, 27), + listOf(4u) to Rational(100, 81), + listOf(0u, 1u) to Rational(-5, 3), + listOf(1u, 1u) to Rational(14, 9), + listOf(2u, 1u) to Rational(1874, 189), + listOf(3u, 1u) to Rational(-620, 63), + listOf(4u, 1u) to Rational(40, 63), + listOf(0u, 2u) to Rational(16, 9), + listOf(1u, 2u) to Rational(365, 21), + listOf(2u, 2u) to Rational(112, 9), + listOf(3u, 2u) to Rational(-464, 63), + listOf(4u, 2u) to Rational(1996, 441), + listOf(0u, 3u) to Rational(10, 3), + listOf(1u, 3u) to Rational(118, 21), + listOf(2u, 3u) to Rational(-272, 21), + listOf(3u, 3u) to Rational(-764, 49), + listOf(4u, 3u) to Rational(8, 7), + listOf(0u, 4u) to Rational(1, 1), + listOf(1u, 4u) to Rational(-10, 7), + listOf(2u, 4u) to Rational(-171, 49), + listOf(3u, 4u) to Rational(20, 7), + listOf(4u, 4u) to Rational(4, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(17, 5), + listOf(1u) to Rational(11, 6), + listOf(2u) to Rational(14, 3), + listOf(0u, 1u) to Rational(17, 1), + listOf(1u, 1u) to Rational(12, 3), + listOf(2u, 1u) to Rational(-6, 2), + listOf(0u, 2u) to Rational(17, 1), + listOf(1u, 2u) to Rational(-4, 3), + listOf(2u, 2u) to Rational(2, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(3, 5), + listOf(1u) to Rational(3, 5), + listOf(2u) to Rational(3, 7), + listOf(0u, 1u) to Rational(-3, 8), + listOf(1u, 1u) to Rational(-1, 1), + listOf(2u, 1u) to Rational(17, 9), + listOf(0u, 2u) to Rational(-8, 1), + listOf(1u, 2u) to Rational(6, 4), + listOf(2u, 2u) to Rational(10, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ), + NumberedPolynomialAsIs(listOf() to Rational(0, 1), + listOf() to Rational(0, 1) + ) + ), + NumberedPolynomialAsIs( + listOf() to Rational(15, 7), + listOf(1u) to Rational(1, 5), + listOf(2u) to Rational(-7, 4), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(-2, 7), + listOf(2u, 1u) to Rational(17, 3), + listOf(0u, 2u) to Rational(2, 6), + listOf(1u, 2u) to Rational(-17, 6), + listOf(2u, 2u) to Rational(-6, 2), + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Double_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs(emptyList() to 0.0), + NumberedPolynomialAsIs(emptyList() to 1.0), + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ), + NumberedPolynomialAsIs( + listOf() to 1.0, + ) + ).substitute(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf()), + 0.001, + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 151.1502229133916, + listOf(0u, 1u) to -262.3790170577034, + listOf(0u, 2u) to 102.5097937392923, + ), + NumberedPolynomialAsIs( + listOf() to -367.9969733169944, + listOf(0u, 1u) to 112.4911133334554, + listOf(0u, 2u) to -469.755906895345, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf( + -8.11707689492641, + )), + 0.001, + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf( + -8.11707689492641, + 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 7.321261307532708, + ), + NumberedPolynomialAsIs( + listOf() to -575.6325831127576, + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substitute(bufferOf( + -8.11707689492641, + 0.795265651276015, + 0.9211194782050933 + )), + 0.001, + "test 5" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Constant_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + Rational(-16, 4), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(22047, 2450), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2204953, 147000), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-939, 200), + listOf(0u, 1u) to Rational(123, 50), + listOf(0u, 2u) to Rational(1059, 200) + ), + NumberedPolynomialAsIs( + listOf() to Rational(121, 25), + listOf(0u, 1u) to Rational(-949, 375), + listOf(0u, 2u) to Rational(-1423, 200) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf( + Rational(7, 5), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, bufferOf()), + "test 5" + ) } @Test - @Ignore fun test_RationalFunction_substitute_Polynomial_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(211, 4), + listOf(2u) to Rational(88, 3), + listOf(3u) to Rational(-63, 8), + listOf(4u) to Rational(441, 16), + listOf(0u, 1u) to Rational(-671, 15), + listOf(1u, 1u) to Rational(-551, 21), + listOf(2u, 1u) to Rational(279, 25), + listOf(3u, 1u) to Rational(231, 20), + listOf(0u, 2u) to Rational(-1436, 1575), + listOf(1u, 2u) to Rational(2471, 250), + listOf(2u, 2u) to Rational(-4919, 100), + listOf(0u, 3u) to Rational(-1464, 125), + listOf(1u, 3u) to Rational(-264, 25), + listOf(0u, 4u) to Rational(576, 25), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(-9, 4), + listOf(2u) to Rational(943, 8), + listOf(3u) to Rational(117, 8), + listOf(4u) to Rational(147, 16), + listOf(0u, 1u) to Rational(289, 90), + listOf(1u, 1u) to Rational(-2692, 15), + listOf(2u, 1u) to Rational(-1629, 140), + listOf(3u, 1u) to Rational(77, 20), + listOf(0u, 2u) to Rational(6187, 75), + listOf(1u, 2u) to Rational(-2879, 175), + listOf(2u, 2u) to Rational(-4919, 300), + listOf(0u, 3u) to Rational(336, 25), + listOf(1u, 3u) to Rational(-88, 25), + listOf(0u, 4u) to Rational(192, 25), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 2), + listOf(0u, 1u) to Rational(8, 5), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-3, 1), + ) + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 1), + listOf(1u) to Rational(-9, 8), + listOf(2u) to Rational(17, 5), + listOf(0u, 1u) to Rational(-2, 3), + listOf(1u, 1u) to Rational(1, 5), + listOf(2u, 1u) to Rational(-11, 7), + listOf(0u, 2u) to Rational(13, 6), + listOf(1u, 2u) to Rational(-15, 2), + listOf(2u, 2u) to Rational(-14, 4), + ) + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1202861, 210), + listOf(1u) to Rational(-215117, 45), + listOf(2u) to Rational(10889651, 19845), + listOf(3u) to Rational(-3503956, 6615), + listOf(4u) to Rational(809066, 2205), + listOf(5u) to Rational(-9056, 735), + listOf(6u) to Rational(5396, 315), + listOf(7u) to Rational(-752, 147), + listOf(8u) to Rational(16, 49), + listOf(0u, 1u) to Rational(1738469, 1470), + listOf(1u, 1u) to Rational(-926238703, 52920), + listOf(2u, 1u) to Rational(-44113982, 6615), + listOf(3u, 1u) to Rational(10423519, 5292), + listOf(4u, 1u) to Rational(3769712, 2205), + listOf(5u, 1u) to Rational(8905046, 6615), + listOf(6u, 1u) to Rational(1186972, 6615), + listOf(7u, 1u) to Rational(22124, 441), + listOf(8u, 1u) to Rational(-1504, 147), + listOf(0u, 2u) to Rational(-54723628, 2205), + listOf(1u, 2u) to Rational(70109407, 1323), + listOf(2u, 2u) to Rational(151072591, 17640), + listOf(3u, 2u) to Rational(1216428107, 52920), + listOf(4u, 2u) to Rational(2587873193, 317520), + listOf(5u, 2u) to Rational(393536369, 79380), + listOf(6u, 2u) to Rational(137614937, 79380), + listOf(7u, 2u) to Rational(566866, 1323), + listOf(8u, 2u) to Rational(41848, 441), + listOf(0u, 3u) to Rational(-19470406, 2205), + listOf(1u, 3u) to Rational(72514195, 882), + listOf(2u, 3u) to Rational(-78090707, 1764), + listOf(3u, 3u) to Rational(-1988237707, 26460), + listOf(4u, 3u) to Rational(-802137919, 17640), + listOf(5u, 3u) to Rational(-139989463, 5880), + listOf(6u, 3u) to Rational(-26066641, 3780), + listOf(7u, 3u) to Rational(-2363369, 1323), + listOf(8u, 3u) to Rational(-108280, 441), + listOf(0u, 4u) to Rational(14878516, 441), + listOf(1u, 4u) to Rational(-253416724, 2205), + listOf(2u, 4u) to Rational(16699157, 840), + listOf(3u, 4u) to Rational(-105220979, 13230), + listOf(4u, 4u) to Rational(208266383, 5880), + listOf(5u, 4u) to Rational(650135309, 26460), + listOf(6u, 4u) to Rational(123808663, 11760), + listOf(7u, 4u) to Rational(8563385, 2646), + listOf(8u, 4u) to Rational(19721, 49), + listOf(0u, 5u) to Rational(675645, 49), + listOf(1u, 5u) to Rational(-70554077, 588), + listOf(2u, 5u) to Rational(157884029, 980), + listOf(3u, 5u) to Rational(489548623, 4410), + listOf(4u, 5u) to Rational(148540519, 17640), + listOf(5u, 5u) to Rational(-5559551, 392), + listOf(6u, 5u) to Rational(-18335711, 1470), + listOf(7u, 5u) to Rational(-38437, 9), + listOf(8u, 5u) to Rational(-29620, 63), + listOf(0u, 6u) to Rational(-727625, 49), + listOf(1u, 6u) to Rational(7046685, 98), + listOf(2u, 6u) to Rational(-334814231, 7056), + listOf(3u, 6u) to Rational(-243971737, 17640), + listOf(4u, 6u) to Rational(-571116659, 35280), + listOf(5u, 6u) to Rational(567538, 315), + listOf(6u, 6u) to Rational(3199768, 315), + listOf(7u, 6u) to Rational(227744, 63), + listOf(8u, 6u) to Rational(23116, 63), + listOf(0u, 7u) to Rational(-27500, 7), + listOf(1u, 7u) to Rational(120125, 3), + listOf(2u, 7u) to Rational(-279200, 3), + listOf(3u, 7u) to Rational(-100160, 7), + listOf(4u, 7u) to Rational(920452, 21), + listOf(5u, 7u) to Rational(226481, 21), + listOf(6u, 7u) to Rational(-34428, 7), + listOf(7u, 7u) to Rational(-6232, 3), + listOf(8u, 7u) to Rational(-608, 3), + listOf(0u, 8u) to Rational(2500, 1), + listOf(1u, 8u) to Rational(-19000, 1), + listOf(2u, 8u) to Rational(37900, 1), + listOf(3u, 8u) to Rational(-1840, 1), + listOf(4u, 8u) to Rational(-17876, 1), + listOf(5u, 8u) to Rational(-1240, 1), + listOf(6u, 8u) to Rational(2788, 1), + listOf(7u, 8u) to Rational(800, 1), + listOf(8u, 8u) to Rational(64, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(162487, 63), + listOf(1u) to Rational(-92713, 54), + listOf(2u) to Rational(802436, 1323), + listOf(3u) to Rational(-55088, 441), + listOf(4u) to Rational(1404034, 9261), + listOf(5u) to Rational(-5804, 1029), + listOf(6u) to Rational(51556, 9261), + listOf(7u) to Rational(-752, 441), + listOf(8u) to Rational(16, 147), + listOf(0u, 1u) to Rational(296071, 441), + listOf(1u, 1u) to Rational(-4991281, 882), + listOf(2u, 1u) to Rational(-18702811, 9261), + listOf(3u, 1u) to Rational(40759043, 27783), + listOf(4u, 1u) to Rational(19768501, 27783), + listOf(5u, 1u) to Rational(14307337, 27783), + listOf(6u, 1u) to Rational(1655684, 27783), + listOf(7u, 1u) to Rational(22124, 1323), + listOf(8u, 1u) to Rational(-1504, 441), + listOf(0u, 2u) to Rational(-27667474, 3087), + listOf(1u, 2u) to Rational(265605901, 12348), + listOf(2u, 2u) to Rational(160360775, 98784), + listOf(3u, 2u) to Rational(1169992093, 148176), + listOf(4u, 2u) to Rational(3978014077, 1333584), + listOf(5u, 2u) to Rational(567058123, 333396), + listOf(6u, 2u) to Rational(205132579, 333396), + listOf(7u, 2u) to Rational(566866, 3969), + listOf(8u, 2u) to Rational(41848, 1323), + listOf(0u, 3u) to Rational(-2228822, 1029), + listOf(1u, 3u) to Rational(80179390, 3087), + listOf(2u, 3u) to Rational(-1378630487, 74088), + listOf(3u, 3u) to Rational(-3385811693, 111132), + listOf(4u, 3u) to Rational(-820686977, 49392), + listOf(5u, 3u) to Rational(-89101027, 10584), + listOf(6u, 3u) to Rational(-37847387, 15876), + listOf(7u, 3u) to Rational(-2363369, 3969), + listOf(8u, 3u) to Rational(-108280, 1323), + listOf(0u, 4u) to Rational(12619982, 1029), + listOf(1u, 4u) to Rational(-277723177, 6174), + listOf(2u, 4u) to Rational(649414169, 49392), + listOf(3u, 4u) to Rational(14457595, 63504), + listOf(4u, 4u) to Rational(139270339, 10584), + listOf(5u, 4u) to Rational(140367961, 15876), + listOf(6u, 4u) to Rational(25467083, 7056), + listOf(7u, 4u) to Rational(8563385, 7938), + listOf(8u, 4u) to Rational(19721, 147), + listOf(0u, 5u) to Rational(643850, 147), + listOf(1u, 5u) to Rational(-11818025, 294), + listOf(2u, 5u) to Rational(33963203, 588), + listOf(3u, 5u) to Rational(207216235, 5292), + listOf(4u, 5u) to Rational(2861021, 1512), + listOf(5u, 5u) to Rational(-6302335, 1176), + listOf(6u, 5u) to Rational(-3738587, 882), + listOf(7u, 5u) to Rational(-38437, 27), + listOf(8u, 5u) to Rational(-29620, 189), + listOf(0u, 6u) to Rational(-248725, 49), + listOf(1u, 6u) to Rational(2478535, 98), + listOf(2u, 6u) to Rational(-399721367, 21168), + listOf(3u, 6u) to Rational(-54309317, 10584), + listOf(4u, 6u) to Rational(-95398327, 21168), + listOf(5u, 6u) to Rational(173750, 189), + listOf(6u, 6u) to Rational(92216, 27), + listOf(7u, 6u) to Rational(227744, 189), + listOf(8u, 6u) to Rational(23116, 189), + listOf(0u, 7u) to Rational(-27500, 21), + listOf(1u, 7u) to Rational(120125, 9), + listOf(2u, 7u) to Rational(-279200, 9), + listOf(3u, 7u) to Rational(-100160, 21), + listOf(4u, 7u) to Rational(920452, 63), + listOf(5u, 7u) to Rational(226481, 63), + listOf(6u, 7u) to Rational(-11476, 7), + listOf(7u, 7u) to Rational(-6232, 9), + listOf(8u, 7u) to Rational(-608, 9), + listOf(0u, 8u) to Rational(2500, 3), + listOf(1u, 8u) to Rational(-19000, 3), + listOf(2u, 8u) to Rational(37900, 3), + listOf(3u, 8u) to Rational(-1840, 3), + listOf(4u, 8u) to Rational(-17876, 3), + listOf(5u, 8u) to Rational(-1240, 3), + listOf(6u, 8u) to Rational(2788, 3), + listOf(7u, 8u) to Rational(800, 3), + listOf(8u, 8u) to Rational(64, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(8, 2), + listOf(1u) to Rational(-15, 5), + listOf(2u) to Rational(2, 7), + listOf(0u, 1u) to Rational(-18, 7), + listOf(1u, 1u) to Rational(-16, 6), + listOf(2u, 1u) to Rational(-13, 3), + listOf(0u, 2u) to Rational(-5, 1), + listOf(1u, 2u) to Rational(17, 1), + listOf(2u, 2u) to Rational(8, 2), + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-409, 6), + listOf(1u) to Rational(-376, 9), + listOf(2u) to Rational(-1781, 81), + listOf(3u) to Rational(-128, 27), + listOf(4u) to Rational(-8, 9), + listOf(0u, 1u) to Rational(18701, 210), + listOf(1u, 1u) to Rational(614183, 7560), + listOf(2u, 1u) to Rational(90941, 1890), + listOf(3u, 1u) to Rational(1802, 135), + listOf(4u, 1u) to Rational(112, 45), + listOf(0u, 2u) to Rational(181421, 315), + listOf(1u, 2u) to Rational(77813, 378), + listOf(2u, 2u) to Rational(598583, 7560), + listOf(3u, 2u) to Rational(85, 27), + listOf(4u, 2u) to Rational(2, 5), + listOf(0u, 3u) to Rational(130997, 315), + listOf(1u, 3u) to Rational(1093, 420), + listOf(2u, 3u) to Rational(9551, 2520), + listOf(3u, 3u) to Rational(-14, 45), + listOf(4u, 3u) to Rational(22, 45), + listOf(0u, 4u) to Rational(-2801, 9), + listOf(1u, 4u) to Rational(4033, 90), + listOf(2u, 4u) to Rational(6429, 80), + listOf(3u, 4u) to Rational(2851, 90), + listOf(4u, 4u) to Rational(293, 45), + listOf(0u, 5u) to Rational(-220, 1), + listOf(1u, 5u) to Rational(127, 1), + listOf(2u, 5u) to Rational(202, 5), + listOf(3u, 5u) to Rational(-63, 5), + listOf(4u, 5u) to Rational(-12, 5), + listOf(0u, 6u) to Rational(100, 1), + listOf(1u, 6u) to Rational(-80, 1), + listOf(2u, 6u) to Rational(-24, 1), + listOf(3u, 6u) to Rational(16, 1), + listOf(4u, 6u) to Rational(4, 1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(5407, 9), + listOf(1u) to Rational(9568, 27), + listOf(2u) to Rational(4996, 27), + listOf(3u) to Rational(352, 9), + listOf(4u) to Rational(22, 3), + listOf(0u, 1u) to Rational(104411, 126), + listOf(1u, 1u) to Rational(6001, 126), + listOf(2u, 1u) to Rational(-796, 21), + listOf(3u, 1u) to Rational(-5389, 126), + listOf(4u, 1u) to Rational(-166, 21), + listOf(0u, 2u) to Rational(-35327, 126), + listOf(1u, 2u) to Rational(53, 252), + listOf(2u, 2u) to Rational(849197, 6048), + listOf(3u, 2u) to Rational(22361, 252), + listOf(4u, 2u) to Rational(773, 42), + listOf(0u, 3u) to Rational(-6067, 21), + listOf(1u, 3u) to Rational(39049, 126), + listOf(2u, 3u) to Rational(80303, 1008), + listOf(3u, 3u) to Rational(-3035, 63), + listOf(4u, 3u) to Rational(-209, 21), + listOf(0u, 4u) to Rational(3113, 21), + listOf(1u, 4u) to Rational(-22345, 126), + listOf(2u, 4u) to Rational(-30931, 1008), + listOf(3u, 4u) to Rational(5837, 126), + listOf(4u, 4u) to Rational(229, 21), + listOf(0u, 5u) to Rational(-2120, 21), + listOf(1u, 5u) to Rational(451, 7), + listOf(2u, 5u) to Rational(422, 21), + listOf(3u, 5u) to Rational(-181, 21), + listOf(4u, 5u) to Rational(-40, 21), + listOf(0u, 6u) to Rational(100, 3), + listOf(1u, 6u) to Rational(-80, 3), + listOf(2u, 6u) to Rational(-8, 1), + listOf(3u, 6u) to Rational(16, 3), + listOf(4u, 6u) to Rational(4, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf( + NumberedPolynomialAsIs( + listOf() to Rational(18, 1), + listOf(1u) to Rational(16, 3), + listOf(2u) to Rational(12, 6), + listOf(0u, 1u) to Rational(13, 1), + listOf(1u, 1u) to Rational(-11, 4), + listOf(2u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(-10, 1), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(2, 1), + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 6), + listOf(1u) to Rational(1, 6), + listOf(2u) to Rational(-2, 9), + listOf(0u, 1u) to Rational(15, 1), + listOf(1u, 1u) to Rational(18, 7), + listOf(2u, 1u) to Rational(2, 5), + listOf(0u, 2u) to Rational(12, 9), + listOf(1u, 2u) to Rational(-3, 5), + listOf(2u, 2u) to Rational(4, 4), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-11, 9), + listOf(1u) to Rational(4, 9), + listOf(2u) to Rational(11, 6), + listOf(0u, 1u) to Rational(-5, 6), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(-1, 7), + listOf(0u, 2u) to Rational(9, 1), + listOf(1u, 2u) to Rational(6, 7), + listOf(2u, 2u) to Rational(1, 3), + ) + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), // not r^(deg(p)(deg(p)+1)/2) as it is now. fun test_RationalFunction_substitute_RationalFunction_Buffer() { - // TODO + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(0) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(4u) to Rational(-17166109, 793800), + listOf(3u, 1u) to Rational(-930960143, 5556600), + listOf(2u, 2u) to Rational(-144665109691, 350065800), + listOf(1u, 3u) to Rational(-17232577, 52920), + listOf(0u, 4u) to Rational(-68141, 1323), + ), + NumberedPolynomialAsIs( + listOf(4u) to Rational(-57522533, 14288400), + listOf(3u, 1u) to Rational(-13085162953, 300056400), + listOf(2u, 2u) to Rational(-92093367341, 525098700), + listOf(1u, 3u) to Rational(-1979342797, 6667920), + listOf(0u, 4u) to Rational(-3082727, 21168), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(11, 5), + listOf(0u, 1u) to Rational(8, 4), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(1, 9), + listOf(0u, 1u) to Rational(11, 7), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-2, 7), + listOf(0u, 1u) to Rational(-4, 3), + ), + NumberedPolynomialAsIs( + listOf(1u) to Rational(3, 6), + listOf(0u, 1u) to Rational(12, 8), + ) + ), + )), + "test 2" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(5, 8), + listOf(1u) to Rational(-12, 6), + listOf(2u) to Rational(7, 6), + listOf(0u, 1u) to Rational(-10, 4), + listOf(1u, 1u) to Rational(-7, 6), + listOf(2u, 1u) to Rational(8, 9), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-13, 4), + listOf(2u, 2u) to Rational(5, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(10, 6), + listOf(1u) to Rational(-18, 6), + listOf(2u) to Rational(5, 1), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(8, 4), + listOf(2u, 1u) to Rational(-4, 9), + listOf(0u, 2u) to Rational(-6, 5), + listOf(1u, 2u) to Rational(-15, 8), + listOf(2u, 2u) to Rational(-18, 5), + ) + ), + )), + "test 3" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-130778291, 76800), + listOf(1u) to Rational(-445270919, 230400), + listOf(2u) to Rational(44578444937, 14515200), + listOf(3u) to Rational(17329402153, 1555200), + listOf(4u) to Rational(89239926809, 2332800), + listOf(5u) to Rational(2808812267, 145152), + listOf(6u) to Rational(-21362661007, 725760), + listOf(7u) to Rational(-258455443, 2016), + listOf(8u) to Rational(-21454693, 96), + listOf(0u, 1u) to Rational(-1002137, 15360), + listOf(1u, 1u) to Rational(-1704849697, 430080), + listOf(2u, 1u) to Rational(-57657676789, 4838400), + listOf(3u, 1u) to Rational(-101331731, 89600), + listOf(4u, 1u) to Rational(5362280079329, 130636800), + listOf(5u, 1u) to Rational(4069896167053, 130636800), + listOf(6u, 1u) to Rational(12011514569, 544320), + listOf(7u, 1u) to Rational(138293195623, 725760), + listOf(8u, 1u) to Rational(6228779419, 48384), + listOf(0u, 2u) to Rational(-32395872823, 8064000), + listOf(1u, 2u) to Rational(-7398505523, 2304000), + listOf(2u, 2u) to Rational(95217051699521, 3048192000), + listOf(3u, 2u) to Rational(198026968812079, 3657830400), + listOf(4u, 2u) to Rational(4291645618499, 228614400), + listOf(5u, 2u) to Rational(-33211690942439, 914457600), + listOf(6u, 2u) to Rational(-637385538163153, 1371686400), + listOf(7u, 2u) to Rational(-138671528276273, 182891520), + listOf(8u, 2u) to Rational(-14566368751, 217728), + listOf(0u, 3u) to Rational(-10538718719, 2016000), + listOf(1u, 3u) to Rational(-1844485375199, 84672000), + listOf(2u, 3u) to Rational(103968665891, 12096000), + listOf(3u, 3u) to Rational(175402107278351, 1828915200), + listOf(4u, 3u) to Rational(8020699588879, 114307200), + listOf(5u, 3u) to Rational(3414841894991, 38102400), + listOf(6u, 3u) to Rational(1848405591611, 4665600), + listOf(7u, 3u) to Rational(39486708738989, 137168640), + listOf(8u, 3u) to Rational(255926289517, 9144576), + listOf(0u, 4u) to Rational(-655379564629, 105840000), + listOf(1u, 4u) to Rational(-208336039441, 127008000), + listOf(2u, 4u) to Rational(40173146771411, 1143072000), + listOf(3u, 4u) to Rational(150473493581239, 2667168000), + listOf(4u, 4u) to Rational(38833783990483, 1143072000), + listOf(5u, 4u) to Rational(-1963676248203053, 4800902400), + listOf(6u, 4u) to Rational(-2598759412825747, 3200601600), + listOf(7u, 4u) to Rational(-192895352019667, 1280240640), + listOf(8u, 4u) to Rational(3737382679, 6858432), + listOf(0u, 5u) to Rational(-16959378721, 1890000), + listOf(1u, 5u) to Rational(-1864802244743, 79380000), + listOf(2u, 5u) to Rational(13449261536489, 666792000), + listOf(3u, 5u) to Rational(215272234137329, 2667168000), + listOf(4u, 5u) to Rational(6040691379277, 83349000), + listOf(5u, 5u) to Rational(153687143525887, 800150400), + listOf(6u, 5u) to Rational(475602854903563, 2400451200), + listOf(7u, 5u) to Rational(27315599358749, 640120320), + listOf(8u, 5u) to Rational(-2630413357, 10668672), + listOf(0u, 6u) to Rational(-6654999511, 2646000), + listOf(1u, 6u) to Rational(-67885252327, 15876000), + listOf(2u, 6u) to Rational(5786776220983, 2667168000), + listOf(3u, 6u) to Rational(60615922629083, 1143072000), + listOf(4u, 6u) to Rational(-34703539637627407, 672126336000), + listOf(5u, 6u) to Rational(-744694192134101, 2240421120), + listOf(6u, 6u) to Rational(-1782470617231, 14817600), + listOf(7u, 6u) to Rational(59123208433, 8890560), + listOf(8u, 6u) to Rational(-141653, 5292), + listOf(0u, 7u) to Rational(-338051969, 441000), + listOf(1u, 7u) to Rational(468850013, 1764000), + listOf(2u, 7u) to Rational(2102343426101, 222264000), + listOf(3u, 7u) to Rational(7836130602007, 1333584000), + listOf(4u, 7u) to Rational(16239111865997, 746807040), + listOf(5u, 7u) to Rational(3824649185383, 88905600), + listOf(6u, 7u) to Rational(56058614459, 3457440), + listOf(7u, 7u) to Rational(-396766339, 493920), + listOf(8u, 7u) to Rational(-165147, 2744), + listOf(0u, 8u) to Rational(-3088619, 58800), + listOf(1u, 8u) to Rational(155343347, 88200), + listOf(2u, 8u) to Rational(100098736469, 7408800), + listOf(3u, 8u) to Rational(109725511381, 7408800), + listOf(4u, 8u) to Rational(-2431199641013, 59270400), + listOf(5u, 8u) to Rational(-102872383249, 3457440), + listOf(6u, 8u) to Rational(1449461309, 576240), + listOf(7u, 8u) to Rational(812775, 1372), + listOf(8u, 8u) to Rational(-16461, 343) + ), + NumberedPolynomialAsIs( + listOf() to Rational(164202773, 230400), + listOf(1u) to Rational(-70345303, 518400), + listOf(2u) to Rational(-4229702731, 4665600), + listOf(3u) to Rational(3262171027, 6998400), + listOf(4u) to Rational(-25423104169, 13996800), + listOf(5u) to Rational(64061869, 349920), + listOf(6u) to Rational(-1655878091, 116640), + listOf(7u) to Rational(-7991441, 648), + listOf(8u) to Rational(-502591, 18), + listOf(0u, 1u) to Rational(-8780429, 3840), + listOf(1u, 1u) to Rational(434272361, 115200), + listOf(2u, 1u) to Rational(429825727, 41472), + listOf(3u, 1u) to Rational(-10066790339, 6998400), + listOf(4u, 1u) to Rational(70022035471, 20995200), + listOf(5u, 1u) to Rational(-32070283493, 1399680), + listOf(6u, 1u) to Rational(-22051101001, 1399680), + listOf(7u, 1u) to Rational(-126493427, 12960), + listOf(8u, 1u) to Rational(3050245, 864), + listOf(0u, 2u) to Rational(-1194654631, 345600), + listOf(1u, 2u) to Rational(-542961452671, 31104000), + listOf(2u, 2u) to Rational(-234000873607, 48988800), + listOf(3u, 2u) to Rational(140520538087, 3628800), + listOf(4u, 2u) to Rational(9215088876563, 130636800), + listOf(5u, 2u) to Rational(27590569647253, 293932800), + listOf(6u, 2u) to Rational(5129057792891, 97977600), + listOf(7u, 2u) to Rational(-106334191, 5103), + listOf(8u, 2u) to Rational(-1024113911, 435456), + listOf(0u, 3u) to Rational(76223843, 6000), + listOf(1u, 3u) to Rational(57425857357, 2592000), + listOf(2u, 3u) to Rational(-2044736497573, 46656000), + listOf(3u, 3u) to Rational(-26155810120031, 293932800), + listOf(4u, 3u) to Rational(-1064419459813, 6998400), + listOf(5u, 3u) to Rational(-753782018389, 4082400), + listOf(6u, 3u) to Rational(-291973360873, 2799360), + listOf(7u, 3u) to Rational(-46372122599, 816480), + listOf(8u, 3u) to Rational(3579859657, 653184), + listOf(0u, 4u) to Rational(-13374241901, 4320000), + listOf(1u, 4u) to Rational(306606499811, 54432000), + listOf(2u, 4u) to Rational(964267124745437, 13716864000), + listOf(3u, 4u) to Rational(21603809415373, 182891520), + listOf(4u, 4u) to Rational(1097860214654027, 6858432000), + listOf(5u, 4u) to Rational(161615254570669, 914457600), + listOf(6u, 4u) to Rational(758415239461, 22861440), + listOf(7u, 4u) to Rational(2585568355471, 274337280), + listOf(8u, 4u) to Rational(-70433747863, 9144576), + listOf(0u, 5u) to Rational(-9582586217, 2520000), + listOf(1u, 5u) to Rational(-19093471394171, 635040000), + listOf(2u, 5u) to Rational(-13010261944411, 381024000), + listOf(3u, 5u) to Rational(-259039825301861, 4572288000), + listOf(4u, 5u) to Rational(-305081119071079, 2286144000), + listOf(5u, 5u) to Rational(-1923114383311, 19595520), + listOf(6u, 5u) to Rational(-14181787253231, 228614400), + listOf(7u, 5u) to Rational(-3959584789, 4354560), + listOf(8u, 5u) to Rational(4691742523, 762048), + listOf(0u, 6u) to Rational(-588323437, 180000), + listOf(1u, 6u) to Rational(5952234691, 52920000), + listOf(2u, 6u) to Rational(21001851056959, 1088640000), + listOf(3u, 6u) to Rational(84668034357563, 2133734400), + listOf(4u, 6u) to Rational(2029754605811557, 25604812800), + listOf(5u, 6u) to Rational(11721216739823, 426746880), + listOf(6u, 6u) to Rational(-8275903187003, 2133734400), + listOf(7u, 6u) to Rational(-4730447299, 2540160), + listOf(8u, 6u) to Rational(-46069985, 21168), + listOf(0u, 7u) to Rational(-75711301, 117600), + listOf(1u, 7u) to Rational(32430417413, 7056000), + listOf(2u, 7u) to Rational(677988533153, 98784000), + listOf(3u, 7u) to Rational(-948417645827, 71124480), + listOf(4u, 7u) to Rational(-11320265215207, 711244800), + listOf(5u, 7u) to Rational(-676438627783, 50803200), + listOf(6u, 7u) to Rational(-7382274253, 1975680), + listOf(7u, 7u) to Rational(6505733, 2205), + listOf(8u, 7u) to Rational(450137, 882), + listOf(0u, 8u) to Rational(-8368253, 78400), + listOf(1u, 8u) to Rational(6833783, 117600), + listOf(2u, 8u) to Rational(4528971133, 5927040), + listOf(3u, 8u) to Rational(146252636617, 29635200), + listOf(4u, 8u) to Rational(8321882556889, 1659571200), + listOf(5u, 8u) to Rational(-4686033011, 1975680), + listOf(6u, 8u) to Rational(-1074445963, 987840), + listOf(7u, 8u) to Rational(-142313, 588), + listOf(8u, 8u) to Rational(-4281, 49) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(14, 4), + listOf(1u) to Rational(7, 6), + listOf(2u) to Rational(7, 2), + listOf(0u, 1u) to Rational(-15, 2), + listOf(1u, 1u) to Rational(-13, 8), + listOf(2u, 1u) to Rational(-14, 3), + listOf(0u, 2u) to Rational(-7, 6), + listOf(1u, 2u) to Rational(7, 4), + listOf(2u, 2u) to Rational(9, 7), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-7, 4), + listOf(1u) to Rational(-6, 3), + listOf(2u) to Rational(-16, 2), + listOf(0u, 1u) to Rational(-15, 5), + listOf(1u, 1u) to Rational(4, 6), + listOf(2u, 1u) to Rational(5, 4), + listOf(0u, 2u) to Rational(-12, 5), + listOf(1u, 2u) to Rational(-18, 2), + listOf(2u, 2u) to Rational(6, 7), + ) + ), + )), + "test 4" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-506213, 2800), + listOf(1u) to Rational(9859, 315), + listOf(2u) to Rational(17384377, 11340), + listOf(3u) to Rational(-9662, 63), + listOf(4u) to Rational(-12563, 4), + listOf(0u, 1u) to Rational(-486293, 22400), + listOf(1u, 1u) to Rational(-6530947, 25200), + listOf(2u, 1u) to Rational(866125, 18144), + listOf(3u, 1u) to Rational(2948747, 2520), + listOf(4u, 1u) to Rational(1196611, 2016), + listOf(0u, 2u) to Rational(-20266021, 117600), + listOf(1u, 2u) to Rational(26656339, 44100), + listOf(2u, 2u) to Rational(19499183, 18144), + listOf(3u, 2u) to Rational(-19801849, 7560), + listOf(4u, 2u) to Rational(-2639635, 1296), + listOf(0u, 3u) to Rational(-5017697, 29400), + listOf(1u, 3u) to Rational(-606007, 1575), + listOf(2u, 3u) to Rational(127494487, 132300), + listOf(3u, 3u) to Rational(166567, 105), + listOf(4u, 3u) to Rational(486403, 18144), + listOf(0u, 4u) to Rational(-32182, 735), + listOf(1u, 4u) to Rational(2420671, 8820), + listOf(2u, 4u) to Rational(-12619193, 26460), + listOf(3u, 4u) to Rational(-6823067, 5670), + listOf(4u, 4u) to Rational(-2311693, 13608), + listOf(0u, 5u) to Rational(-13324, 245), + listOf(1u, 5u) to Rational(1966, 35), + listOf(2u, 5u) to Rational(1052719, 2520), + listOf(3u, 5u) to Rational(19153, 270), + listOf(4u, 5u) to Rational(701, 54), + listOf(0u, 6u) to Rational(4647, 196), + listOf(1u, 6u) to Rational(2197, 28), + listOf(2u, 6u) to Rational(-43853, 336), + listOf(3u, 6u) to Rational(-301, 3), + listOf(4u, 6u) to Rational(34, 3) + ), + NumberedPolynomialAsIs( + listOf() to Rational(-2843, 1600), + listOf(1u) to Rational(-1483, 240), + listOf(2u) to Rational(110623, 1296), + listOf(3u) to Rational(1265, 72), + listOf(4u) to Rational(-5011, 16), + listOf(0u, 1u) to Rational(47743, 1800), + listOf(1u, 1u) to Rational(619229, 32400), + listOf(2u, 1u) to Rational(-5978369, 58320), + listOf(3u, 1u) to Rational(-86081, 1620), + listOf(4u, 1u) to Rational(6325, 72), + listOf(0u, 2u) to Rational(110951, 3360), + listOf(1u, 2u) to Rational(-9550649, 302400), + listOf(2u, 2u) to Rational(6542933, 85050), + listOf(3u, 2u) to Rational(4708291, 38880), + listOf(4u, 2u) to Rational(-433327, 1296), + listOf(0u, 3u) to Rational(56143, 600), + listOf(1u, 3u) to Rational(94243, 720), + listOf(2u, 3u) to Rational(-46779139, 226800), + listOf(3u, 3u) to Rational(-6948253, 12960), + listOf(4u, 3u) to Rational(-260261, 486), + listOf(0u, 4u) to Rational(-3205317, 19600), + listOf(1u, 4u) to Rational(-201253, 1050), + listOf(2u, 4u) to Rational(332192677, 302400), + listOf(3u, 4u) to Rational(351511, 360), + listOf(4u, 4u) to Rational(-40547, 81), + listOf(0u, 5u) to Rational(-65421, 1960), + listOf(1u, 5u) to Rational(-10118, 35), + listOf(2u, 5u) to Rational(-4341709, 10080), + listOf(3u, 5u) to Rational(-91703, 360), + listOf(4u, 5u) to Rational(-85, 9), + listOf(0u, 6u) to Rational(-25965, 784), + listOf(1u, 6u) to Rational(3351, 16), + listOf(2u, 6u) to Rational(595159, 1344), + listOf(3u, 6u) to Rational(-1381, 12), + listOf(4u, 6u) to Rational(-155, 3) + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-17, 5), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(14, 1), + listOf(0u, 1u) to Rational(-6, 6), + listOf(1u, 1u) to Rational(-7, 3), + listOf(2u, 1u) to Rational(-2, 9), + listOf(0u, 2u) to Rational(-9, 6), + listOf(1u, 2u) to Rational(17, 4), + listOf(2u, 2u) to Rational(2, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(5, 4), + listOf(1u) to Rational(-5, 9), + listOf(2u) to Rational(-3, 6), + listOf(0u, 1u) to Rational(6, 5), + listOf(1u, 1u) to Rational(14, 5), + listOf(2u, 1u) to Rational(5, 2), + listOf(0u, 2u) to Rational(-18, 7), + listOf(1u, 2u) to Rational(-8, 2), + listOf(2u, 2u) to Rational(18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(10, 2), + listOf(1u) to Rational(6, 7), + listOf(2u) to Rational(-16, 1), + listOf(0u, 1u) to Rational(13, 8), + listOf(1u, 1u) to Rational(-12, 1), + listOf(2u, 1u) to Rational(16, 8), + listOf(0u, 2u) to Rational(10, 4), + listOf(1u, 2u) to Rational(4, 1), + listOf(2u, 2u) to Rational(-11, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1, 4), + listOf(1u) to Rational(-17, 4), + listOf(2u) to Rational(-14, 8), + listOf(0u, 1u) to Rational(17, 9), + listOf(1u, 1u) to Rational(1, 3), + listOf(2u, 1u) to Rational(7, 6), + listOf(0u, 2u) to Rational(16, 3), + listOf(1u, 2u) to Rational(-17, 1), + listOf(2u, 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, bufferOf>()), + "test 6" + ) } @Test - @Ignore fun test_Polynomial_substituteFully_Double_Buffer() { - // TODO + assertEquals( + 0.0, + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ).substituteFully(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 2" + ) { + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf()) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 3" + ) { + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.0, + )) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 4" + ) { + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + )) + } + assertEquals( + 1.934530767358133, + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + )), + 0.001, + "test 5" + ) + assertEquals( + 1.934530767358133, + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933 + )), + 0.001, + "test 6" + ) + assertEquals( + 1.934530767358133, + NumberedPolynomialAsIs( + listOf() to 0.8597048543814783, + listOf(1u) to 0.22997637465889875, + listOf(2u) to 0.32675302591924016, + listOf(0u, 1u) to 0.4561746111587508, + listOf(1u, 1u) to 0.5304946210170756, + listOf(2u, 1u) to 0.6244313712888998, + listOf(0u, 2u) to 0.2700930201481795, + listOf(1u, 2u) to -0.06962351375204712, + listOf(2u, 2u) to -0.015206988092131501, + ).substituteFully(bufferOf( + 0.4846192734143442, + 0.8400458576651112, + 0.9211194782050933, + 0.4752854632152105 + )), + 0.001, + "test 7" + ) } @Test - @Ignore fun test_Polynomial_substituteFully_Constant_Buffer() { - // TODO + assertEquals( + Rational(0), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ).substituteFully(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 2" + ) { + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf()) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 3" + ) { + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully( + RationalField, bufferOf( + Rational(-2, 5), + ) + ) + } + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + Rational(143, 150), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 4" + ) + assertEquals( + Rational(143, 150), + NumberedPolynomialAsIs( + listOf() to Rational(-3, 2), + listOf(1u) to Rational(8, 6), + listOf(2u) to Rational(14, 6), + listOf(0u, 1u) to Rational(-3, 1), + listOf(1u, 1u) to Rational(-19, 2), + listOf(2u, 1u) to Rational(9, 4), + listOf(0u, 2u) to Rational(5, 5), + listOf(1u, 2u) to Rational(18, 9), + listOf(2u, 2u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + Rational(57, 179), + )), + "test 5" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + Rational(47639065216, 2562890625), + NumberedPolynomialAsIs( + listOf(8u) to Rational(-3, 2), + listOf(7u, 1u) to Rational(8, 6), + listOf(6u, 2u) to Rational(14, 6), + listOf(5u, 3u) to Rational(-3, 1), + listOf(4u, 4u) to Rational(-19, 2), + listOf(3u, 5u) to Rational(9, 4), + listOf(2u, 6u) to Rational(5, 5), + listOf(1u, 7u) to Rational(18, 9), + listOf(0u, 8u) to Rational(5, 2), + ).substituteFully(RationalField, bufferOf( + Rational(-2, 5), + Rational(12, 9), + )), + "test 6" + ) } @Test - @Ignore fun test_RationalFunction_substituteFully_Double_Buffer() { - // TODO + assertEquals( + 0.0, + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 1.0, + listOf(1u) to -2.0, + listOf(2u) to 1.0, + ), + NumberedPolynomialAsIs( + listOf() to 1.0, + ) + ).substituteFully(bufferOf( + 1.0 + )), + 0.001, + "test 1" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 2" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully(bufferOf()) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 3" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully( + bufferOf( + -8.11707689492641, + ) + ) + } + assertEquals( + -0.012718636022899672, + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully(bufferOf( + -8.11707689492641, + 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + -0.012718636022899672, + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to 6.593754860231304, + listOf(1u) to -7.853302571550634, + listOf(2u) to 1.2265042281530025, + listOf(0u, 1u) to 3.762648877294904, + listOf(1u, 1u) to -8.945144619305292, + listOf(2u, 1u) to -5.141384718042281, + listOf(0u, 2u) to 7.359794483988782, + listOf(1u, 2u) to -4.3526172680518815, + listOf(2u, 2u) to 0.907910924854372, + ), + NumberedPolynomialAsIs( + listOf() to 9.533292132172562, + listOf(1u) to -1.982814534018857, + listOf(2u) to -5.974248303415283, + listOf(0u, 1u) to 1.5876716499288879, + listOf(1u, 1u) to -7.535152566659664, + listOf(2u, 1u) to 0.7549300500153517, + listOf(0u, 2u) to -5.242030058021028, + listOf(1u, 2u) to -0.7265704289690582, + listOf(2u, 2u) to -7.139677818189821, + ) + ).substituteFully(bufferOf( + -8.11707689492641, + 0.795265651276015, + 0.9211194782050933 + )), + 0.001, + "test 5" + ) } @Test - @Ignore fun test_RationalFunction_substituteFully_Constant_Buffer() { - // TODO + assertEquals( + Rational(0), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1) + ), + NumberedPolynomialAsIs( + listOf() to Rational(1) + ) + ).substituteFully(RationalField, bufferOf( + Rational(1) + )), + "test 1" + ) + assertEquals( + Rational(-1322820, 2204953), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + Rational(-16, 4), + )), + "test 2" + ) + assertEquals( + Rational(-1322820, 2204953), + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully(RationalField, bufferOf( + Rational(7, 5), + Rational(-13, 7), + )), + "test 3" + ) + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 4" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully( + RationalField, bufferOf( + Rational(7, 5), + ) + ) + } + assertFailsWithTypeAndMessage( + fullSubstitutionExceptionMessage, + "test 5" + ) { + NumberedRationalFunction( + NumberedPolynomialAsIs( + listOf() to Rational(-3, 5), + listOf(1u) to Rational(-18, 4), + listOf(2u) to Rational(9, 8), + listOf(0u, 1u) to Rational(-11, 6), + listOf(1u, 1u) to Rational(-16, 3), + listOf(2u, 1u) to Rational(12, 2), + listOf(0u, 2u) to Rational(5, 3), + listOf(1u, 2u) to Rational(17, 8), + listOf(2u, 2u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(11, 1), + listOf(1u) to Rational(4, 1), + listOf(2u) to Rational(-18, 3), + listOf(0u, 1u) to Rational(12, 9), + listOf(1u, 1u) to Rational(14, 7), + listOf(2u, 1u) to Rational(-17, 5), + listOf(0u, 2u) to Rational(-4, 1), + listOf(1u, 2u) to Rational(-5, 5), + listOf(2u, 2u) to Rational(-7, 8), + ) + ).substituteFully(RationalField, bufferOf()) + } } @Test @Ignore diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt index bf8675675..3ad482454 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.test.misc import space.kscience.kmath.functions.NumberedPolynomial import space.kscience.kmath.functions.NumberedRationalFunction import kotlin.test.assertEquals +import kotlin.test.assertFailsWith fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { @@ -45,4 +46,15 @@ fun assertEquals( absoluteTolerance, message ) -} \ No newline at end of file +} + +inline fun assertFailsWithTypeAndMessage( + expectedMessage: String? = null, + assertionMessage: String? = null, + block: () -> Unit +) = + assertEquals( + expectedMessage, + assertFailsWith(T::class, assertionMessage, block).message, + assertionMessage + ) \ No newline at end of file From 39088ec36b3ab7635889fc5ca593f6684021bf54 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 02:36:46 +0300 Subject: [PATCH 106/174] Replaced assertFailsWith with assertFailsWithTypeAndMessage. --- .../kmath/functions/ListPolynomialUtilTest.kt | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 9d4f4411b..685a2a506 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -8,16 +8,22 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertFailsWith @OptIn(UnstableKMathAPI::class) class ListPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double() { + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) assertEquals( 0.0, ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), @@ -859,7 +865,10 @@ class ListPolynomialUtilTest { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), "test 1" ) - assertFailsWith("test2") { + assertFailsWithTypeAndMessage( + "Order of derivative must be non-negative", + "test2" + ) { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) } assertEquals( @@ -928,7 +937,10 @@ class ListPolynomialUtilTest { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), "test 1" ) - assertFailsWith("test2") { + assertFailsWithTypeAndMessage( + "Order of antiderivative must be non-negative", + "test2" + ) { ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) } assertEquals( From e89e4e19d35e61240e8cb7fb00d88c4e35087991 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 03:54:28 +0300 Subject: [PATCH 107/174] Return suppresses. --- .../kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt | 2 ++ .../space/kscience/kmath/functions/LabeledRationalFunction.kt | 2 ++ .../kotlin/space/kscience/kmath/functions/ListPolynomial.kt | 2 ++ .../space/kscience/kmath/functions/ListRationalFunction.kt | 2 ++ .../kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt | 2 ++ .../space/kscience/kmath/functions/NumberedRationalFunction.kt | 2 ++ .../space/kscience/kmath/functions/labeledConstructors.kt | 2 +- .../space/kscience/kmath/functions/numberedConstructors.kt | 2 +- .../kotlin/space/kscience/kmath/test/misc/Rational.kt | 1 + 9 files changed, 15 insertions(+), 2 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index f1859ac4b..6d9af631a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index c34d1e46f..e4f2b6c37 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 3f470d5e7..a83b3915a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index 40c6745d9..b744afc51 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 35d0c7448..ad421d7d3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 97dffebe1..0f3c1ced9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index f3fa32334..7a8d961c0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName") +@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") package space.kscience.kmath.functions diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index d561e06ba..7f02ff1e3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:Suppress("FunctionName") +@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") package space.kscience.kmath.functions diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt index 071701593..62b7dc3be 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -9,6 +9,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps +@Suppress("NAME_SHADOWING") class Rational { companion object { val ZERO: Rational = Rational(0L) From e40977647ddf5637855fe9a3171d03895103ef02 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 4 Jul 2022 04:02:08 +0300 Subject: [PATCH 108/174] Added suppresses. --- .../kotlin/space/kscience/kmath/test/misc/IntModulo.kt | 2 ++ .../kotlin/space/kscience/kmath/test/misc/Rational.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt index b3bb4faf7..f6e8457bb 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.test.misc import space.kscience.kmath.functions.ListPolynomial diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt index 62b7dc3be..731621658 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + package space.kscience.kmath.test.misc import space.kscience.kmath.misc.UnstableKMathAPI From 45ed45bd137bb5e5f7547333ca72bf6b3d90b46d Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 5 Jul 2022 03:41:52 +0300 Subject: [PATCH 109/174] Finish tests generation for numbered utilities. Also: - Optimize a bit labeled and numbered differentiation. - Fixed bugs in numbered anti-differentiation. --- .../kscience/kmath/functions/labeledUtil.kt | 12 +- .../kscience/kmath/functions/numberedUtil.kt | 24 +- .../functions/NumberedPolynomialUtilTest.kt | 2816 ++++++++++++++++- 3 files changed, 2823 insertions(+), 29 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt index 4002eb25a..4e799cb43 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -148,7 +148,7 @@ public fun > LabeledPolynomial.derivativeWithRespectTo( variable: Symbol, ): LabeledPolynomial = algebra { LabeledPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= 1u }) { coefficients .forEach { (degs, c) -> if (variable !in degs) return@forEach @@ -179,7 +179,7 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( ): LabeledPolynomial = algebra { if (order == 0u) return this@nthDerivativeWithRespectTo LabeledPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= order }) { coefficients .forEach { (degs, c) -> if (degs.getOrElse(variable) { 0u } < order) return@forEach @@ -213,7 +213,13 @@ public fun > LabeledPolynomial.nthDerivativeWithRespectTo( val filteredVariablesAndOrders = variablesAndOrders.filterValues { it != 0u } if (filteredVariablesAndOrders.isEmpty()) return this@nthDerivativeWithRespectTo LabeledPolynomial( - buildMap(coefficients.size) { + buildMap( + coefficients.count { + variablesAndOrders.all { (variable, order) -> + it.key.getOrElse(variable) { 0u } >= order + } + } + ) { coefficients .forEach { (degs, c) -> if (filteredVariablesAndOrders.any { (variable, order) -> degs.getOrElse(variable) { 0u } < order }) return@forEach diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 9397c1956..9d88cd648 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -352,7 +352,7 @@ public fun > NumberedPolynomial.derivativeWithRespectTo( variable: Int, ): NumberedPolynomial = ring { NumberedPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= 1u }) { coefficients .forEach { (degs, c) -> if (degs.lastIndex < variable) return@forEach @@ -382,7 +382,7 @@ public fun > NumberedPolynomial.nthDerivativeWithRespectTo( ): NumberedPolynomial = ring { if (order == 0u) return this@nthDerivativeWithRespectTo NumberedPolynomial( - buildMap(coefficients.size) { + buildMap(coefficients.count { it.key.getOrElse(variable) { 0u } >= order }) { coefficients .forEach { (degs, c) -> if (degs.lastIndex < variable) return@forEach @@ -451,8 +451,8 @@ public fun > NumberedPolynomial.antiderivativeWithRespectTo( coefficients .forEach { (degs, c) -> put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + 1u }, - c / multiplyByDoubling(one, degs[variable]) + List(max(variable + 1, degs.size)) { degs.getOrElse(it) { 0u } + if (it != variable) 0u else 1u }, + c / multiplyByDoubling(one, degs.getOrElse(variable) { 0u } + 1u) ) } } @@ -474,9 +474,9 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT coefficients .forEach { (degs, c) -> put( - List(max(variable + 1, degs.size)) { if (it != variable) degs[it] else degs[it] + order }, - degs[variable].let { deg -> - (deg downTo deg - order + 1u) + List(max(variable + 1, degs.size)) { degs.getOrElse(it) { 0u } + if (it != variable) 0u else order }, + degs.getOrElse(variable) { 0u }.let { deg -> + (deg + 1u .. deg + order) .fold(c) { acc, ord -> acc / multiplyByDoubling(one, ord) } } ) @@ -501,11 +501,11 @@ public fun > NumberedPolynomial.nthAntiderivativeWithRespectT coefficients .forEach { (degs, c) -> put( - List(max(maxRespectedVariable + 1, degs.size)) { degs[it] + filteredVariablesAndOrders.getOrElse(it) { 0u } }, - filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> - degs[index].let { deg -> - (deg downTo deg - order + 1u) - .fold(acc1) { acc2, ord -> acc2 / multiplyByDoubling(one, ord) } + List(max(maxRespectedVariable + 1, degs.size)) { degs.getOrElse(it) { 0u } + filteredVariablesAndOrders.getOrElse(it) { 0u } }, + filteredVariablesAndOrders.entries.fold(c) { acc1, (variable, order) -> + degs.getOrElse(variable) { 0u }.let { deg -> + (deg + 1u .. deg + order) + .fold(acc1) { acc, ord -> acc / multiplyByDoubling(one, ord) } } } ) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 9e49f1315..1b87d3fcf 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.functions +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.test.misc.Rational @@ -8832,7 +8833,7 @@ class NumberedPolynomialUtilTest { listOf(0u, 2u) to Rational(5, 5), listOf(1u, 2u) to Rational(18, 9), listOf(2u, 2u) to Rational(5, 2), - ).substituteFully(RationalField, bufferOf()) + ).substituteFully(RationalField, bufferOf()) } assertFailsWithTypeAndMessage( fullSubstitutionExceptionMessage, @@ -9200,37 +9201,2824 @@ class NumberedPolynomialUtilTest { listOf(1u, 2u) to Rational(-5, 5), listOf(2u, 2u) to Rational(-7, 8), ) - ).substituteFully(RationalField, bufferOf()) + ).substituteFully(RationalField, bufferOf()) } } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_derivativeWithRespectTo_variable() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).derivativeWithRespectTo(RationalField, 0), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 3), + listOf(1u) to Rational(1, 1), + listOf(2u) to Rational(-33, 8), + listOf(3u) to Rational(72, 1), + listOf(0u, 1u) to Rational(2, 3), + listOf(1u, 1u) to Rational(-22, 1), + listOf(2u, 1u) to Rational(-1, 1), + listOf(3u, 1u) to Rational(-36, 1), + listOf(0u, 2u) to Rational(-8, 5), + listOf(1u, 2u) to Rational(-1, 4), + listOf(2u, 2u) to Rational(12, 7), + listOf(3u, 2u) to Rational(-2, 1), + listOf(0u, 3u) to Rational(16, 8), + listOf(1u, 3u) to Rational(-4, 1), + listOf(2u, 3u) to Rational(9, 2), + listOf(3u, 3u) to Rational(20, 9), + listOf(0u, 4u) to Rational(-10, 1), + listOf(1u, 4u) to Rational(-14, 1), + listOf(2u, 4u) to Rational(3, 7), + listOf(3u, 4u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 0), + "test 2a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-18, 3), + listOf(1u) to Rational(2, 3), + listOf(2u) to Rational(-11, 1), + listOf(3u) to Rational(-1, 3), + listOf(4u) to Rational(-18, 2), + listOf(0u, 1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(-16, 5), + listOf(2u, 1u) to Rational(-1, 4), + listOf(3u, 1u) to Rational(8, 7), + listOf(4u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(9, 7), + listOf(1u, 2u) to Rational(6, 1), + listOf(2u, 2u) to Rational(-6, 1), + listOf(3u, 2u) to Rational(9, 2), + listOf(4u, 2u) to Rational(5, 3), + listOf(0u, 3u) to Rational(-9, 1), + listOf(1u, 3u) to Rational(-40, 1), + listOf(2u, 3u) to Rational(-28, 1), + listOf(3u, 3u) to Rational(4, 7), + listOf(4u, 3u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 1), + "test 2b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(-1, 4), + listOf(2u, 2u) to Rational(12, 7), + listOf(3u, 2u) to Rational(-2, 1), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(-4, 1), + listOf(2u, 3u) to Rational(9, 2), + listOf(3u, 3u) to Rational(20, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(-14, 1), + listOf(2u, 4u) to Rational(3, 7), + listOf(3u, 4u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 0), + "test 3a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(-1, 4), + listOf(3u, 1u) to Rational(8, 7), + listOf(4u, 1u) to Rational(-1, 1), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-6, 1), + listOf(3u, 2u) to Rational(9, 2), + listOf(4u, 2u) to Rational(5, 3), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-28, 1), + listOf(3u, 3u) to Rational(4, 7), + listOf(4u, 3u) to Rational(20, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 1), + "test 3b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2, 3), + listOf(1u) to Rational(1, 1), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(2, 3), + listOf(1u, 1u) to Rational(-22, 1), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-8, 5), + listOf(1u, 2u) to Rational(-1, 4), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, 0), + "test 4a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-18, 3), + listOf(1u) to Rational(2, 3), + listOf(2u) to Rational(-11, 1), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-20, 3), + listOf(1u, 1u) to Rational(-16, 5), + listOf(2u, 1u) to Rational(-1, 4), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, 1), + "test 4b" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, 5), + "test 5" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthDerivativeWithRespectTo_variable_order() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 1u), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 0u), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 3u), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 0, 4u), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 1, 0u), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 1, 1u), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(-33, 4), + listOf(2u) to Rational(216, 1), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(-2, 1), + listOf(2u, 1u) to Rational(-108, 1), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 9a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(18, 7), + listOf(1u, 1u) to Rational(12, 1), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(-27, 1), + listOf(1u, 2u) to Rational(-120, 1), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 9b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 10a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 10b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, 0, 2u), + "test 11a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, 1, 2u), + "test 11b" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthDerivativeWithRespectTo_variablesAndOrders() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u)), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 0u)), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 3u)), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 4u)), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 0u)), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 1u)), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-2), + listOf(1u) to Rational(2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + 0 to 1u, + 1 to 0u + )), + "test 10" + ) + assertEquals( + NumberedPolynomialAsIs(), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + 0 to 0u, + 1 to 1u + )), + "test 11" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(-33, 4), + listOf(2u) to Rational(216, 1), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(-2, 1), + listOf(2u, 1u) to Rational(-108, 1), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 12a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2, 3), + listOf(1u) to Rational(-22, 1), + listOf(2u) to Rational(-1, 1), + listOf(3u) to Rational(-36, 1), + listOf(0u, 1u) to Rational(-16, 5), + listOf(1u, 1u) to Rational(-1, 2), + listOf(2u, 1u) to Rational(24, 7), + listOf(3u, 1u) to Rational(-4, 1), + listOf(0u, 2u) to Rational(6, 1), + listOf(1u, 2u) to Rational(-12, 1), + listOf(2u, 2u) to Rational(27, 2), + listOf(3u, 2u) to Rational(20, 3), + listOf(0u, 3u) to Rational(-40, 1), + listOf(1u, 3u) to Rational(-56, 1), + listOf(2u, 3u) to Rational(12, 7), + listOf(3u, 3u) to Rational(80, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 12b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(18, 7), + listOf(1u, 1u) to Rational(12, 1), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(-27, 1), + listOf(1u, 2u) to Rational(-120, 1), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 12c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(24, 7), + listOf(2u, 2u) to Rational(-6, 1), + listOf(0u, 3u) to Rational(-4, 1), + listOf(1u, 3u) to Rational(9, 1), + listOf(2u, 3u) to Rational(20, 3), + listOf(0u, 4u) to Rational(-14, 1), + listOf(1u, 4u) to Rational(6, 7), + listOf(2u, 4u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 13a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(-1, 2), + listOf(2u, 1u) to Rational(24, 7), + listOf(3u, 1u) to Rational(-4, 1), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(-12, 1), + listOf(2u, 2u) to Rational(27, 2), + listOf(3u, 2u) to Rational(20, 3), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(-56, 1), + listOf(2u, 3u) to Rational(12, 7), + listOf(3u, 3u) to Rational(80, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 13b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(8, 7), + listOf(4u) to Rational(-1, 1), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(-12, 1), + listOf(3u, 1u) to Rational(9, 1), + listOf(4u, 1u) to Rational(10, 3), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-84, 1), + listOf(3u, 2u) to Rational(12, 7), + listOf(4u, 2u) to Rational(60, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 13c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1, 1), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(-22, 1), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-1, 4), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 14a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(2, 3), + listOf(1u) to Rational(-22, 1), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 1u) to Rational(-16, 5), + listOf(1u, 1u) to Rational(-1, 2), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 14b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(-20, 3), + listOf(1u) to Rational(-16, 5), + listOf(2u) to Rational(-1, 4), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 14c" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_antiderivativeWithRespectTo_variable() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-6, 8), + listOf(2u) to Rational(-1, 3), + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(-11, 32), + listOf(5u) to Rational(18, 5), + listOf(1u, 1u) to Rational(-18, 3), + listOf(2u, 1u) to Rational(1, 3), + listOf(3u, 1u) to Rational(-11, 3), + listOf(4u, 1u) to Rational(-1, 12), + listOf(5u, 1u) to Rational(-18, 10), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(-4, 5), + listOf(3u, 2u) to Rational(-1, 24), + listOf(4u, 2u) to Rational(1, 7), + listOf(5u, 2u) to Rational(-1, 10), + listOf(1u, 3u) to Rational(3, 7), + listOf(2u, 3u) to Rational(1, 1), + listOf(3u, 3u) to Rational(-2, 3), + listOf(4u, 3u) to Rational(3, 8), + listOf(5u, 3u) to Rational(1, 9), + listOf(1u, 4u) to Rational(-18, 8), + listOf(2u, 4u) to Rational(-5, 1), + listOf(3u, 4u) to Rational(-7, 3), + listOf(4u, 4u) to Rational(1, 28), + listOf(5u, 4u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 2a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(-6, 8), + listOf(1u, 1u) to Rational(-2, 3), + listOf(2u, 1u) to Rational(1, 2), + listOf(3u, 1u) to Rational(-11, 8), + listOf(4u, 1u) to Rational(18, 1), + listOf(0u, 2u) to Rational(-9, 3), + listOf(1u, 2u) to Rational(1, 3), + listOf(2u, 2u) to Rational(-11, 2), + listOf(3u, 2u) to Rational(-1, 6), + listOf(4u, 2u) to Rational(-9, 2), + listOf(0u, 3u) to Rational(-10, 9), + listOf(1u, 3u) to Rational(-8, 15), + listOf(2u, 3u) to Rational(-1, 24), + listOf(3u, 3u) to Rational(4, 21), + listOf(4u, 3u) to Rational(-1, 6), + listOf(0u, 4u) to Rational(3, 28), + listOf(1u, 4u) to Rational(1, 2), + listOf(2u, 4u) to Rational(-1, 2), + listOf(3u, 4u) to Rational(3, 8), + listOf(4u, 4u) to Rational(5, 36), + listOf(0u, 5u) to Rational(-9, 20), + listOf(1u, 5u) to Rational(-2, 1), + listOf(2u, 5u) to Rational(-7, 5), + listOf(3u, 5u) to Rational(1, 35), + listOf(4u, 5u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 1), + "test 2b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(-1, 24), + listOf(4u, 2u) to Rational(1, 7), + listOf(5u, 2u) to Rational(-1, 10), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(-2, 3), + listOf(4u, 3u) to Rational(3, 8), + listOf(5u, 3u) to Rational(1, 9), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(-7, 3), + listOf(4u, 4u) to Rational(1, 28), + listOf(5u, 4u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 3a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-1, 24), + listOf(3u, 3u) to Rational(4, 21), + listOf(4u, 3u) to Rational(-1, 6), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-1, 2), + listOf(3u, 4u) to Rational(3, 8), + listOf(4u, 4u) to Rational(5, 36), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(-7, 5), + listOf(3u, 5u) to Rational(1, 35), + listOf(4u, 5u) to Rational(1, 1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 1), + "test 3b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(-6, 8), + listOf(2u) to Rational(-1, 3), + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(1u, 1u) to Rational(-18, 3), + listOf(2u, 1u) to Rational(1, 3), + listOf(3u, 1u) to Rational(-11, 3), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(-4, 5), + listOf(3u, 2u) to Rational(-1, 24), + listOf(4u, 2u) to Rational(0), + listOf(5u, 2u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, 0), + "test 4a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(-6, 8), + listOf(1u, 1u) to Rational(-2, 3), + listOf(2u, 1u) to Rational(1, 2), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-9, 3), + listOf(1u, 2u) to Rational(1, 3), + listOf(2u, 2u) to Rational(-11, 2), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(-10, 9), + listOf(1u, 3u) to Rational(-8, 15), + listOf(2u, 3u) to Rational(-1, 24), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, 1), + "test 4b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 0u, 0u, 0u, 0u, 1u) to Rational(-6, 8), + listOf(1u, 0u, 0u, 0u, 0u, 1u) to Rational(-2, 3), + listOf(2u, 0u, 0u, 0u, 0u, 1u) to Rational(1, 2), + listOf(3u, 0u, 0u, 0u, 0u, 1u) to Rational(-11, 8), + listOf(4u, 0u, 0u, 0u, 0u, 1u) to Rational(18, 1), + listOf(0u, 1u, 0u, 0u, 0u, 1u) to Rational(-18, 3), + listOf(1u, 1u, 0u, 0u, 0u, 1u) to Rational(2, 3), + listOf(2u, 1u, 0u, 0u, 0u, 1u) to Rational(-11, 1), + listOf(3u, 1u, 0u, 0u, 0u, 1u) to Rational(-1, 3), + listOf(4u, 1u, 0u, 0u, 0u, 1u) to Rational(-18, 2), + listOf(0u, 2u, 0u, 0u, 0u, 1u) to Rational(-10, 3), + listOf(1u, 2u, 0u, 0u, 0u, 1u) to Rational(-8, 5), + listOf(2u, 2u, 0u, 0u, 0u, 1u) to Rational(-1, 8), + listOf(3u, 2u, 0u, 0u, 0u, 1u) to Rational(4, 7), + listOf(4u, 2u, 0u, 0u, 0u, 1u) to Rational(-4, 8), + listOf(0u, 3u, 0u, 0u, 0u, 1u) to Rational(3, 7), + listOf(1u, 3u, 0u, 0u, 0u, 1u) to Rational(16, 8), + listOf(2u, 3u, 0u, 0u, 0u, 1u) to Rational(-16, 8), + listOf(3u, 3u, 0u, 0u, 0u, 1u) to Rational(12, 8), + listOf(4u, 3u, 0u, 0u, 0u, 1u) to Rational(5, 9), + listOf(0u, 4u, 0u, 0u, 0u, 1u) to Rational(-18, 8), + listOf(1u, 4u, 0u, 0u, 0u, 1u) to Rational(-10, 1), + listOf(2u, 4u, 0u, 0u, 0u, 1u) to Rational(-14, 2), + listOf(3u, 4u, 0u, 0u, 0u, 1u) to Rational(1, 7), + listOf(4u, 4u, 0u, 0u, 0u, 1u) to Rational(15, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, 5), + "test 5" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthAntiderivativeWithRespectTo_variable_order() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 1u), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 0u), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-1, 3), + listOf(4u) to Rational(1, 12), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(-1, 12), + listOf(5u) to Rational(1, 60), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 3u), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-1, 60), + listOf(6u) to Rational(1, 360), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 4u), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 0u), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(1), + listOf(1u, 1u) to Rational(-2), + listOf(2u, 1u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 1u), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(1, 2), + listOf(1u, 2u) to Rational(-1), + listOf(2u, 2u) to Rational(1, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-11, 160), + listOf(6u) to Rational(3, 5), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(-1, 60), + listOf(6u, 1u) to Rational(-3, 10), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(3, 14), + listOf(3u, 3u) to Rational(1, 3), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(-9, 8), + listOf(3u, 4u) to Rational(-5, 3), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 9a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(-11, 16), + listOf(4u, 2u) to Rational(9, 1), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(-1, 18), + listOf(4u, 3u) to Rational(-9, 6), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(3, 140), + listOf(1u, 5u) to Rational(1, 10), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(-3, 40), + listOf(1u, 6u) to Rational(-1, 3), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 9b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 10a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 10b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(0), + listOf(6u, 2u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(6u, 3u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + listOf(6u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 11a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(0), + listOf(3u, 6u) to Rational(0), + listOf(4u, 6u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 11b" + ) } @Test - @Ignore + @OptIn(UnstableKMathAPI::class) fun test_Polynomial_nthAntiderivativeWithRespectTo_variablesAndOrders() { - // TODO + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u)), + "test 1" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 0u), + "test 2" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-1, 3), + listOf(4u) to Rational(1, 12), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 2u), + "test 3" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(3u) to Rational(1, 6), + listOf(4u) to Rational(-1, 12), + listOf(5u) to Rational(1, 60), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 3u), + "test 4" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-1, 60), + listOf(6u) to Rational(1, 360), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 0, 4u), + "test 5" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 0u), + "test 6" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(1), + listOf(1u, 1u) to Rational(-2), + listOf(2u, 1u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 1u), + "test 7" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(1, 2), + listOf(1u, 2u) to Rational(-1), + listOf(2u, 2u) to Rational(1, 2), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, 1, 2u), + "test 8" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u) to Rational(1), + listOf(2u) to Rational(-1), + listOf(3u) to Rational(1, 3), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + 0 to 1u, + 1 to 0u + )), + "test 10" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 1u) to Rational(1), + listOf(1u, 1u) to Rational(-2), + listOf(2u, 1u) to Rational(1), + ), + NumberedPolynomialAsIs( + listOf() to Rational(1), + listOf(1u) to Rational(-2), + listOf(2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + 0 to 0u, + 1 to 1u + )), + "test 11" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(-11, 160), + listOf(6u) to Rational(3, 5), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(-1, 60), + listOf(6u, 1u) to Rational(-3, 10), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(3, 14), + listOf(3u, 3u) to Rational(1, 3), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(-9, 8), + listOf(3u, 4u) to Rational(-5, 3), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 12a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u, 1u) to Rational(-6, 8), + listOf(2u, 1u) to Rational(-1, 3), + listOf(3u, 1u) to Rational(1, 6), + listOf(4u, 1u) to Rational(-11, 32), + listOf(5u, 1u) to Rational(18, 5), + listOf(1u, 2u) to Rational(-9, 3), + listOf(2u, 2u) to Rational(1, 6), + listOf(3u, 2u) to Rational(-11, 6), + listOf(4u, 2u) to Rational(-1, 24), + listOf(5u, 2u) to Rational(-9, 10), + listOf(1u, 3u) to Rational(-10, 9), + listOf(2u, 3u) to Rational(-4, 15), + listOf(3u, 3u) to Rational(-1, 72), + listOf(4u, 3u) to Rational(1, 21), + listOf(5u, 3u) to Rational(-1, 30), + listOf(1u, 4u) to Rational(3, 28), + listOf(2u, 4u) to Rational(1, 4), + listOf(3u, 4u) to Rational(-1, 6), + listOf(4u, 4u) to Rational(3, 32), + listOf(5u, 4u) to Rational(1, 36), + listOf(1u, 5u) to Rational(-9, 20), + listOf(2u, 5u) to Rational(-1, 1), + listOf(3u, 5u) to Rational(-7, 15), + listOf(4u, 5u) to Rational(1, 140), + listOf(5u, 5u) to Rational(1, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 12b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(-11, 16), + listOf(4u, 2u) to Rational(9, 1), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(-1, 18), + listOf(4u, 3u) to Rational(-9, 6), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(3, 140), + listOf(1u, 5u) to Rational(1, 10), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(-3, 40), + listOf(1u, 6u) to Rational(-1, 3), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(-11, 8), + listOf(4u) to Rational(18, 1), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(-1, 3), + listOf(4u, 1u) to Rational(-18, 2), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(3, 7), + listOf(1u, 3u) to Rational(16, 8), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(-18, 8), + listOf(1u, 4u) to Rational(-10, 1), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 12c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(1, 35), + listOf(6u, 2u) to Rational(-1, 60), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(-1, 6), + listOf(5u, 3u) to Rational(3, 40), + listOf(6u, 3u) to Rational(1, 54), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(-7, 12), + listOf(5u, 4u) to Rational(1, 140), + listOf(6u, 4u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 13a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(5u, 2u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(-1, 72), + listOf(4u, 3u) to Rational(1, 21), + listOf(5u, 3u) to Rational(-1, 30), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(-1, 6), + listOf(4u, 4u) to Rational(3, 32), + listOf(5u, 4u) to Rational(1, 36), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(-7, 15), + listOf(4u, 5u) to Rational(1, 140), + listOf(5u, 5u) to Rational(1, 5), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 13b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(1, 21), + listOf(4u, 4u) to Rational(-1, 24), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(-1, 10), + listOf(3u, 5u) to Rational(3, 40), + listOf(4u, 5u) to Rational(1, 36), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(-7, 30), + listOf(3u, 6u) to Rational(1, 210), + listOf(4u, 6u) to Rational(1, 6), + ), + NumberedPolynomialAsIs( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(4, 7), + listOf(4u, 2u) to Rational(-4, 8), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(-16, 8), + listOf(3u, 3u) to Rational(12, 8), + listOf(4u, 3u) to Rational(5, 9), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(-14, 2), + listOf(3u, 4u) to Rational(1, 7), + listOf(4u, 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 13c" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(2u) to Rational(-3, 8), + listOf(3u) to Rational(-1, 9), + listOf(4u) to Rational(1, 24), + listOf(5u) to Rational(0), + listOf(6u) to Rational(0), + listOf(2u, 1u) to Rational(-9, 3), + listOf(3u, 1u) to Rational(1, 9), + listOf(4u, 1u) to Rational(-11, 12), + listOf(5u, 1u) to Rational(0), + listOf(6u, 1u) to Rational(0), + listOf(2u, 2u) to Rational(-5, 3), + listOf(3u, 2u) to Rational(-4, 15), + listOf(4u, 2u) to Rational(-1, 96), + listOf(5u, 2u) to Rational(0), + listOf(6u, 2u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(6u, 3u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + listOf(6u, 4u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 2u)), + "test 14a" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(1u, 1u) to Rational(-6, 8), + listOf(2u, 1u) to Rational(-1, 3), + listOf(3u, 1u) to Rational(1, 6), + listOf(4u, 1u) to Rational(0), + listOf(5u, 1u) to Rational(0), + listOf(1u, 2u) to Rational(-9, 3), + listOf(2u, 2u) to Rational(1, 6), + listOf(3u, 2u) to Rational(-11, 6), + listOf(4u, 2u) to Rational(0), + listOf(5u, 2u) to Rational(0), + listOf(1u, 3u) to Rational(-10, 9), + listOf(2u, 3u) to Rational(-4, 15), + listOf(3u, 3u) to Rational(-1, 72), + listOf(4u, 3u) to Rational(0), + listOf(5u, 3u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(5u, 4u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + listOf(5u, 5u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(0 to 1u, 1 to 1u)), + "test 14b" + ) + assertEquals( + NumberedPolynomialAsIs( + listOf(0u, 2u) to Rational(-3, 8), + listOf(1u, 2u) to Rational(-1, 3), + listOf(2u, 2u) to Rational(1, 4), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(-1, 1), + listOf(1u, 3u) to Rational(1, 9), + listOf(2u, 3u) to Rational(-11, 6), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(-5, 18), + listOf(1u, 4u) to Rational(-2, 15), + listOf(2u, 4u) to Rational(-1, 96), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + listOf(0u, 5u) to Rational(0), + listOf(1u, 5u) to Rational(0), + listOf(2u, 5u) to Rational(0), + listOf(3u, 5u) to Rational(0), + listOf(4u, 5u) to Rational(0), + listOf(0u, 6u) to Rational(0), + listOf(1u, 6u) to Rational(0), + listOf(2u, 6u) to Rational(0), + listOf(3u, 6u) to Rational(0), + listOf(4u, 6u) to Rational(0), + ), + NumberedPolynomialAsIs( + listOf() to Rational(-6, 8), + listOf(1u) to Rational(-2, 3), + listOf(2u) to Rational(1, 2), + listOf(3u) to Rational(0), + listOf(4u) to Rational(0), + listOf(0u, 1u) to Rational(-18, 3), + listOf(1u, 1u) to Rational(2, 3), + listOf(2u, 1u) to Rational(-11, 1), + listOf(3u, 1u) to Rational(0), + listOf(4u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(-10, 3), + listOf(1u, 2u) to Rational(-8, 5), + listOf(2u, 2u) to Rational(-1, 8), + listOf(3u, 2u) to Rational(0), + listOf(4u, 2u) to Rational(0), + listOf(0u, 3u) to Rational(0), + listOf(1u, 3u) to Rational(0), + listOf(2u, 3u) to Rational(0), + listOf(3u, 3u) to Rational(0), + listOf(4u, 3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + listOf(1u, 4u) to Rational(0), + listOf(2u, 4u) to Rational(0), + listOf(3u, 4u) to Rational(0), + listOf(4u, 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(1 to 2u)), + "test 14c" + ) } } \ No newline at end of file From 5834fad938a973976eff3d0f1cea83df2198ba73 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 6 Jul 2022 00:37:46 +0300 Subject: [PATCH 110/174] Renamed constructing DSLs components. Fixed rejected NumberedPolynomial tests. --- .../kscience/kmath/functions/polynomials.kt | 205 +- .../kmath/functions/labeledConstructors.kt | 23 +- .../kmath/functions/numberedConstructors.kt | 22 +- .../functions/NumberedConstructorsTest.kt | 10 +- .../kmath/functions/NumberedPolynomialTest.kt | 2287 ++++++++--------- 5 files changed, 1270 insertions(+), 1277 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index 273fe5cb9..7843a0210 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke /** @@ -102,7 +103,7 @@ fun numberedPolynomialsExample() { numberedPolynomialSpace { // Also there is DSL for constructing NumberedPolynomials: - val polynomial5: NumberedPolynomial = NumberedPolynomial { + val polynomial5: NumberedPolynomial = NumberedPolynomialDSL1 { 3 {} 5 { 2 inPowerOf 1u } -7 with { 1 pow 2u; 3 pow 1u } @@ -116,7 +117,7 @@ fun numberedPolynomialsExample() { } } - val polynomial6: NumberedPolynomial = with(Int.algebra) { + val polynomial6: NumberedPolynomial = Int.algebra { NumberedPolynomial( listOf() to 7, listOf(0u, 1u) to -5, @@ -127,28 +128,28 @@ fun numberedPolynomialsExample() { // For every ring there can be provided a polynomial ring: Int.algebra.numberedPolynomialSpace { println( - -polynomial6 == NumberedPolynomial { - (-7) {} - 5 { 2 pow 1u } - 0 { 1 pow 2u; 3 pow 1u } - (-4) { 4 pow 4u } - } + -polynomial6 == NumberedPolynomial( + listOf() to -7, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to 0, + listOf(0u, 0u, 0u, 4u) to (-4), + ) ) // true println( - polynomial1 + polynomial6 == NumberedPolynomial { - 10 {} - 0 { 2 pow 1u } - (-7) { 1 pow 2u; 3 pow 1u } - 4 { 4 pow 4u } - } + polynomial1 + polynomial6 == NumberedPolynomial( + listOf() to 10, + listOf(0u, 1u) to 0, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to 4, + ) ) // true println( - polynomial1 - polynomial6 == NumberedPolynomial { - (-4) {} - 10 { 2 pow 1u } - (-7) { 1 pow 2u; 3 pow 1u } - (-4) { 4 pow 4u } - } + polynomial1 - polynomial6 == NumberedPolynomial( + listOf() to -4, + listOf(0u, 1u) to 10, + listOf(2u, 0u, 1u) to -7, + listOf(0u, 0u, 0u, 4u) to -4, + ) ) // true polynomial1 * polynomial6 // Multiplication works too @@ -156,14 +157,14 @@ fun numberedPolynomialsExample() { Double.algebra.numberedPolynomialSpace { // You can even write - val x_1: NumberedPolynomial = NumberedPolynomial { 1.0 { 1 pow 1u } } - val x_2: NumberedPolynomial = NumberedPolynomial { 1.0 { 2 pow 1u } } - val x_3: NumberedPolynomial = NumberedPolynomial { 1.0 { 3 pow 1u } } - val polynomial7: NumberedPolynomial = NumberedPolynomial { - 3.0 {} - 5.0 { 2 pow 1u } - (-7.0) { 1 pow 2u; 3 pow 1u } - } + val x_1: NumberedPolynomial = NumberedPolynomial(listOf(1u) to 1.0) + val x_2: NumberedPolynomial = NumberedPolynomial(listOf(0u, 1u) to 1.0) + val x_3: NumberedPolynomial = NumberedPolynomial(listOf(0u, 0u, 1u) to 1.0) + val polynomial7: NumberedPolynomial = NumberedPolynomial( + listOf() to 3.0, + listOf(0u, 1u) to 5.0, + listOf(2u, 0u, 1u) to -7.0, + ) Double.algebra.listPolynomialSpace { println(3 + 5 * x_2 - 7 * x_1 * x_1 * x_3 == polynomial7) println(3.0 + 5.0 * x_2 - 7.0 * x_1 * x_1 * x_3 == polynomial7) @@ -171,49 +172,49 @@ fun numberedPolynomialsExample() { } Int.algebra.numberedPolynomialSpace { - val x_4: NumberedPolynomial = NumberedPolynomial { 1 { 4 pow 1u } } + val x_4: NumberedPolynomial = NumberedPolynomial(listOf(0u, 0u, 0u, 4u) to 1) // Also there are some utilities for polynomials: println(polynomial1.substitute(mapOf(0 to 1, 1 to -2, 2 to -1)) == 0.asNumberedPolynomial()) // true, // because it's substitution x_1 -> 1, x_2 -> -2, x_3 -> -1, // so 3 + 5 x_2 - 7 x_1^2 x_3 = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 println( - polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial { - 3 {} - 5 { 4 pow 1u } - (-7) { 1 pow 2u; 3 pow 1u } - } + polynomial1.substitute(mapOf(1 to x_4)) == NumberedPolynomial( + listOf() to 3, + listOf(0u, 1u) to 5, + listOf(2u, 0u, 1u) to -7, + ) ) // true, because it's substitution x_2 -> x_4, so result is 3 + 5 x_4 - 7 x_1^2 x_3 println( polynomial1.derivativeWithRespectTo(Int.algebra, 1) == - NumberedPolynomial { 5 {} } + NumberedPolynomial(listOf() to 5) ) // true, d/dx_2 (3 + 5 x_2 - 7 x_1^2 x_3) = 5 } // Lastly, there are rational functions and some other utilities: Double.algebra.numberedRationalFunctionSpace { val rationalFunction1: NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial { - 2.0 {} - (-3.0) { 1 pow 1u } - 1.0 { 1 pow 2u } - }, - NumberedPolynomial { - 3.0 {} - (-1.0) { 1 pow 1u } - } + NumberedPolynomial( + listOf() to 2.0, + listOf(1u) to -3.0, + listOf(2u) to 1.0, + ), + NumberedPolynomial( + listOf() to 3.0, + listOf(1u) to -1.0, + ) ) // It's just (2 - 3x + x^2)/(3 - x) where x = x_1 val rationalFunction2: NumberedRationalFunction = NumberedRationalFunction( - NumberedPolynomial { - 5.0 {} - (-4.0) { 1 pow 1u } - 1.0 { 1 pow 2u } - }, - NumberedPolynomial { - 3.0 {} - (-1.0) { 1 pow 1u } - } + NumberedPolynomial( + listOf() to 5.0, + listOf(1u) to -4.0, + listOf(2u) to 1.0, + ), + NumberedPolynomial( + listOf() to 3.0, + listOf(1u) to -1.0, + ) ) // It's just (5 - 4x + x^2)/(3 - x) where x = x_1 @@ -267,7 +268,7 @@ fun labeledPolynomialsExample() { labeledPolynomialSpace { // Also there is DSL for constructing NumberedPolynomials: - val polynomial5: LabeledPolynomial = LabeledPolynomial { + val polynomial5: LabeledPolynomial = LabeledPolynomialDSL1 { 3 {} 5 { y inPowerOf 1u } -7 with { x pow 2u; z pow 1u } @@ -281,7 +282,7 @@ fun labeledPolynomialsExample() { } } - val polynomial6: LabeledPolynomial = with(Int.algebra) { + val polynomial6: LabeledPolynomial = Int.algebra { LabeledPolynomial( mapOf() to 7, mapOf(y to 1u) to -5, @@ -292,28 +293,28 @@ fun labeledPolynomialsExample() { // For every ring there can be provided a polynomial ring: Int.algebra.labeledPolynomialSpace { println( - -polynomial6 == LabeledPolynomial { - (-7) {} - 5 { y pow 1u } - 0 { x pow 2u; z pow 1u } - (-4) { t pow 4u } - } + -polynomial6 == LabeledPolynomial( + mapOf() to -7, + mapOf(y to 1u) to 5, + mapOf(x to 2u, z to 1u) to 0, + mapOf(t to 4u) to -4, + ) ) // true println( - polynomial1 + polynomial6 == LabeledPolynomial { - 10 {} - 0 { y pow 1u } - (-7) { x pow 2u; z pow 1u } - 4 { t pow 4u } - } + polynomial1 + polynomial6 == LabeledPolynomial( + mapOf() to 10, + mapOf(y to 1u) to 0, + mapOf(x to 2u, z to 1u) to -7, + mapOf(t to 4u) to 4, + ) ) // true println( - polynomial1 - polynomial6 == LabeledPolynomial { - (-4) {} - 10 { y pow 1u } - (-7) { x pow 2u; z pow 1u } - (-4) { t pow 4u } - } + polynomial1 - polynomial6 == LabeledPolynomial( + mapOf() to -4, + mapOf(y to 1u) to 10, + mapOf(x to 2u, z to 1u) to -7, + mapOf(t to 4u) to -4, + ) ) // true polynomial1 * polynomial6 // Multiplication works too @@ -321,11 +322,11 @@ fun labeledPolynomialsExample() { Double.algebra.labeledPolynomialSpace { // You can even write - val polynomial7: LabeledPolynomial = LabeledPolynomial { - 3.0 {} - 5.0 { y pow 1u } - (-7.0) { x pow 2u; z pow 1u } - } + val polynomial7: LabeledPolynomial = LabeledPolynomial( + mapOf() to 3.0, + mapOf(y to 1u) to 5.0, + mapOf(x to 2u, z to 1u) to -7.0, + ) Double.algebra.listPolynomialSpace { println(3 + 5 * y - 7 * x * x * z == polynomial7) println(3.0 + 5.0 * y - 7.0 * x * x * z == polynomial7) @@ -338,42 +339,42 @@ fun labeledPolynomialsExample() { // because it's substitution x -> 1, y -> -2, z -> -1, // so 3 + 5 y - 7 x^2 z = 3 + 5 * (-2) - 7 * 1^2 * (-1) = 3 - 10 + 7 = 0 println( - polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial { - 3 {} - 5 { t pow 1u } - (-7) { x pow 2u; z pow 1u } - } + polynomial1.substitute(mapOf(y to t.asPolynomial())) == LabeledPolynomial( + mapOf() to 3, + mapOf(t to 1u) to 5, + mapOf(x to 2u, z to 1u) to -7, + ) ) // true, because it's substitution y -> t, so result is 3 + 5 t - 7 x^2 z println( - polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial { 5 {} } + polynomial1.derivativeWithRespectTo(Int.algebra, y) == LabeledPolynomial(mapOf() to 5) ) // true, d/dy (3 + 5 y - 7 x^2 z) = 5 } // Lastly, there are rational functions and some other utilities: Double.algebra.labeledRationalFunctionSpace { val rationalFunction1: LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial { - 2.0 {} - (-3.0) { x pow 1u } - 1.0 { x pow 2u } - }, - LabeledPolynomial { - 3.0 {} - (-1.0) { x pow 1u } - } + LabeledPolynomial( + mapOf() to 2.0, + mapOf(x to 1u) to -3.0, + mapOf(x to 2u) to 1.0, + ), + LabeledPolynomial( + mapOf() to 3.0, + mapOf(x to 1u) to -1.0, + ) ) // It's just (2 - 3x + x^2)/(3 - x) val rationalFunction2: LabeledRationalFunction = LabeledRationalFunction( - LabeledPolynomial { - 5.0 {} - (-4.0) { x pow 1u } - 1.0 { x pow 2u } - }, - LabeledPolynomial { - 3.0 {} - (-1.0) { x pow 1u } - } + LabeledPolynomial( + mapOf() to 5.0, + mapOf(x to 1u) to -4.0, + mapOf(x to 2u) to 1.0, + ), + LabeledPolynomial( + mapOf() to 3.0, + mapOf(x to 1u) to -1.0, + ) ) // It's just (5 - 4x + x^2)/(3 - x) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 7a8d961c0..8442d3f91 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -274,14 +274,14 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo */ @DslMarker @UnstableKMathAPI -internal annotation class LabeledPolynomialConstructorDSL +internal annotation class LabeledPolynomialConstructorDSL1 /** * Builder of [LabeledPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. */ @UnstableKMathAPI -@LabeledPolynomialConstructorDSL -public class LabeledPolynomialTermSignatureBuilder { +@LabeledPolynomialConstructorDSL1 +public class DSL1LabeledPolynomialTermSignatureBuilder { /** * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. * Afterward the storage will be used as a resulting signature. @@ -302,7 +302,7 @@ public class LabeledPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Symbol.inPowerOf(deg: UInt) { - signature[this] = deg + signature[this] = signature.getOrElse(this) { 0u } + deg } /** * Declares power of [this] variable of degree [deg]. @@ -328,7 +328,8 @@ public class LabeledPolynomialTermSignatureBuilder { * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. */ @UnstableKMathAPI -public class LabeledPolynomialBuilder( +@LabeledPolynomialConstructorDSL1 +public class DSL1LabeledPolynomialBuilder( /** * Summation operation that will be used to sum coefficients of monomials of same signatures. */ @@ -367,15 +368,15 @@ public class LabeledPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline infix fun C.with(noinline block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + public inline infix fun C.with(noinline block: DSL1LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. * * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline operator fun C.invoke(block: LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = - this with LabeledPolynomialTermSignatureBuilder().apply(block).build() + public inline operator fun C.invoke(block: DSL1LabeledPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with DSL1LabeledPolynomialTermSignatureBuilder().apply(block).build() } // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -398,7 +399,7 @@ public class LabeledPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. * @@ -413,7 +414,7 @@ public class LabeledPolynomialBuilder( * ``` */ @UnstableKMathAPI -public inline fun > LabeledPolynomialSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. * @@ -428,7 +429,7 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * ``` */ @UnstableKMathAPI -public inline fun > LabeledRationalFunctionSpace.LabeledPolynomial(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index 7f02ff1e3..8d2c9e617 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -255,14 +255,14 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere */ @DslMarker @UnstableKMathAPI -internal annotation class NumberedPolynomialConstructorDSL +internal annotation class NumberedPolynomialConstructorDSL1 /** * Builder of [NumberedPolynomial] signature. It should be used as an implicit context for lambdas that describe term signature. */ @UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialTermSignatureBuilder { +@NumberedPolynomialConstructorDSL1 +public class DSL1NumberedPolynomialTermSignatureBuilder { /** * Signature storage. Any declaration of any variable's power updates the storage by increasing corresponding value. * Afterward the storage will be used as a resulting signature. @@ -316,8 +316,8 @@ public class NumberedPolynomialTermSignatureBuilder { * Builder of [NumberedPolynomial]. It should be used as an implicit context for lambdas that describe [NumberedPolynomial]. */ @UnstableKMathAPI -@NumberedPolynomialConstructorDSL -public class NumberedPolynomialBuilder( +@NumberedPolynomialConstructorDSL1 +public class DSL1NumberedPolynomialBuilder( /** * Summation operation that will be used to sum coefficients of monomials of same signatures. */ @@ -356,15 +356,15 @@ public class NumberedPolynomialBuilder( * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline infix fun C.with(noinline block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) + public inline infix fun C.with(noinline block: DSL1NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = this.invoke(block) /** * Declares monomial with [this] coefficient and signature constructed by [block]. * * Declaring another monomial with the same signature will add [this] coefficient to existing one. If the sum of such * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ - public inline operator fun C.invoke(block: NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = - this with NumberedPolynomialTermSignatureBuilder().apply(block).build() + public inline operator fun C.invoke(block: DSL1NumberedPolynomialTermSignatureBuilder.() -> Unit): Unit = + this with DSL1NumberedPolynomialTermSignatureBuilder().apply(block).build() } // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -387,7 +387,7 @@ public class NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * @@ -402,7 +402,7 @@ public class NumberedPolynomialBuilder( * ``` */ @UnstableKMathAPI -public inline fun > NumberedPolynomialSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * @@ -417,7 +417,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * ``` */ @UnstableKMathAPI -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomial(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index 8d1b128cf..f9a5a041b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -15,14 +15,14 @@ import kotlin.test.assertEquals class NumberedConstructorsTest { @Test @UnstableKMathAPI - fun testBuilder() { + fun testDSL1() { assertEquals( NumberedPolynomialAsIs( listOf(2u, 0u, 3u) to 5, listOf(0u, 1u) to -6, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { 1 pow 2u; 3 pow 3u } (-6) { 2 pow 1u } } @@ -34,7 +34,7 @@ class NumberedConstructorsTest { listOf() to -1, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { } (-6) { } } @@ -46,7 +46,7 @@ class NumberedConstructorsTest { listOf(2u) to -1, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { 1 pow 1u; 1 pow 1u } (-6) { 1 pow 2u } } @@ -58,7 +58,7 @@ class NumberedConstructorsTest { listOf(2u) to -1, ), Int.algebra.numberedPolynomialSpace { - NumberedPolynomial { + NumberedPolynomialDSL1 { 5 { 1 pow 1u; 1 pow 1u } (-6) { 1 pow 2u; 3 pow 0u } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index dac7c1a62..f0a1128b4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -14,84 +14,85 @@ import kotlin.test.* @UnstableKMathAPI class NumberedPolynomialTest { + private val o = Rational(0) @Test fun test_Polynomial_Int_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + -3, "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + -3, "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + -3, "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + -3, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) + -3, "test 4" ) - val polynomial_5 = NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_5 = NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_5, polynomial_5 + 0, "test 5" ) - val polynomial_6 = NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_6 = NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_6, polynomial_6 + 0, "test 6" ) - val polynomial_7 = NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_7 = NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_7, polynomial_7 + 0, @@ -103,80 +104,80 @@ class NumberedPolynomialTest { fun test_Polynomial_Int_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - 3, "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - 3, "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - 3, "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - 3, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) - 3, "test 4" ) - val polynomial_5 = NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_5 = NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_5, polynomial_5 - 0, "test 5" ) - val polynomial_6 = NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_6 = NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_6, polynomial_6 - 0, "test 6" ) - val polynomial_7 = NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_7 = NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_7, polynomial_7 - 0, @@ -188,46 +189,46 @@ class NumberedPolynomialTest { fun test_Polynomial_Int_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * 27, + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * 27, "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - } * 15, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ) * 15, "test 2" ) - val polynomial = NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } + val polynomial = NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) assertSame( zero, polynomial * 0, @@ -244,80 +245,80 @@ class NumberedPolynomialTest { fun test_Int_Polynomial_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + -3 + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + -3 + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + -3 + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - -3 + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + -3 + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) - val polynomial_5 = NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_5 = NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_5, 0 + polynomial_5, "test 5" ) - val polynomial_6 = NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_6 = NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_6, 0 + polynomial_6, "test 6" ) - val polynomial_7 = NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + val polynomial_7 = NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) assertSame( polynomial_7, 0 + polynomial_7, @@ -329,91 +330,91 @@ class NumberedPolynomialTest { fun test_Int_Polynomial_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 3 - NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(3, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(3, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 3 - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 3 - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 3 - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + 3 - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 0 - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 0 - NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 0 - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 0 - NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - 0 - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + 0 - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 7" ) } @@ -422,46 +423,46 @@ class NumberedPolynomialTest { fun test_Int_Polynomial_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - 27 * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + 27 * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - 15 * NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + 15 * NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ), "test 2" ) - val polynomial = NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } + val polynomial = NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) assertSame( zero, 0 * polynomial, @@ -478,92 +479,91 @@ class NumberedPolynomialTest { fun test_Polynomial_Constant_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(-3), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(-3), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(-3), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(-3), + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) + Rational(-3), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(0), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(0), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(0), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(0), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } + Rational(0), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) + Rational(0), "test 7" ) } @@ -572,92 +572,91 @@ class NumberedPolynomialTest { fun test_Polynomial_Constant_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(3), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(3), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(3), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(3), + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ) - Rational(3), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(0), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(0), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(0), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(0), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - } - Rational(0), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ) - Rational(0), "test 7" ) } @@ -666,71 +665,71 @@ class NumberedPolynomialTest { fun test_Polynomial_Constant_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * m(27), + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * m(27), "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - } * m(15), + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ) * m(15), "test 2" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * m(0), + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * m(0), "test 3" ) assertEquals( - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - } * m(1), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ) * m(1), "test 4" ) } @@ -739,92 +738,91 @@ class NumberedPolynomialTest { fun test_Constant_Polynomial_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(-3) + NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-3, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-3, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(-3) + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(-3) + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(-3) + NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + Rational(-3) + NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(0) + NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(0) + NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(0) + NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(0) + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, - Rational(0) + NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), + Rational(0) + NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 7" ) } @@ -833,92 +831,92 @@ class NumberedPolynomialTest { fun test_Constant_Polynomial_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(5, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(3) - NumberedPolynomial( + listOf() to Rational(5, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(3, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(3, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(3) - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 1), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(3) - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0, 1) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(3) - NumberedPolynomial { - Rational(27, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), + Rational(3) - NumberedPolynomial( + listOf() to Rational(27, 9), + listOf(3u) to Rational(0), + listOf(0u, 4u) to Rational(0), + ), "test 4" ) assertEquals( - NumberedPolynomial { - Rational(22, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(0) - NumberedPolynomial { - Rational(-22, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(22, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(0) - NumberedPolynomial( + listOf() to Rational(-22, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 5" ) assertEquals( - NumberedPolynomial { - Rational(0, 9) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(0) - NumberedPolynomial { - Rational(0, 9) with {} - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(0) - NumberedPolynomial( + listOf() to Rational(0, 9), + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 6" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(8, 9) with { 1 pow 3u } - Rational(8, 7) with { 2 pow 4u } - }, - Rational(0) - NumberedPolynomial { - Rational(-8, 9) with { 1 pow 3u } - Rational(-8, 7) with { 2 pow 4u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(3u) to Rational(8, 9), + listOf(0u, 4u) to Rational(8, 7), + ), + Rational(0) - NumberedPolynomial( + listOf(3u) to Rational(-8, 9), + listOf(0u, 4u) to Rational(-8, 7), + ), "test 7" ) } @@ -927,71 +925,71 @@ class NumberedPolynomialTest { fun test_Constant_Polynomial_times() { IntModuloRing(35).numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - m(34) with {} - m(2) with { 1 pow 3u } - m(1) with { 2 pow 1u } - m(20) with { 1 pow 1u } - m(2) with { 3 pow 2u } - }, - m(27) * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(34), + listOf(3u) to m(2), + listOf(0u, 1u) to m(1), + listOf(1u) to m(20), + listOf(0u, 0u, 2u) to m(2), + ), + m(27) * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 1" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - m(15) * NumberedPolynomial { - m(7) with {} - m(0) with { 1 pow 3u } - m(49) with { 2 pow 1u } - m(21) with { 1 pow 1u } - m(14) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + m(15) * NumberedPolynomial( + listOf() to m(7), + listOf(3u) to m(0), + listOf(0u, 1u) to m(49), + listOf(1u) to m(21), + listOf(0u, 0u, 2u) to m(14), + ), "test 2" ) assertEquals( - NumberedPolynomial { - m(0) with {} - m(0) with { 1 pow 3u } - m(0) with { 2 pow 1u } - m(0) with { 1 pow 1u } - m(0) with { 3 pow 2u } - }, - m(0) * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(0), + listOf(3u) to m(0), + listOf(0u, 1u) to m(0), + listOf(1u) to m(0), + listOf(0u, 0u, 2u) to m(0), + ), + m(0) * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 3" ) assertEquals( - NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, - m(1) * NumberedPolynomial { - m(22) with {} - m(26) with { 1 pow 3u } - m(13) with { 2 pow 1u } - m(15) with { 1 pow 1u } - m(26) with { 3 pow 2u } - }, + NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), + m(1) * NumberedPolynomial( + listOf() to m(22), + listOf(3u) to m(26), + listOf(0u, 1u) to m(13), + listOf(1u) to m(15), + listOf(0u, 0u, 2u) to m(26), + ), "test 4" ) } @@ -1000,33 +998,33 @@ class NumberedPolynomialTest { fun test_Polynomial_unaryMinus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-5, 9) with { 1 pow 5u } - Rational(8, 9) with {} - Rational(8, 7) with { 7 pow 13u } - }, - -NumberedPolynomial { - Rational(5, 9) with { 1 pow 5u } - Rational(-8, 9) with {} - Rational(-8, 7) with { 7 pow 13u } - }, + NumberedPolynomial( + listOf(5u) to Rational(-5, 9), + listOf() to Rational(8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(8, 7), + ), + -NumberedPolynomial( + listOf(5u) to Rational(5, 9), + listOf() to Rational(-8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(-8, 7), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-5, 9) with { 3 pow 7u } - Rational(8, 9) with {} - Rational(8, 7) with { 1 pow 3u } - Rational(0) with { 2 pow 4u } - Rational(0) with { 1 pow 5u } - }, - -NumberedPolynomial { - Rational(5, 9) with { 3 pow 7u } - Rational(-8, 9) with {} - Rational(-8, 7) with { 1 pow 3u } - Rational(0) with { 2 pow 4u } - Rational(0) with { 1 pow 5u } - }, + NumberedPolynomial( + listOf(5u) to Rational(-5, 9), + listOf() to Rational(8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(8, 7), + listOf(0u, 4u) to Rational(0), + listOf(5u) to Rational(0), + ), + -NumberedPolynomial( + listOf(5u) to Rational(5, 9), + listOf() to Rational(-8, 9), + listOf(0u, 0u, 0u, 0u, 0u, 0u, 13u) to Rational(-8, 7), + listOf(0u, 4u) to Rational(0), + listOf(5u) to Rational(0), + ), "test 2" ) } @@ -1035,137 +1033,137 @@ class NumberedPolynomialTest { fun test_Polynomial_Polynomial_plus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(146, 63) with { 2 pow 1u } - Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } - Rational(61, 15) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(-20, 7) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(7, 9) with { 2 pow 2u } - Rational(5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(146, 63), + listOf(1u, 1u) to Rational(-3, 5), + listOf(2u, 1u) to Rational(61, 15), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(-20, 7), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(7, 9), + listOf(1u, 2u) to Rational(5, 7), + listOf(2u, 2u) to Rational(-2, 3), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(-20, 7) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(7, 9) with { 2 pow 2u } - Rational(5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(-2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(-20, 7), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(7, 9), + listOf(1u, 2u) to Rational(5, 7), + listOf(2u, 2u) to Rational(-2, 3), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(-20, 7) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(-20, 7), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(0) with { 1 pow 1u } - Rational(0) with { 1 pow 2u } - Rational(0) with { 2 pow 1u } - Rational(0) with { 1 pow 1u; 2 pow 1u } - Rational(0) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } + NumberedPolynomial { - Rational(-6, 4) with {} - Rational(2, 6) with { 1 pow 1u } - Rational(-10, 6) with { 1 pow 2u } - Rational(-17, 7) with { 2 pow 1u } - Rational(7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(-12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(-12, 7) with { 2 pow 2u } - Rational(10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(-9, 8) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) + NumberedPolynomial( + listOf() to Rational(-6, 4), + listOf(1u) to Rational(2, 6), + listOf(2u) to Rational(-10, 6), + listOf(0u, 1u) to Rational(-17, 7), + listOf(1u, 1u) to Rational(7, 7), + listOf(2u, 1u) to Rational(-12, 5), + listOf(0u, 2u) to Rational(-12, 7), + listOf(1u, 2u) to Rational(10, 3), + listOf(2u, 2u) to Rational(-9, 8), + ), "test 4" ) } @@ -1174,137 +1172,137 @@ class NumberedPolynomialTest { fun test_Polynomial_Polynomial_minus() { RationalField.numberedPolynomialSpace { assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(146, 63) with { 2 pow 1u } - Rational(-3, 5) with { 1 pow 1u; 2 pow 1u } - Rational(61, 15) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(20, 7) with { 1 pow 2u } - Rational(1, 9) with { 2 pow 1u } - Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(-7, 9) with { 2 pow 2u } - Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(146, 63), + listOf(1u, 1u) to Rational(-3, 5), + listOf(2u, 1u) to Rational(61, 15), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(20, 7), + listOf(0u, 1u) to Rational(1, 9), + listOf(1u, 1u) to Rational(-2, 5), + listOf(2u, 1u) to Rational(-10, 6), + listOf(0u, 2u) to Rational(-7, 9), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(2, 3), + ), "test 1" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(157, 63) with { 2 pow 2u } - Rational(-55, 21) with { 1 pow 1u; 2 pow 2u } - Rational(11, 24) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(20, 7) with { 1 pow 2u } - Rational(1, 9) with { 2 pow 1u } - Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(-7, 9) with { 2 pow 2u } - Rational(-5, 7) with { 1 pow 1u; 2 pow 2u } - Rational(2, 3) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(157, 63), + listOf(1u, 2u) to Rational(-55, 21), + listOf(2u, 2u) to Rational(11, 24), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(20, 7), + listOf(0u, 1u) to Rational(1, 9), + listOf(1u, 1u) to Rational(-2, 5), + listOf(2u, 1u) to Rational(-10, 6), + listOf(0u, 2u) to Rational(-7, 9), + listOf(1u, 2u) to Rational(-5, 7), + listOf(2u, 2u) to Rational(2, 3), + ), "test 2" ) assertEquals( - NumberedPolynomial { - Rational(-17, 2) with {} - Rational(-1, 3) with { 1 pow 1u } - Rational(-25, 21) with { 1 pow 2u } - Rational(-1, 9) with { 2 pow 1u } - Rational(2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(20, 2) with {} - Rational(0, 9) with { 1 pow 1u } - Rational(20, 7) with { 1 pow 2u } - Rational(1, 9) with { 2 pow 1u } - Rational(-2, 5) with { 1 pow 1u; 2 pow 1u } - Rational(-10, 6) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(-17, 2), + listOf(1u) to Rational(-1, 3), + listOf(2u) to Rational(-25, 21), + listOf(0u, 1u) to Rational(-1, 9), + listOf(1u, 1u) to Rational(2, 5), + listOf(2u, 1u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(20, 2), + listOf(1u) to Rational(0, 9), + listOf(2u) to Rational(20, 7), + listOf(0u, 1u) to Rational(1, 9), + listOf(1u, 1u) to Rational(-2, 5), + listOf(2u, 1u) to Rational(-10, 6), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), "test 3" ) assertEquals( - NumberedPolynomial { - Rational(0) with {} - Rational(0) with { 1 pow 1u } - Rational(0) with { 1 pow 2u } - Rational(0) with { 2 pow 1u } - Rational(0) with { 1 pow 1u; 2 pow 1u } - Rational(0) with { 1 pow 2u; 2 pow 1u } - Rational(0) with { 2 pow 2u } - Rational(0) with { 1 pow 1u; 2 pow 2u } - Rational(0) with { 1 pow 2u; 2 pow 2u } - }, - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - } - NumberedPolynomial { - Rational(6, 4) with {} - Rational(-2, 6) with { 1 pow 1u } - Rational(10, 6) with { 1 pow 2u } - Rational(17, 7) with { 2 pow 1u } - Rational(-7, 7) with { 1 pow 1u; 2 pow 1u } - Rational(12, 5) with { 1 pow 2u; 2 pow 1u } - Rational(12, 7) with { 2 pow 2u } - Rational(-10, 3) with { 1 pow 1u; 2 pow 2u } - Rational(9, 8) with { 1 pow 2u; 2 pow 2u } - }, + NumberedPolynomial( + listOf() to Rational(0), + listOf(1u) to Rational(0), + listOf(2u) to Rational(0), + listOf(0u, 1u) to Rational(0), + listOf(1u, 1u) to Rational(0), + listOf(2u, 1u) to Rational(0), + listOf(0u, 2u) to Rational(0), + listOf(1u, 2u) to Rational(0), + listOf(2u, 2u) to Rational(0), + ), + NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ) - NumberedPolynomial( + listOf() to Rational(6, 4), + listOf(1u) to Rational(-2, 6), + listOf(2u) to Rational(10, 6), + listOf(0u, 1u) to Rational(17, 7), + listOf(1u, 1u) to Rational(-7, 7), + listOf(2u, 1u) to Rational(12, 5), + listOf(0u, 2u) to Rational(12, 7), + listOf(1u, 2u) to Rational(-10, 3), + listOf(2u, 2u) to Rational(9, 8), + ), "test 4" ) } @@ -1314,255 +1312,250 @@ class NumberedPolynomialTest { IntModuloRing(35).numberedPolynomialSpace { // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr assertEquals( - NumberedPolynomial { - m(1) with { 1 pow 3u } - m(1) with { 2 pow 3u } - m(1) with { 3 pow 3u } - m(0) with { 1 pow 1u; 2 pow 2u } - m(0) with { 2 pow 1u; 3 pow 2u } - m(0) with { 3 pow 1u; 1 pow 2u } - m(0) with { 1 pow 1u; 3 pow 2u } - m(0) with { 2 pow 1u; 1 pow 2u } - m(0) with { 3 pow 1u; 2 pow 2u } - m(-3) with { 1 pow 1u; 2 pow 1u; 3 pow 1u } - }, - NumberedPolynomial { - m(1) with { 1 pow 1u } - m(1) with { 2 pow 1u } - m(1) with { 3 pow 1u } - } * NumberedPolynomial { - m(1) with { 1 pow 2u } - m(1) with { 2 pow 2u } - m(1) with { 3 pow 2u } - m(-1) with { 1 pow 1u; 2 pow 1u } - m(-1) with { 2 pow 1u; 3 pow 1u } - m(-1) with { 3 pow 1u; 1 pow 1u } - }, + NumberedPolynomial( + listOf(3u) to m(1), + listOf(0u, 3u) to m(1), + listOf(0u, 0u, 3u) to m(1), + listOf(1u, 2u) to m(0), + listOf(0u, 1u, 2u) to m(0), + listOf(2u, 0u, 1u) to m(0), + listOf(1u, 0u, 2u) to m(0), + listOf(2u, 1u) to m(0), + listOf(0u, 2u, 1u) to m(0), + listOf(1u, 1u, 1u) to m(-3), + ), + NumberedPolynomial( + listOf(1u) to m(1), + listOf(0u, 1u) to m(1), + listOf(0u, 0u, 1u) to m(1), + ) * NumberedPolynomial( + listOf(2u) to m(1), + listOf(0u, 2u) to m(1), + listOf(0u, 0u, 2u) to m(1), + listOf(1u, 1u) to m(-1), + listOf(0u, 1u, 1u) to m(-1), + listOf(1u, 0u, 1u) to m(-1), + ), "test 1" ) // Spoiler: 5 * 7 = 0 assertEquals( - NumberedPolynomial { - m(0) with { 1 pow 2u } - m(0) with { 2 pow 2u } - m(0) with { 3 pow 2u } - m(0) with { 1 pow 1u; 2 pow 1u } - m(0) with { 2 pow 1u; 3 pow 1u } - m(0) with { 3 pow 1u; 1 pow 1u } - }, - NumberedPolynomial { - m(5) with { 1 pow 1u } - m(-25) with { 2 pow 1u } - m(10) with { 3 pow 1u } - } * NumberedPolynomial { - m(21) with { 1 pow 1u } - m(14) with { 2 pow 1u } - m(-7) with { 3 pow 1u } - }, + NumberedPolynomial( + listOf(2u) to m(0), + listOf(0u, 2u) to m(0), + listOf(0u, 0u, 2u) to m(0), + listOf(1u, 1u) to m(0), + listOf(0u, 1u, 1u) to m(0), + listOf(1u, 0u, 1u) to m(0), + ), + NumberedPolynomial( + listOf(1u) to m(5), + listOf(0u, 1u) to m(-25), + listOf(0u, 0u, 1u) to m(10), + ) * NumberedPolynomial( + listOf(1u) to m(21), + listOf(0u, 1u) to m(14), + listOf(0u, 0u, 1u) to m(-7), + ), "test 2" ) } } @Test fun test_lastVariable() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( -1, - NumberedPolynomial {}.lastVariable, + NumberedPolynomial().lastVariable, "test 1" ) assertEquals( -1, - NumberedPolynomial { - o {} - }.lastVariable, + NumberedPolynomial( + listOf() to o + ).lastVariable, "test 2" ) assertEquals( 2, - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.lastVariable, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).lastVariable, "test 3" ) assertEquals( 3, - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.also { println(it) }.lastVariable, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).also { println(it) }.lastVariable, "test 4" ) assertEquals( 2, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.lastVariable, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).lastVariable, "test 5" ) } } @Test fun test_degree() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( -1, - NumberedPolynomial {}.degree, + NumberedPolynomial().degree, "test 1" ) assertEquals( 0, - NumberedPolynomial { - o {} - }.degree, + NumberedPolynomial( + listOf() to o + ).degree, "test 2" ) assertEquals( 6, - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.degree, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).degree, "test 3" ) assertEquals( 4, - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.degree, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).degree, "test 4" ) assertEquals( 3, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.degree, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).degree, "test 5" ) assertEquals( 4, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.degree, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).degree, "test 6" ) } } @Test fun test_degrees() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( listOf(), - NumberedPolynomial {}.degrees, + NumberedPolynomial().degrees, "test 1" ) assertEquals( listOf(), - NumberedPolynomial { - o {} - }.degrees, + NumberedPolynomial( + listOf() to o + ).degrees, "test 2" ) assertEquals( listOf(1u, 2u, 3u), - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.degrees, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).degrees, "test 3" ) assertEquals( listOf(0u, 1u, 2u, 1u), - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.degrees, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).degrees, "test 4" ) assertEquals( listOf(2u, 1u, 1u), - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.degrees, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).degrees, "test 5" ) assertEquals( listOf(2u, 2u, 2u, 4u), - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.degrees, + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).degrees, "test 6" ) } } @Test fun test_degreeBy() { - val o = Rational(0) RationalField.numberedPolynomialSpace { fun NumberedPolynomial.collectDegrees(limit: Int = lastVariable + 2): List = List(limit) { degreeBy(it) } assertEquals( listOf(0u), - NumberedPolynomial {}.collectDegrees(), + NumberedPolynomial().collectDegrees(), "test 1" ) assertEquals( listOf(0u), - NumberedPolynomial { - o {} - }.collectDegrees(), + NumberedPolynomial( + listOf() to o + ).collectDegrees(), "test 2" ) assertEquals( listOf(1u, 2u, 3u, 0u), - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.collectDegrees(), + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).collectDegrees(), "test 3" ) assertEquals( listOf(0u, 1u, 2u, 1u, 0u), - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.collectDegrees(), + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).collectDegrees(), "test 4" ) assertEquals( listOf(2u, 1u, 1u, 0u), - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.collectDegrees(), + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).collectDegrees(), "test 5" ) assertEquals( listOf(2u, 2u, 2u, 4u, 0u), - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.collectDegrees(), + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).collectDegrees(), "test 6" ) } } @Test fun test_degreeBy_Collection() { - val o = Rational(0) RationalField.numberedPolynomialSpace { fun NumberedPolynomial.checkDegreeBy(message: String? = null) { val lastVariable = lastVariable @@ -1587,153 +1580,151 @@ class NumberedPolynomialTest { fail("${message ?: ""} Incorrect answer for variable collection $indexCollection: expected $expected, actual $actual") } } - NumberedPolynomial {}.checkDegreeBy("test 1") - NumberedPolynomial { - o {} - }.checkDegreeBy("test 2") - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.checkDegreeBy("test 3") - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.checkDegreeBy("test 4") - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.checkDegreeBy("test 5") - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.checkDegreeBy("test 6") + NumberedPolynomial().checkDegreeBy("test 1") + NumberedPolynomial( + listOf() to o + ).checkDegreeBy("test 2") + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).checkDegreeBy("test 3") + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).checkDegreeBy("test 4") + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).checkDegreeBy("test 5") + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).checkDegreeBy("test 6") } } @Test fun test_countOfVariables() { - val o = Rational(0) RationalField.numberedPolynomialSpace { assertEquals( 0, - NumberedPolynomial {}.countOfVariables, + NumberedPolynomial().countOfVariables, "test 1" ) assertEquals( 0, - NumberedPolynomial { - o {} - }.countOfVariables, + NumberedPolynomial( + listOf() to o + ).countOfVariables, "test 2" ) assertEquals( 3, - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - }.countOfVariables, + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ).countOfVariables, "test 3" ) assertEquals( 3, - NumberedPolynomial { - o { 1 pow 0u; 2 pow 1u; 3 pow 2u; 4 pow 1u; 5 pow 0u } - }.countOfVariables, + NumberedPolynomial( + listOf(0u, 1u, 2u, 1u, 0u) to o + ).countOfVariables, "test 4" ) assertEquals( 3, - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - }.countOfVariables, + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ).countOfVariables, "test 5" ) assertEquals( 4, - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 2 pow 1u; 3 pow 2u } - o { 1 pow 2u; 3 pow 1u } - o { 4 pow 4u } - }.countOfVariables, + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(0u, 1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ).countOfVariables, "test 6" ) } } @Test fun test_RF_countOfVariables() { - val o = Rational(0) RationalField.numberedRationalFunctionSpace { assertEquals( 0, NumberedRationalFunction( - NumberedPolynomial {} + NumberedPolynomial() ).countOfVariables, "test 1" ) assertEquals( 0, NumberedRationalFunction( - NumberedPolynomial {}, - NumberedPolynomial {} + NumberedPolynomial(), + NumberedPolynomial() ).countOfVariables, "test 2" ) assertEquals( 0, NumberedRationalFunction( - NumberedPolynomial { - o {} - } + NumberedPolynomial( + listOf() to o + ) ).countOfVariables, "test 3" ) assertEquals( 3, NumberedRationalFunction( - NumberedPolynomial { - o { 1 pow 1u; 2 pow 2u; 3 pow 3u } - } + NumberedPolynomial( + listOf(1u, 2u, 3u) to o + ) ).countOfVariables, "test 4" ) assertEquals( 3, NumberedRationalFunction( - NumberedPolynomial { - o { 2 pow 1u; 4 pow 1u } - }, - NumberedPolynomial { - o { 1 pow 0u; 3 pow 2u; 5 pow 0u } - } + NumberedPolynomial( + listOf(0u, 1u, 0u, 1u) to o + ), + NumberedPolynomial( + listOf(0u, 0u, 2u) to o + ) ).countOfVariables, "test 5" ) assertEquals( 3, NumberedRationalFunction( - NumberedPolynomial { - o {} - o { 2 pow 1u } - o { 1 pow 2u; 3 pow 1u } - } + NumberedPolynomial( + listOf() to o, + listOf(0u, 1u) to o, + listOf(2u, 0u, 1u) to o, + ) ).countOfVariables, "test 6" ) assertEquals( 4, NumberedRationalFunction( - NumberedPolynomial { - o {} - o { 1 pow 1u; 2 pow 2u } - o { 1 pow 2u; 3 pow 1u } - }, NumberedPolynomial { - o { 2 pow 1u; 3 pow 2u } - o { 4 pow 4u } - } + NumberedPolynomial( + listOf() to o, + listOf(1u, 2u) to o, + listOf(2u, 0u, 1u) to o, + ), NumberedPolynomial( + listOf(0u, 1u, 2u) to o, + listOf(0u, 0u, 0u, 4u) to o, + ) ).countOfVariables, "test 7" ) From 923c52737d4f5ca4e1153757b7079ebc2e19718b Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:13:50 +0300 Subject: [PATCH 111/174] Adapt NumberedPolynomial tests to LabeledPolynomial tests. --- .../kmath/functions/LabeledPolynomial.kt | 42 +- .../kmath/functions/labeledConstructors.kt | 1 + .../functions/LabeledConstructorsTest.kt | 129 + .../kmath/functions/LabeledPolynomialTest.kt | 1872 ++++ .../functions/LabeledPolynomialUtilTest.kt | 8224 +++++++++++++++++ .../kmath/functions/NumberedPolynomialTest.kt | 18 +- .../kscience/kmath/test/misc/assertion.kt | 34 + 7 files changed, 10296 insertions(+), 24 deletions(-) create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 6d9af631a..1477796ea 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -177,14 +177,17 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to sum of [other] copies of [this]. */ public override operator fun LabeledPolynomial.times(other: Int): LabeledPolynomial = - if (other == 0) zero - else LabeledPolynomial( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } - ) + when(other) { + 0 -> zero + 1 -> this + else -> LabeledPolynomial( + coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this[degs]!! * other + } + ) + } /** * Returns sum of the integer represented as a polynomial and the polynomial. @@ -210,7 +213,7 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other + if (this == 0) -other else with(other.coefficients) { if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) else LabeledPolynomialAsIs( @@ -230,14 +233,17 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to sum of [this] copies of [other]. */ public override operator fun Int.times(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) zero - else LabeledPolynomial( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } - ) + when(this) { + 0 -> zero + 1 -> other + else -> LabeledPolynomial( + other.coefficients + .toMutableMap() + .apply { + for (degs in keys) this[degs] = this@times * this[degs]!! + } + ) + } /** * Converts the integer [value] to polynomial. @@ -360,8 +366,6 @@ public class LabeledPolynomialSpace>( else LabeledPolynomialAsIs( toMutableMap() .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - val degs = emptyMap() this[degs] = getOrElse(degs) { constantZero } - other diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index 8442d3f91..819a36449 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -302,6 +302,7 @@ public class DSL1LabeledPolynomialTermSignatureBuilder { * Declaring another power of the same variable will increase its degree by received degree. */ public infix fun Symbol.inPowerOf(deg: UInt) { + if (deg == 0u) return signature[this] = signature.getOrElse(this) { 0u } + deg } /** diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt new file mode 100644 index 000000000..edeaef6a7 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -0,0 +1,129 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +class LabeledConstructorsTest { + val x by symbol + val y by symbol + val z by symbol + val t by symbol + + @Test + @UnstableKMathAPI + fun testDSL1() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { x pow 2u; z pow 3u } + (-6) { y pow 1u } + } + }, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to -1, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { } + (-6) { } + } + }, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to -1, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { x pow 1u; x pow 1u } + (-6) { x pow 2u } + } + }, + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to -1, + ), + Int.algebra.labeledPolynomialSpace { + LabeledPolynomialDSL1 { + 5 { x pow 1u; x pow 1u } + (-6) { x pow 2u; z pow 0u } + } + }, + "test 3" + ) + } + @Test + @UnstableKMathAPI + fun testFabric() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ) + }, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u, z to 3u) to 5, + mapOf(y to 1u) to -6, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 2u, y to 0u, z to 3u, t to 0u) to 5, + mapOf(x to 0u, y to 1u, z to 0u, t to 0u) to -6, + ) + }, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to -1, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 0u) to 5, + mapOf(y to 0u, z to 0u) to -6, + ) + }, + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0, + ), + Int.algebra { + LabeledPolynomial( + mapOf(x to 0u) to 5, + mapOf(z to 0u, t to 0u) to -5, + ) + }, + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt new file mode 100644 index 000000000..15c4c3656 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -0,0 +1,1872 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.test.misc.IntModuloRing +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.m +import kotlin.test.* + + +// TODO: Тесты на конвертацию. +class LabeledPolynomialTest { + val x by symbol + val y by symbol + val z by symbol + val t by symbol + val s by symbol + val iota by symbol + + val o = Rational(0) + + @Test + @Ignore + fun test_Variable_Int_plus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Int_minus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Int_times() { + // TODO + } + @Test + @Ignore + fun test_Int_Variable_plus() { + // TODO + } + @Test + @Ignore + fun test_Int_Variable_minus() { + // TODO + } + @Test + @Ignore + fun test_Int_Variable_times() { + // TODO + } + @Test + fun test_Polynomial_Int_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + -3, + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + -3, + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + -3, + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) + -3, + "test 4" + ) + val polynomial_5 = LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + val polynomial_6 = LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_6, + polynomial_6 + 0, + "test 6" + ) + val polynomial_7 = LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_7, + polynomial_7 + 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - 3, + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - 3, + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - 3, + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) - 3, + "test 4" + ) + val polynomial_5 = LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + val polynomial_6 = LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_6, + polynomial_6 - 0, + "test 6" + ) + val polynomial_7 = LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_7, + polynomial_7 - 0, + "test 7" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * 27, + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ) * 15, + "test 2" + ) + val polynomial = LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + -3 + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + -3 + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + -3 + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + -3 + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + val polynomial_5 = LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + val polynomial_6 = LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_6, + 0 + polynomial_6, + "test 6" + ) + val polynomial_7 = LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + assertSame( + polynomial_7, + 0 + polynomial_7, + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 3 - LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(3, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 3 - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 3 - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + 3 - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 0 - LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 0 - LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + 0 - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 7" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + 27 * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + 15 * LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ), + "test 2" + ) + val polynomial = LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + @Ignore + fun test_Variable_Constant_plus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Constant_minus() { + // TODO + } + @Test + @Ignore + fun test_Variable_Constant_times() { + // TODO + } + @Test + @Ignore + fun test_Constant_Variable_plus() { + // TODO + } + @Test + @Ignore + fun test_Constant_Variable_minus() { + // TODO + } + @Test + @Ignore + fun test_Constant_Variable_times() { + // TODO + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(-3), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(-3), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(-3), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) + Rational(-3), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(0), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(0), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) + Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(3), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(3), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(3), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ) - Rational(3), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(0), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(0), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ) - Rational(0), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * m(27), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ) * m(15), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * m(0), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ) * m(1), + "test 4" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(-3) + LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-3, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(-3) + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(-3) + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + Rational(-3) + LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(0) + LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(0) + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + Rational(0) + LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(3) - LabeledPolynomial( + mapOf() to Rational(5, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(3, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(3) - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 1), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(3) - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + Rational(3) - LabeledPolynomial( + mapOf() to Rational(27, 9), + mapOf(x to 3u) to Rational(0), + mapOf(x to 0u, y to 4u) to Rational(0), + ), + "test 4" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(22, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(0) - LabeledPolynomial( + mapOf() to Rational(-22, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 5" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(0) - LabeledPolynomial( + mapOf() to Rational(0, 9), + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 6" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 3u) to Rational(8, 9), + mapOf(x to 0u, y to 4u) to Rational(8, 7), + ), + Rational(0) - LabeledPolynomial( + mapOf(x to 3u) to Rational(-8, 9), + mapOf(x to 0u, y to 4u) to Rational(-8, 7), + ), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to m(34), + mapOf(x to 3u) to m(2), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 1u) to m(20), + mapOf(x to 0u, y to 0u, z to 2u) to m(2), + ), + m(27) * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + m(15) * LabeledPolynomial( + mapOf() to m(7), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(49), + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 0u, z to 2u) to m(14), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(0), + mapOf(x to 3u) to m(0), + mapOf(x to 0u, y to 1u) to m(0), + mapOf(x to 1u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + ), + m(0) * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + m(1) * LabeledPolynomial( + mapOf() to m(22), + mapOf(x to 3u) to m(26), + mapOf(x to 0u, y to 1u) to m(13), + mapOf(x to 1u) to m(15), + mapOf(x to 0u, y to 0u, z to 2u) to m(26), + ), + "test 4" + ) + } + } + @Test + @Ignore + fun test_Variable_unaryPlus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_unaryMinus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Variable_plus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Variable_minus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Variable_times(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Polynomial_plus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Polynomial_minus(){ + // TODO + } + @Test + @Ignore + fun test_Variable_Polynomial_times(){ + // TODO + } + @Test + @Ignore + fun test_Polynomial_Variable_plus(){ + // TODO + } + @Test + @Ignore + fun test_Polynomial_Variable_minus(){ + // TODO + } + @Test + @Ignore + fun test_Polynomial_Variable_times(){ + // TODO + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf(x to 5u) to Rational(-5, 9), + mapOf() to Rational(8, 9), + mapOf(iota to 13u) to Rational(8, 7), + ), + -LabeledPolynomial( + mapOf(x to 5u) to Rational(5, 9), + mapOf() to Rational(-8, 9), + mapOf(iota to 13u) to Rational(-8, 7), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf(x to 5u) to Rational(-5, 9), + mapOf() to Rational(8, 9), + mapOf(iota to 13u) to Rational(8, 7), + mapOf(x to 0u, y to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + ), + -LabeledPolynomial( + mapOf(x to 5u) to Rational(5, 9), + mapOf() to Rational(-8, 9), + mapOf(iota to 13u) to Rational(-8, 7), + mapOf(x to 0u, y to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + ), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(146, 63), + mapOf(x to 1u, y to 1u) to Rational(-3, 5), + mapOf(x to 2u, y to 1u) to Rational(61, 15), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(-20, 7), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(7, 9), + mapOf(x to 1u, y to 2u) to Rational(5, 7), + mapOf(x to 2u, y to 2u) to Rational(-2, 3), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(-20, 7), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(7, 9), + mapOf(x to 1u, y to 2u) to Rational(5, 7), + mapOf(x to 2u, y to 2u) to Rational(-2, 3), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(-20, 7), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 0u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) + LabeledPolynomial( + mapOf() to Rational(-6, 4), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(-10, 6), + mapOf(x to 0u, y to 1u) to Rational(-17, 7), + mapOf(x to 1u, y to 1u) to Rational(7, 7), + mapOf(x to 2u, y to 1u) to Rational(-12, 5), + mapOf(x to 0u, y to 2u) to Rational(-12, 7), + mapOf(x to 1u, y to 2u) to Rational(10, 3), + mapOf(x to 2u, y to 2u) to Rational(-9, 8), + ), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(146, 63), + mapOf(x to 1u, y to 1u) to Rational(-3, 5), + mapOf(x to 2u, y to 1u) to Rational(61, 15), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(20, 7), + mapOf(x to 0u, y to 1u) to Rational(1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 5), + mapOf(x to 2u, y to 1u) to Rational(-10, 6), + mapOf(x to 0u, y to 2u) to Rational(-7, 9), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(2, 3), + ), + "test 1" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(157, 63), + mapOf(x to 1u, y to 2u) to Rational(-55, 21), + mapOf(x to 2u, y to 2u) to Rational(11, 24), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(20, 7), + mapOf(x to 0u, y to 1u) to Rational(1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 5), + mapOf(x to 2u, y to 1u) to Rational(-10, 6), + mapOf(x to 0u, y to 2u) to Rational(-7, 9), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(2, 3), + ), + "test 2" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(-17, 2), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-25, 21), + mapOf(x to 0u, y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(2, 5), + mapOf(x to 2u, y to 1u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(20, 2), + mapOf(x to 1u) to Rational(0, 9), + mapOf(x to 2u) to Rational(20, 7), + mapOf(x to 0u, y to 1u) to Rational(1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 5), + mapOf(x to 2u, y to 1u) to Rational(-10, 6), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + "test 3" + ) + assertEquals( + LabeledPolynomial( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 0u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 0u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + ), + LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ) - LabeledPolynomial( + mapOf() to Rational(6, 4), + mapOf(x to 1u) to Rational(-2, 6), + mapOf(x to 2u) to Rational(10, 6), + mapOf(x to 0u, y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(-7, 7), + mapOf(x to 2u, y to 1u) to Rational(12, 5), + mapOf(x to 0u, y to 2u) to Rational(12, 7), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(9, 8), + ), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).labeledPolynomialSpace { + // (p + q + r) * (p^2 + q^2 + r^2 - pq - pr - qr) = p^3 + q^3 + r^3 - 3pqr + assertEquals( + LabeledPolynomial( + mapOf(x to 3u) to m(1), + mapOf(x to 0u, y to 3u) to m(1), + mapOf(x to 0u, y to 0u, z to 3u) to m(1), + mapOf(x to 1u, y to 2u) to m(0), + mapOf(x to 0u, y to 1u, z to 2u) to m(0), + mapOf(x to 2u, y to 0u, z to 1u) to m(0), + mapOf(x to 1u, y to 0u, z to 2u) to m(0), + mapOf(x to 2u, y to 1u) to m(0), + mapOf(x to 0u, y to 2u, z to 1u) to m(0), + mapOf(x to 1u, y to 1u, z to 1u) to m(-3), + ), + LabeledPolynomial( + mapOf(x to 1u) to m(1), + mapOf(x to 0u, y to 1u) to m(1), + mapOf(x to 0u, y to 0u, z to 1u) to m(1), + ) * LabeledPolynomial( + mapOf(x to 2u) to m(1), + mapOf(x to 0u, y to 2u) to m(1), + mapOf(x to 0u, y to 0u, z to 2u) to m(1), + mapOf(x to 1u, y to 1u) to m(-1), + mapOf(x to 0u, y to 1u, z to 1u) to m(-1), + mapOf(x to 1u, y to 0u, z to 1u) to m(-1), + ), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + LabeledPolynomial( + mapOf(x to 2u) to m(0), + mapOf(x to 0u, y to 2u) to m(0), + mapOf(x to 0u, y to 0u, z to 2u) to m(0), + mapOf(x to 1u, y to 1u) to m(0), + mapOf(x to 0u, y to 1u, z to 1u) to m(0), + mapOf(x to 1u, y to 0u, z to 1u) to m(0), + ), + LabeledPolynomial( + mapOf(x to 1u) to m(5), + mapOf(x to 0u, y to 1u) to m(-25), + mapOf(x to 0u, y to 0u, z to 1u) to m(10), + ) * LabeledPolynomial( + mapOf(x to 1u) to m(21), + mapOf(x to 0u, y to 1u) to m(14), + mapOf(x to 0u, y to 0u, z to 1u) to m(-7), + ), + "test 2" + ) + } + } + @Test + fun test_degree() { + RationalField.labeledPolynomialSpace { + assertEquals( + -1, + LabeledPolynomial().degree, + "test 1" + ) + assertEquals( + 0, + LabeledPolynomial( + mapOf() to o + ).degree, + "test 2" + ) + assertEquals( + 6, + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).degree, + "test 3" + ) + assertEquals( + 4, + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).degree, + "test 4" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).degree, + "test 5" + ) + assertEquals( + 4, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).degree, + "test 6" + ) + } + } + @Test + fun test_degrees() { + RationalField.labeledPolynomialSpace { + assertEquals( + mapOf(), + LabeledPolynomial().degrees, + "test 1" + ) + assertEquals( + mapOf(), + LabeledPolynomial( + mapOf() to o + ).degrees, + "test 2" + ) + assertEquals( + mapOf(x to 1u, y to 2u, z to 3u), + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).degrees, + "test 3" + ) + assertEquals( + mapOf(y to 1u, z to 2u, t to 1u), + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).degrees, + "test 4" + ) + assertEquals( + mapOf(x to 2u, y to 1u, z to 1u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).degrees, + "test 5" + ) + assertEquals( + mapOf(x to 2u, y to 2u, z to 2u, t to 4u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).degrees, + "test 6" + ) + } + } + @Test + fun test_degreeBy() { + RationalField.labeledPolynomialSpace { + fun LabeledPolynomial.collectDegrees(variables: Set = this.variables + iota): Map = variables.associateWith { degreeBy(it) } + assertEquals( + mapOf(iota to 0u), + LabeledPolynomial().collectDegrees(), + "test 1" + ) + assertEquals( + mapOf(iota to 0u), + LabeledPolynomial( + mapOf() to o + ).collectDegrees(), + "test 2" + ) + assertEquals( + mapOf(x to 1u, y to 2u, z to 3u, iota to 0u), + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).collectDegrees(), + "test 3" + ) + assertEquals( + mapOf(y to 1u, z to 2u, t to 1u, iota to 0u), + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).collectDegrees(), + "test 4" + ) + assertEquals( + mapOf(x to 2u, y to 1u, z to 1u, iota to 0u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).collectDegrees(), + "test 5" + ) + assertEquals( + mapOf(x to 2u, y to 2u, z to 2u, t to 4u, iota to 0u), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).collectDegrees(), + "test 6" + ) + } + } + @Test + fun test_degreeBy_Collection() { + RationalField.labeledPolynomialSpace { + fun LabeledPolynomial.checkDegreeBy(message: String? = null) { + val variables = variables.toList() + iota + val variablesCollectionSequence: Sequence> = sequence { + val appearances = MutableList(variables.size) { 0 } + while (true) { + yield( + buildList { + for ((variableIndex, count) in appearances.withIndex()) repeat(count) { add(variables[variableIndex]) } + } + ) + val indexChange = appearances.indexOfFirst { it < 4 } + if (indexChange == -1) break + appearances[indexChange] += 1 + for (index in 0 until indexChange) appearances[index] = 0 + } + } + for (variablesCollection in variablesCollectionSequence) { + val expected = coefficients.keys.maxOfOrNull { degs -> degs.filterKeys { it in variablesCollection }.values.sum() } ?: 0u + val actual = degreeBy(variablesCollection) + if (actual != expected) + fail("${message ?: ""} Incorrect answer for variable collection $variablesCollection: expected $expected, actual $actual") + } + } + LabeledPolynomial().checkDegreeBy("test 1") + LabeledPolynomial( + mapOf() to o + ).checkDegreeBy("test 2") + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).checkDegreeBy("test 3") + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).checkDegreeBy("test 4") + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).checkDegreeBy("test 5") + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).checkDegreeBy("test 6") + } + } + @Test + fun test_variables() { + RationalField.labeledPolynomialSpace { + assertEquals( + setOf(), + LabeledPolynomial().variables, + "test 1" + ) + assertEquals( + setOf(), + LabeledPolynomial( + mapOf() to o + ).variables, + "test 2" + ) + assertEquals( + setOf(x, y, z), + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).variables, + "test 3" + ) + assertEquals( + setOf(y, z, t), + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).variables, + "test 4" + ) + assertEquals( + setOf(x, y, z), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).variables, + "test 5" + ) + assertEquals( + setOf(x, y, z, t), + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).variables, + "test 6" + ) + } + } + @Test + fun test_countOfVariables() { + RationalField.labeledPolynomialSpace { + assertEquals( + 0, + LabeledPolynomial().countOfVariables, + "test 1" + ) + assertEquals( + 0, + LabeledPolynomial( + mapOf() to o + ).countOfVariables, + "test 2" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ).countOfVariables, + "test 3" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u, t to 1u, s to 0u) to o + ).countOfVariables, + "test 4" + ) + assertEquals( + 3, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ).countOfVariables, + "test 5" + ) + assertEquals( + 4, + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ).countOfVariables, + "test 6" + ) + } + } + @Test + fun test_RF_countOfVariables() { + RationalField.labeledRationalFunctionSpace { + assertEquals( + 0, + LabeledRationalFunction( + LabeledPolynomial() + ).countOfVariables, + "test 1" + ) + assertEquals( + 0, + LabeledRationalFunction( + LabeledPolynomial(), + LabeledPolynomial() + ).countOfVariables, + "test 2" + ) + assertEquals( + 0, + LabeledRationalFunction( + LabeledPolynomial( + mapOf() to o + ) + ).countOfVariables, + "test 3" + ) + assertEquals( + 3, + LabeledRationalFunction( + LabeledPolynomial( + mapOf(x to 1u, y to 2u, z to 3u) to o + ) + ).countOfVariables, + "test 4" + ) + assertEquals( + 3, + LabeledRationalFunction( + LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 0u, t to 1u) to o + ), + LabeledPolynomial( + mapOf(x to 0u, y to 0u, z to 2u) to o + ) + ).countOfVariables, + "test 5" + ) + assertEquals( + 3, + LabeledRationalFunction( + LabeledPolynomial( + mapOf() to o, + mapOf(x to 0u, y to 1u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ) + ).countOfVariables, + "test 6" + ) + assertEquals( + 4, + LabeledRationalFunction( + LabeledPolynomial( + mapOf() to o, + mapOf(x to 1u, y to 2u) to o, + mapOf(x to 2u, y to 0u, z to 1u) to o, + ), LabeledPolynomial( + mapOf(x to 0u, y to 1u, z to 2u) to o, + mapOf(x to 0u, y to 0u, z to 0u, t to 4u) to o, + ) + ).countOfVariables, + "test 7" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt new file mode 100644 index 000000000..cdfe309f9 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -0,0 +1,8224 @@ +/* + * 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.expressions.Symbol +import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.assertEquals +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertEquals + +class LabeledPolynomialUtilTest { + val x by symbol + val y by symbol + val iota by symbol + + @Test + fun test_Polynomial_substitute_Double() { + assertEquals( + LabeledPolynomialAsIs(emptyMap() to 0.0), + LabeledPolynomialAsIs( + mapOf() to 1.0, + mapOf(x to 1u) to -2.0, + mapOf(x to 2u) to 1.0, + ).substitute(mapOf( + x to 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf()), + 0.001, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + iota to 0.9211194782050933 + )), + 0.001, + "test 2'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(y to 2u) to 0.2700930201481795, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.0 + )), + 0.001, + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(y to 2u) to 0.2700930201481795, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.0, + iota to 0.9211194782050933 + )), + 0.001, + "test 3'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.433510890645169, + mapOf(x to 1u) to 0.6264844682514724, + mapOf(x to 2u) to 0.8405727903771333, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + y to 0.8400458576651112 + )), + 0.001, + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.433510890645169, + mapOf(x to 1u) to 0.6264844682514724, + mapOf(x to 2u) to 0.8405727903771333, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + y to 0.8400458576651112, + iota to 0.9211194782050933 + )), + 0.001, + "test 4'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.934530767358133, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.4846192734143442, + y to 0.8400458576651112, + )), + 0.001, + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to 1.934530767358133, + ), + LabeledPolynomialAsIs( + mapOf() to 0.8597048543814783, + mapOf(x to 1u) to 0.22997637465889875, + mapOf(x to 2u) to 0.32675302591924016, + mapOf(y to 1u) to 0.4561746111587508, + mapOf(x to 1u, y to 1u) to 0.5304946210170756, + mapOf(x to 2u, y to 1u) to 0.6244313712888998, + mapOf(y to 2u) to 0.2700930201481795, + mapOf(x to 1u, y to 2u) to -0.06962351375204712, + mapOf(x to 2u, y to 2u) to -0.015206988092131501, + ).substitute(mapOf( + x to 0.4846192734143442, + y to 0.8400458576651112, + iota to 0.9211194782050933 + )), + 0.001, + "test 5'" + ) + } + @Test + fun test_Polynomial_substitute_Constant_Map() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ).substitute(RationalField, mapOf( + x to Rational(1) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5%2C+y+%3D+12%2F9 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(143, 150) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + y to Rational(12, 9), + )), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(143, 150) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + y to Rational(12, 9), + iota to Rational(57, 179), + )), + "test 2'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+y+%3D+12%2F9 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-67, 18), + mapOf(x to 1u) to Rational(-70, 9), + mapOf(x to 2u) to Rational(88, 9), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to Rational(12, 9), + )), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-67, 18), + mapOf(x to 1u) to Rational(-70, 9), + mapOf(x to 2u) to Rational(88, 9), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to Rational(12, 9), + iota to Rational(57, 179), + )), + "test 3'" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-2%2F5 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-83, 50), + mapOf(y to 1u) to Rational(29, 25), + mapOf(y to 2u) to Rational(3, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + )), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-83, 50), + mapOf(y to 1u) to Rational(29, 25), + mapOf(y to 2u) to Rational(3, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + iota to Rational(57, 179), + )), + "test 4'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + iota to Rational(57, 179), + )), + "test 5'" + ) + // https://www.wolframalpha.com/input?i=%28%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2%29+p%5E8+where+x+%3D+q%2Fp%2C+y+%3D+x%5E3%2C+p+%3D+-2%2F5%2C+q+%3D+12%2F9 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(47639065216, 2562890625) + ), + LabeledPolynomialAsIs( + mapOf(x to 8u) to Rational(-3, 2), + mapOf(x to 7u, y to 1u) to Rational(8, 6), + mapOf(x to 6u, y to 2u) to Rational(14, 6), + mapOf(x to 5u, y to 3u) to Rational(-3, 1), + mapOf(x to 4u, y to 4u) to Rational(-19, 2), + mapOf(x to 3u, y to 5u) to Rational(9, 4), + mapOf(x to 2u, y to 6u) to Rational(5, 5), + mapOf(x to 1u, y to 7u) to Rational(18, 9), + mapOf(y to 8u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to Rational(-2, 5), + y to Rational(12, 9), + )), + "test 6" + ) + } + @Test + fun test_Polynomial_substitute_Polynomial_Map() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + )), + "test 1" + ) + // https://www.wolframalpha.com/input?i=%28-3%2F2+%2B+8%2F6+x+%2B+14%2F6+x%5E2%29+%2B+%28-3%2F1+%2B+-19%2F2+x+%2B+9%2F4+x%5E2%29+y+%2B+%285%2F5+%2B+18%2F9+x+%2B+5%2F2+x%5E2%29+y%5E2+where+x+%3D+-5%2F1+s+%2B+2%2F8+t%2C+y+%3D+11%2F7+t + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(y to 1u) to Rational(-92, 21), + mapOf(y to 2u) to Rational(-2627, 2352), + mapOf(y to 3u) to Rational(4565, 3136), + mapOf(y to 4u) to Rational(605, 1568), + mapOf(x to 1u) to Rational(-20, 3), + mapOf(x to 1u, y to 1u) to Rational(1445, 21), + mapOf(x to 1u, y to 2u) to Rational(-13145, 392), + mapOf(x to 1u, y to 3u) to Rational(-3025, 196), + mapOf(x to 2u) to Rational(175, 3), + mapOf(x to 2u, y to 1u) to Rational(2475, 28), + mapOf(x to 2u, y to 2u) to Rational(15125, 98), + mapOf(x to 3u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-5, 1), + mapOf(y to 1u) to Rational(2, 8), + ), + y to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0, 5), + mapOf(y to 1u) to Rational(11, 7), + ), + )), + "test 2" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(48583, 336), + mapOf(x to 2u) to Rational(-913477, 1568), + mapOf(x to 3u) to Rational(-967567, 672), + mapOf(x to 4u) to Rational(4722043, 1344), + mapOf(x to 5u) to Rational(8855, 2), + mapOf(x to 6u) to Rational(-311971, 32), + mapOf(x to 7u) to Rational(-17325, 4), + mapOf(x to 8u) to Rational(19845, 2), + mapOf(y to 1u) to Rational(-827, 4), + mapOf(x to 1u, y to 1u) to Rational(191927, 840), + mapOf(x to 2u, y to 1u) to Rational(9592627, 2352), + mapOf(x to 3u, y to 1u) to Rational(-105400711, 53760), + mapOf(x to 4u, y to 1u) to Rational(-10054101459, 439040), + mapOf(x to 5u, y to 1u) to Rational(2127351, 128), + mapOf(x to 6u, y to 1u) to Rational(116680973, 3136), + mapOf(x to 7u, y to 1u) to Rational(-220445, 7), + mapOf(x to 8u, y to 1u) to Rational(-2655, 4), + mapOf(y to 2u) to Rational(30567, 100), + mapOf(x to 1u, y to 2u) to Rational(-156284953, 39200), + mapOf(x to 2u, y to 2u) to Rational(-57661541711, 6585600), + mapOf(x to 3u, y to 2u) to Rational(131931579, 3136), + mapOf(x to 4u, y to 2u) to Rational(98818124791, 3512320), + mapOf(x to 5u, y to 2u) to Rational(-94458855053, 878080), + mapOf(x to 6u, y to 2u) to Rational(13937705305, 1229312), + mapOf(x to 7u, y to 2u) to Rational(335706887, 21952), + mapOf(x to 8u, y to 2u) to Rational(23549165, 1568), + mapOf(y to 3u) to Rational(111367, 1400), + mapOf(x to 1u, y to 3u) to Rational(4937369, 700), + mapOf(x to 2u, y to 3u) to Rational(-4449423711, 274400), + mapOf(x to 3u, y to 3u) to Rational(-351873325703, 4390400), + mapOf(x to 4u, y to 3u) to Rational(23495875029, 307328), + mapOf(x to 5u, y to 3u) to Rational(17576300919, 878080), + mapOf(x to 6u, y to 3u) to Rational(230316993, 12544), + mapOf(x to 7u, y to 3u) to Rational(-191130515, 21952), + mapOf(x to 8u, y to 3u) to Rational(332435, 392), + mapOf(y to 4u) to Rational(-275084, 1225), + mapOf(x to 1u, y to 4u) to Rational(-266774603, 137200), + mapOf(x to 2u, y to 4u) to Rational(2176279167121, 30732800), + mapOf(x to 3u, y to 4u) to Rational(10904913303, 2195200), + mapOf(x to 4u, y to 4u) to Rational(-10769286147, 2195200), + mapOf(x to 5u, y to 4u) to Rational(-26277119793, 439040), + mapOf(x to 6u, y to 4u) to Rational(25859735869, 6146560), + mapOf(x to 7u, y to 4u) to Rational(38906289, 2744), + mapOf(x to 8u, y to 4u) to Rational(-3072025, 392), + mapOf(y to 5u) to Rational(9573, 98), + mapOf(x to 1u, y to 5u) to Rational(-4154651399, 548800), + mapOf(x to 2u, y to 5u) to Rational(3446069019, 548800), + mapOf(x to 3u, y to 5u) to Rational(-7851500623, 137200), + mapOf(x to 4u, y to 5u) to Rational(-53205142903, 1920800), + mapOf(x to 5u, y to 5u) to Rational(-31953611, 3430), + mapOf(x to 6u, y to 5u) to Rational(1447380313, 109760), + mapOf(x to 7u, y to 5u) to Rational(764158625, 21952), + mapOf(x to 8u, y to 5u) to Rational(1153515, 784), + mapOf(y to 6u) to Rational(1722351, 7840), + mapOf(x to 1u, y to 6u) to Rational(-164554821, 109760), + mapOf(x to 2u, y to 6u) to Rational(-79096147243, 7683200), + mapOf(x to 3u, y to 6u) to Rational(-624721089, 15680), + mapOf(x to 4u, y to 6u) to Rational(11147305567, 548800), + mapOf(x to 5u, y to 6u) to Rational(8318333679, 109760), + mapOf(x to 6u, y to 6u) to Rational(32981871553, 1536640), + mapOf(x to 7u, y to 6u) to Rational(-225359619, 21952), + mapOf(x to 8u, y to 6u) to Rational(-3973995, 392), + mapOf(y to 7u) to Rational(67203, 784), + mapOf(x to 1u, y to 7u) to Rational(39281469, 54880), + mapOf(x to 2u, y to 7u) to Rational(70162551, 27440), + mapOf(x to 3u, y to 7u) to Rational(413630709, 54880), + mapOf(x to 4u, y to 7u) to Rational(4640410269, 192080), + mapOf(x to 5u, y to 7u) to Rational(802712247, 54880), + mapOf(x to 6u, y to 7u) to Rational(-473517603, 27440), + mapOf(x to 7u, y to 7u) to Rational(-17055459, 1568), + mapOf(x to 8u, y to 7u) to Rational(-12825, 14), + mapOf(y to 8u) to Rational(16245, 1568), + mapOf(x to 1u, y to 8u) to Rational(503253, 2744), + mapOf(x to 2u, y to 8u) to Rational(125292591, 96040), + mapOf(x to 3u, y to 8u) to Rational(12033171, 2744), + mapOf(x to 4u, y to 8u) to Rational(154352673, 27440), + mapOf(x to 5u, y to 8u) to Rational(-1302291, 392), + mapOf(x to 6u, y to 8u) to Rational(-20265741, 1960), + mapOf(x to 7u, y to 8u) to Rational(-26163, 56), + mapOf(x to 8u, y to 8u) to Rational(146205, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + )), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(48583, 336), + mapOf(x to 2u) to Rational(-913477, 1568), + mapOf(x to 3u) to Rational(-967567, 672), + mapOf(x to 4u) to Rational(4722043, 1344), + mapOf(x to 5u) to Rational(8855, 2), + mapOf(x to 6u) to Rational(-311971, 32), + mapOf(x to 7u) to Rational(-17325, 4), + mapOf(x to 8u) to Rational(19845, 2), + mapOf(y to 1u) to Rational(-827, 4), + mapOf(x to 1u, y to 1u) to Rational(191927, 840), + mapOf(x to 2u, y to 1u) to Rational(9592627, 2352), + mapOf(x to 3u, y to 1u) to Rational(-105400711, 53760), + mapOf(x to 4u, y to 1u) to Rational(-10054101459, 439040), + mapOf(x to 5u, y to 1u) to Rational(2127351, 128), + mapOf(x to 6u, y to 1u) to Rational(116680973, 3136), + mapOf(x to 7u, y to 1u) to Rational(-220445, 7), + mapOf(x to 8u, y to 1u) to Rational(-2655, 4), + mapOf(y to 2u) to Rational(30567, 100), + mapOf(x to 1u, y to 2u) to Rational(-156284953, 39200), + mapOf(x to 2u, y to 2u) to Rational(-57661541711, 6585600), + mapOf(x to 3u, y to 2u) to Rational(131931579, 3136), + mapOf(x to 4u, y to 2u) to Rational(98818124791, 3512320), + mapOf(x to 5u, y to 2u) to Rational(-94458855053, 878080), + mapOf(x to 6u, y to 2u) to Rational(13937705305, 1229312), + mapOf(x to 7u, y to 2u) to Rational(335706887, 21952), + mapOf(x to 8u, y to 2u) to Rational(23549165, 1568), + mapOf(y to 3u) to Rational(111367, 1400), + mapOf(x to 1u, y to 3u) to Rational(4937369, 700), + mapOf(x to 2u, y to 3u) to Rational(-4449423711, 274400), + mapOf(x to 3u, y to 3u) to Rational(-351873325703, 4390400), + mapOf(x to 4u, y to 3u) to Rational(23495875029, 307328), + mapOf(x to 5u, y to 3u) to Rational(17576300919, 878080), + mapOf(x to 6u, y to 3u) to Rational(230316993, 12544), + mapOf(x to 7u, y to 3u) to Rational(-191130515, 21952), + mapOf(x to 8u, y to 3u) to Rational(332435, 392), + mapOf(y to 4u) to Rational(-275084, 1225), + mapOf(x to 1u, y to 4u) to Rational(-266774603, 137200), + mapOf(x to 2u, y to 4u) to Rational(2176279167121, 30732800), + mapOf(x to 3u, y to 4u) to Rational(10904913303, 2195200), + mapOf(x to 4u, y to 4u) to Rational(-10769286147, 2195200), + mapOf(x to 5u, y to 4u) to Rational(-26277119793, 439040), + mapOf(x to 6u, y to 4u) to Rational(25859735869, 6146560), + mapOf(x to 7u, y to 4u) to Rational(38906289, 2744), + mapOf(x to 8u, y to 4u) to Rational(-3072025, 392), + mapOf(y to 5u) to Rational(9573, 98), + mapOf(x to 1u, y to 5u) to Rational(-4154651399, 548800), + mapOf(x to 2u, y to 5u) to Rational(3446069019, 548800), + mapOf(x to 3u, y to 5u) to Rational(-7851500623, 137200), + mapOf(x to 4u, y to 5u) to Rational(-53205142903, 1920800), + mapOf(x to 5u, y to 5u) to Rational(-31953611, 3430), + mapOf(x to 6u, y to 5u) to Rational(1447380313, 109760), + mapOf(x to 7u, y to 5u) to Rational(764158625, 21952), + mapOf(x to 8u, y to 5u) to Rational(1153515, 784), + mapOf(y to 6u) to Rational(1722351, 7840), + mapOf(x to 1u, y to 6u) to Rational(-164554821, 109760), + mapOf(x to 2u, y to 6u) to Rational(-79096147243, 7683200), + mapOf(x to 3u, y to 6u) to Rational(-624721089, 15680), + mapOf(x to 4u, y to 6u) to Rational(11147305567, 548800), + mapOf(x to 5u, y to 6u) to Rational(8318333679, 109760), + mapOf(x to 6u, y to 6u) to Rational(32981871553, 1536640), + mapOf(x to 7u, y to 6u) to Rational(-225359619, 21952), + mapOf(x to 8u, y to 6u) to Rational(-3973995, 392), + mapOf(y to 7u) to Rational(67203, 784), + mapOf(x to 1u, y to 7u) to Rational(39281469, 54880), + mapOf(x to 2u, y to 7u) to Rational(70162551, 27440), + mapOf(x to 3u, y to 7u) to Rational(413630709, 54880), + mapOf(x to 4u, y to 7u) to Rational(4640410269, 192080), + mapOf(x to 5u, y to 7u) to Rational(802712247, 54880), + mapOf(x to 6u, y to 7u) to Rational(-473517603, 27440), + mapOf(x to 7u, y to 7u) to Rational(-17055459, 1568), + mapOf(x to 8u, y to 7u) to Rational(-12825, 14), + mapOf(y to 8u) to Rational(16245, 1568), + mapOf(x to 1u, y to 8u) to Rational(503253, 2744), + mapOf(x to 2u, y to 8u) to Rational(125292591, 96040), + mapOf(x to 3u, y to 8u) to Rational(12033171, 2744), + mapOf(x to 4u, y to 8u) to Rational(154352673, 27440), + mapOf(x to 5u, y to 8u) to Rational(-1302291, 392), + mapOf(x to 6u, y to 8u) to Rational(-20265741, 1960), + mapOf(x to 7u, y to 8u) to Rational(-26163, 56), + mapOf(x to 8u, y to 8u) to Rational(146205, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 3'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = s, y = (-9/2 + 2/7 s + 9/1 s^2) + (13/1 + -1/8 s + 2/8 s^2) t + (19/4 + 15/7 s + -19/4 s^2) t^2 + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(6817, 84), + mapOf(x to 2u) to Rational(-21445, 294), + mapOf(x to 3u) to Rational(-12151, 49), + mapOf(x to 4u) to Rational(-17789, 196), + mapOf(x to 5u) to Rational(1224, 7), + mapOf(x to 6u) to Rational(405, 2), + mapOf(y to 1u) to Rational(-156), + mapOf(x to 1u, y to 1u) to Rational(-2440, 7), + mapOf(x to 2u, y to 1u) to Rational(-1571, 112), + mapOf(x to 3u, y to 1u) to Rational(107515, 224), + mapOf(x to 4u, y to 1u) to Rational(64965, 112), + mapOf(x to 5u, y to 1u) to Rational(209, 56), + mapOf(x to 6u, y to 1u) to Rational(45, 4), + mapOf(y to 2u) to Rational(112), + mapOf(x to 1u, y to 2u) to Rational(1449, 8), + mapOf(x to 2u, y to 2u) to Rational(1306309, 3136), + mapOf(x to 3u, y to 2u) to Rational(483207, 1568), + mapOf(x to 4u, y to 2u) to Rational(1978437, 6272), + mapOf(x to 5u, y to 2u) to Rational(-18231, 224), + mapOf(x to 6u, y to 2u) to Rational(-6835, 32), + mapOf(y to 3u) to Rational(247, 2), + mapOf(x to 1u, y to 3u) to Rational(33771, 112), + mapOf(x to 2u, y to 3u) to Rational(2073, 7), + mapOf(x to 3u, y to 3u) to Rational(-23463, 224), + mapOf(x to 4u, y to 3u) to Rational(-33825, 112), + mapOf(x to 5u, y to 3u) to Rational(201, 224), + mapOf(x to 6u, y to 3u) to Rational(-95, 16), + mapOf(y to 4u) to Rational(361, 16), + mapOf(x to 1u, y to 4u) to Rational(3667, 56), + mapOf(x to 2u, y to 4u) to Rational(88729, 1568), + mapOf(x to 3u, y to 4u) to Rational(-2476, 49), + mapOf(x to 4u, y to 4u) to Rational(-23419, 196), + mapOf(x to 5u, y to 4u) to Rational(-323, 56), + mapOf(x to 6u, y to 4u) to Rational(1805, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + )), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(129, 4), + mapOf(x to 1u) to Rational(6817, 84), + mapOf(x to 2u) to Rational(-21445, 294), + mapOf(x to 3u) to Rational(-12151, 49), + mapOf(x to 4u) to Rational(-17789, 196), + mapOf(x to 5u) to Rational(1224, 7), + mapOf(x to 6u) to Rational(405, 2), + mapOf(y to 1u) to Rational(-156), + mapOf(x to 1u, y to 1u) to Rational(-2440, 7), + mapOf(x to 2u, y to 1u) to Rational(-1571, 112), + mapOf(x to 3u, y to 1u) to Rational(107515, 224), + mapOf(x to 4u, y to 1u) to Rational(64965, 112), + mapOf(x to 5u, y to 1u) to Rational(209, 56), + mapOf(x to 6u, y to 1u) to Rational(45, 4), + mapOf(y to 2u) to Rational(112), + mapOf(x to 1u, y to 2u) to Rational(1449, 8), + mapOf(x to 2u, y to 2u) to Rational(1306309, 3136), + mapOf(x to 3u, y to 2u) to Rational(483207, 1568), + mapOf(x to 4u, y to 2u) to Rational(1978437, 6272), + mapOf(x to 5u, y to 2u) to Rational(-18231, 224), + mapOf(x to 6u, y to 2u) to Rational(-6835, 32), + mapOf(y to 3u) to Rational(247, 2), + mapOf(x to 1u, y to 3u) to Rational(33771, 112), + mapOf(x to 2u, y to 3u) to Rational(2073, 7), + mapOf(x to 3u, y to 3u) to Rational(-23463, 224), + mapOf(x to 4u, y to 3u) to Rational(-33825, 112), + mapOf(x to 5u, y to 3u) to Rational(201, 224), + mapOf(x to 6u, y to 3u) to Rational(-95, 16), + mapOf(y to 4u) to Rational(361, 16), + mapOf(x to 1u, y to 4u) to Rational(3667, 56), + mapOf(x to 2u, y to 4u) to Rational(88729, 1568), + mapOf(x to 3u, y to 4u) to Rational(-2476, 49), + mapOf(x to 4u, y to 4u) to Rational(-23419, 196), + mapOf(x to 5u, y to 4u) to Rational(-323, 56), + mapOf(x to 6u, y to 4u) to Rational(1805, 32), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(-9, 2), + mapOf(x to 1u) to Rational(2, 7), + mapOf(x to 2u) to Rational(9, 1), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-1, 8), + mapOf(x to 2u, y to 1u) to Rational(2, 8), + mapOf(y to 2u) to Rational(19, 4), + mapOf(x to 1u, y to 2u) to Rational(15, 7), + mapOf(x to 2u, y to 2u) to Rational(-19, 4), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 4'" + ) + // (-3/2 + 8/6 x + 14/6 x^2) + (-3/1 + -19/2 x + 9/4 x^2) y + (5/5 + 18/9 x + 5/2 x^2) y^2 where x = (0/6 + 14/8 s + -14/2 s^2) + (-3/5 + 11/1 s + 3/7 s^2) t + (-3/7 + -18/5 s + -9/1 s^2) t^2, y = t + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(-35, 16), + mapOf(x to 3u) to Rational(-343, 6), + mapOf(x to 4u) to Rational(343, 3), + mapOf(y to 1u) to Rational(-19, 5), + mapOf(x to 1u, y to 1u) to Rational(-823, 120), + mapOf(x to 2u, y to 1u) to Rational(1232417, 6720), + mapOf(x to 3u, y to 1u) to Rational(-9863, 24), + mapOf(x to 4u, y to 1u) to Rational(385, 4), + mapOf(y to 2u) to Rational(2439, 350), + mapOf(x to 1u, y to 2u) to Rational(-5793, 40), + mapOf(x to 2u, y to 2u) to Rational(1172113, 3360), + mapOf(x to 3u, y to 2u) to Rational(-13531, 40), + mapOf(x to 4u, y to 2u) to Rational(2824, 7), + mapOf(y to 3u) to Rational(3417, 700), + mapOf(x to 1u, y to 3u) to Rational(1191, 200), + mapOf(x to 2u, y to 3u) to Rational(8383, 28), + mapOf(x to 3u, y to 3u) to Rational(-220279, 280), + mapOf(x to 4u, y to 3u) to Rational(49179, 196), + mapOf(y to 4u) to Rational(57, 35), + mapOf(x to 1u, y to 4u) to Rational(-33771, 700), + mapOf(x to 2u, y to 4u) to Rational(196279, 1225), + mapOf(x to 3u, y to 4u) to Rational(-32259, 140), + mapOf(x to 4u, y to 4u) to Rational(23868, 49), + mapOf(y to 5u) to Rational(333, 196), + mapOf(x to 1u, y to 5u) to Rational(-204, 35), + mapOf(x to 2u, y to 5u) to Rational(-307233, 2450), + mapOf(x to 3u, y to 5u) to Rational(-12492, 35), + mapOf(x to 4u, y to 5u) to Rational(4563, 28), + mapOf(y to 6u) to Rational(45, 98), + mapOf(x to 1u, y to 6u) to Rational(54, 7), + mapOf(x to 2u, y to 6u) to Rational(1809, 35), + mapOf(x to 3u, y to 6u) to Rational(162), + mapOf(x to 4u, y to 6u) to Rational(405, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + )), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(-35, 16), + mapOf(x to 3u) to Rational(-343, 6), + mapOf(x to 4u) to Rational(343, 3), + mapOf(y to 1u) to Rational(-19, 5), + mapOf(x to 1u, y to 1u) to Rational(-823, 120), + mapOf(x to 2u, y to 1u) to Rational(1232417, 6720), + mapOf(x to 3u, y to 1u) to Rational(-9863, 24), + mapOf(x to 4u, y to 1u) to Rational(385, 4), + mapOf(y to 2u) to Rational(2439, 350), + mapOf(x to 1u, y to 2u) to Rational(-5793, 40), + mapOf(x to 2u, y to 2u) to Rational(1172113, 3360), + mapOf(x to 3u, y to 2u) to Rational(-13531, 40), + mapOf(x to 4u, y to 2u) to Rational(2824, 7), + mapOf(y to 3u) to Rational(3417, 700), + mapOf(x to 1u, y to 3u) to Rational(1191, 200), + mapOf(x to 2u, y to 3u) to Rational(8383, 28), + mapOf(x to 3u, y to 3u) to Rational(-220279, 280), + mapOf(x to 4u, y to 3u) to Rational(49179, 196), + mapOf(y to 4u) to Rational(57, 35), + mapOf(x to 1u, y to 4u) to Rational(-33771, 700), + mapOf(x to 2u, y to 4u) to Rational(196279, 1225), + mapOf(x to 3u, y to 4u) to Rational(-32259, 140), + mapOf(x to 4u, y to 4u) to Rational(23868, 49), + mapOf(y to 5u) to Rational(333, 196), + mapOf(x to 1u, y to 5u) to Rational(-204, 35), + mapOf(x to 2u, y to 5u) to Rational(-307233, 2450), + mapOf(x to 3u, y to 5u) to Rational(-12492, 35), + mapOf(x to 4u, y to 5u) to Rational(4563, 28), + mapOf(y to 6u) to Rational(45, 98), + mapOf(x to 1u, y to 6u) to Rational(54, 7), + mapOf(x to 2u, y to 6u) to Rational(1809, 35), + mapOf(x to 3u, y to 6u) to Rational(162), + mapOf(x to 4u, y to 6u) to Rational(405, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(0, 6), + mapOf(x to 1u) to Rational(14, 8), + mapOf(x to 2u) to Rational(-14, 2), + mapOf(y to 1u) to Rational(-3, 5), + mapOf(x to 1u, y to 1u) to Rational(11, 1), + mapOf(x to 2u, y to 1u) to Rational(3, 7), + mapOf(y to 2u) to Rational(-3, 7), + mapOf(x to 1u, y to 2u) to Rational(-18, 5), + mapOf(x to 2u, y to 2u) to Rational(-9, 1), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 5'" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 2), + mapOf(x to 1u) to Rational(8, 6), + mapOf(x to 2u) to Rational(14, 6), + mapOf(y to 1u) to Rational(-3, 1), + mapOf(x to 1u, y to 1u) to Rational(-19, 2), + mapOf(x to 2u, y to 1u) to Rational(9, 4), + mapOf(y to 2u) to Rational(5, 5), + mapOf(x to 1u, y to 2u) to Rational(18, 9), + mapOf(x to 2u, y to 2u) to Rational(5, 2), + ).substitute(RationalField, mapOf( + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-11, 3), + mapOf(x to 1u) to Rational(5, 2), + mapOf(x to 2u) to Rational(13, 7), + mapOf(y to 1u) to Rational(16, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(6, 1), + mapOf(y to 2u) to Rational(-14, 3), + mapOf(x to 1u, y to 2u) to Rational(-2, 7), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + )), + "test 6'" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(-194071, 4900), + mapOf(x to 3u, y to 1u) to Rational(394811, 225), + mapOf(x to 2u, y to 2u) to Rational(-444183161, 66150), + mapOf(x to 1u, y to 3u) to Rational(70537618, 59535), + mapOf(y to 4u) to Rational(9655504, 2835), + ), + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(9, 1), + mapOf(x to 3u, y to 1u) to Rational(61, 1), + mapOf(x to 2u, y to 2u) to Rational(2137, 36), + mapOf(x to 1u, y to 3u) to Rational(-1342, 9), + mapOf(y to 4u) to Rational(484, 9), + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(17, 7), + mapOf(y to 1u) to Rational(-13, 1), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-18, 6), + mapOf(y to 1u) to Rational(11, 6), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(18, 5), + mapOf(y to 1u) to Rational(-16, 3), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(-4, 1), + ) + ), + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-6443599, 10000), + mapOf(x to 1u) to Rational(166251223, 210000), + mapOf(x to 2u) to Rational(-4606805099, 3528000), + mapOf(x to 3u) to Rational(51204379, 19600), + mapOf(x to 4u) to Rational(-529045460659, 277830000), + mapOf(x to 5u) to Rational(2630836709, 1488375), + mapOf(x to 6u) to Rational(-42675691369, 25004700), + mapOf(x to 7u) to Rational(495825223, 1250235), + mapOf(x to 8u) to Rational(-22531756, 1750329), + mapOf(y to 1u) to Rational(-2526552797, 420000), + mapOf(x to 1u, y to 1u) to Rational(31108840471, 2520000), + mapOf(x to 2u, y to 1u) to Rational(-4789740847, 1102500), + mapOf(x to 3u, y to 1u) to Rational(186594307807, 11340000), + mapOf(x to 4u, y to 1u) to Rational(-11677815943, 1488375), + mapOf(x to 5u, y to 1u) to Rational(-181118486447, 27783000), + mapOf(x to 6u, y to 1u) to Rational(-16123292162, 14586075), + mapOf(x to 7u, y to 1u) to Rational(-140339343808, 26254935), + mapOf(x to 8u, y to 1u) to Rational(4570171616, 5250987), + mapOf(y to 2u) to Rational(-181436530573, 10080000), + mapOf(x to 1u, y to 2u) to Rational(6700437957491, 105840000), + mapOf(x to 2u, y to 2u) to Rational(-3527267461, 1417500), + mapOf(x to 3u, y to 2u) to Rational(-38084563451, 5556600), + mapOf(x to 4u, y to 2u) to Rational(-565662040631, 13891500), + mapOf(x to 5u, y to 2u) to Rational(-35479071126397, 583443000), + mapOf(x to 6u, y to 2u) to Rational(-11717559078469, 525098700), + mapOf(x to 7u, y to 2u) to Rational(-2043385293517, 225042300), + mapOf(x to 8u, y to 2u) to Rational(-3644439630451, 551353635), + mapOf(y to 3u) to Rational(-1760423269, 126000), + mapOf(x to 1u, y to 3u) to Rational(310176758299, 2352000), + mapOf(x to 2u, y to 3u) to Rational(-907229584837, 21168000), + mapOf(x to 3u, y to 3u) to Rational(-16717135885963, 95256000), + mapOf(x to 4u, y to 3u) to Rational(-43762928025353, 333396000), + mapOf(x to 5u, y to 3u) to Rational(-328427480571607, 3000564000), + mapOf(x to 6u, y to 3u) to Rational(-7722675917197, 210039480), + mapOf(x to 7u, y to 3u) to Rational(1713350137019, 1225230300), + mapOf(x to 8u, y to 3u) to Rational(156695935643, 31505922), + mapOf(y to 4u) to Rational(18362364269, 1008000), + mapOf(x to 1u, y to 4u) to Rational(955674858553, 10584000), + mapOf(x to 2u, y to 4u) to Rational(-71937470607371, 444528000), + mapOf(x to 3u, y to 4u) to Rational(-34097985615163, 95256000), + mapOf(x to 4u, y to 4u) to Rational(-340736178775883, 2000376000), + mapOf(x to 5u, y to 4u) to Rational(-511324523441897, 10501974000), + mapOf(x to 6u, y to 4u) to Rational(-125375649409151, 8821658160), + mapOf(x to 7u, y to 4u) to Rational(-2813518533421, 1575296100), + mapOf(x to 8u, y to 4u) to Rational(-17044089109, 5250987), + mapOf(y to 5u) to Rational(600086461, 20160), + mapOf(x to 1u, y to 5u) to Rational(-18959931367, 423360), + mapOf(x to 2u, y to 5u) to Rational(-9178804929607, 44452800), + mapOf(x to 3u, y to 5u) to Rational(-1460114275979, 5334336), + mapOf(x to 4u, y to 5u) to Rational(-342533479090169, 4200789600), + mapOf(x to 5u, y to 5u) to Rational(20335453022963, 4200789600), + mapOf(x to 6u, y to 5u) to Rational(-21649775090197, 6301184400), + mapOf(x to 7u, y to 5u) to Rational(-197301716069, 131274675), + mapOf(x to 8u, y to 5u) to Rational(18711357470, 15752961), + mapOf(y to 6u) to Rational(621417991, 100800), + mapOf(x to 1u, y to 6u) to Rational(-159236792977, 2116800), + mapOf(x to 2u, y to 6u) to Rational(-6602528890883, 66679200), + mapOf(x to 3u, y to 6u) to Rational(-1086091664047, 19051200), + mapOf(x to 4u, y to 6u) to Rational(3769375009003, 1680315840), + mapOf(x to 5u, y to 6u) to Rational(-12920385574769, 1050197400), + mapOf(x to 6u, y to 6u) to Rational(-90219591809287, 6301184400), + mapOf(x to 7u, y to 6u) to Rational(656361553391, 1575296100), + mapOf(x to 8u, y to 6u) to Rational(757900793, 2250423), + mapOf(y to 7u) to Rational(-100770017, 15120), + mapOf(x to 1u, y to 7u) to Rational(-316364851, 17640), + mapOf(x to 2u, y to 7u) to Rational(-85118560057, 6667920), + mapOf(x to 3u, y to 7u) to Rational(6286563719, 416745), + mapOf(x to 4u, y to 7u) to Rational(26803885301, 1714608), + mapOf(x to 5u, y to 7u) to Rational(-13767154393, 4286520), + mapOf(x to 6u, y to 7u) to Rational(-3875138933, 1224720), + mapOf(x to 7u, y to 7u) to Rational(65193755, 333396), + mapOf(x to 8u, y to 7u) to Rational(90974351, 2500470), + mapOf(y to 8u) to Rational(-3182197, 1260), + mapOf(x to 1u, y to 8u) to Rational(24899923, 8820), + mapOf(x to 2u, y to 8u) to Rational(-19999556, 19845), + mapOf(x to 3u, y to 8u) to Rational(3276587, 3969), + mapOf(x to 4u, y to 8u) to Rational(13719549239, 5000940), + mapOf(x to 5u, y to 8u) to Rational(-961839938, 1250235), + mapOf(x to 6u, y to 8u) to Rational(-198184871, 833490), + mapOf(x to 7u, y to 8u) to Rational(230659711, 5000940), + mapOf(x to 8u, y to 8u) to Rational(292447, 35721) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(9, 100), + mapOf(x to 1u) to Rational(-21, 50), + mapOf(x to 2u) to Rational(293, 700), + mapOf(x to 3u) to Rational(29, 210), + mapOf(x to 4u) to Rational(3233, 8820), + mapOf(x to 5u) to Rational(-289, 441), + mapOf(x to 6u) to Rational(-1, 9), + mapOf(x to 7u) to Rational(-20, 441), + mapOf(x to 8u) to Rational(100, 441), + mapOf(y to 1u) to Rational(-57, 80), + mapOf(x to 1u, y to 1u) to Rational(-121, 400), + mapOf(x to 2u, y to 1u) to Rational(37117, 8400), + mapOf(x to 3u, y to 1u) to Rational(-4853, 3150), + mapOf(x to 4u, y to 1u) to Rational(1166203, 132300), + mapOf(x to 5u, y to 1u) to Rational(-2708, 567), + mapOf(x to 6u, y to 1u) to Rational(-287159, 416745), + mapOf(x to 7u, y to 1u) to Rational(-478204, 83349), + mapOf(x to 8u, y to 1u) to Rational(176320, 83349), + mapOf(y to 2u) to Rational(-6239, 6400), + mapOf(x to 1u, y to 2u) to Rational(264211, 11200), + mapOf(x to 2u, y to 2u) to Rational(-1591999, 100800), + mapOf(x to 3u, y to 2u) to Rational(12450091, 529200), + mapOf(x to 4u, y to 2u) to Rational(9230759, 226800), + mapOf(x to 5u, y to 2u) to Rational(18995554, 2083725), + mapOf(x to 6u, y to 2u) to Rational(136706258, 6251175), + mapOf(x to 7u, y to 2u) to Rational(-120907496, 3750705), + mapOf(x to 8u, y to 2u) to Rational(117200176, 15752961), + mapOf(y to 3u) to Rational(5653, 320), + mapOf(x to 1u, y to 3u) to Rational(-130853, 8400), + mapOf(x to 2u, y to 3u) to Rational(-20939327, 151200), + mapOf(x to 3u, y to 3u) to Rational(2566691, 25200), + mapOf(x to 4u, y to 3u) to Rational(-68441519, 476280), + mapOf(x to 5u, y to 3u) to Rational(2462904247, 12502350), + mapOf(x to 6u, y to 3u) to Rational(353667161, 18753525), + mapOf(x to 7u, y to 3u) to Rational(-1689134372, 26254935), + mapOf(x to 8u, y to 3u) to Rational(35084104, 2250423), + mapOf(y to 4u) to Rational(-3587, 300), + mapOf(x to 1u, y to 4u) to Rational(-10513243, 33600), + mapOf(x to 2u, y to 4u) to Rational(30766733, 176400), + mapOf(x to 3u, y to 4u) to Rational(-65680021, 198450), + mapOf(x to 4u, y to 4u) to Rational(-8108910547, 20003760), + mapOf(x to 5u, y to 4u) to Rational(2922125159, 6251175), + mapOf(x to 6u, y to 4u) to Rational(-4245279943, 131274675), + mapOf(x to 7u, y to 4u) to Rational(-371946872, 3750705), + mapOf(x to 8u, y to 4u) to Rational(61286752, 2250423), + mapOf(y to 5u) to Rational(-20477, 160), + mapOf(x to 1u, y to 5u) to Rational(215741, 1120), + mapOf(x to 2u, y to 5u) to Rational(30785843, 31752), + mapOf(x to 3u, y to 5u) to Rational(-357495959, 317520), + mapOf(x to 4u, y to 5u) to Rational(-1611242993, 10001880), + mapOf(x to 5u, y to 5u) to Rational(345925495, 500094), + mapOf(x to 6u, y to 5u) to Rational(-755948411, 3750705), + mapOf(x to 7u, y to 5u) to Rational(-108643496, 1250235), + mapOf(x to 8u, y to 5u) to Rational(1122512, 35721), + mapOf(y to 6u) to Rational(358037, 2880), + mapOf(x to 1u, y to 6u) to Rational(3895837, 3360), + mapOf(x to 2u, y to 6u) to Rational(359419201, 1270080), + mapOf(x to 3u, y to 6u) to Rational(-158522587, 105840), + mapOf(x to 4u, y to 6u) to Rational(10909002599, 20003760), + mapOf(x to 5u, y to 6u) to Rational(76846972, 138915), + mapOf(x to 6u, y to 6u) to Rational(-327696553, 1250235), + mapOf(x to 7u, y to 6u) to Rational(-1687328, 35721), + mapOf(x to 8u, y to 6u) to Rational(1016836, 35721), + mapOf(y to 7u) to Rational(658, 3), + mapOf(x to 1u, y to 7u) to Rational(48035, 168), + mapOf(x to 2u, y to 7u) to Rational(-5777875, 5292), + mapOf(x to 3u, y to 7u) to Rational(-7893899, 10584), + mapOf(x to 4u, y to 7u) to Rational(10191652, 11907), + mapOf(x to 5u, y to 7u) to Rational(2920121, 23814), + mapOf(x to 6u, y to 7u) to Rational(-2699780, 11907), + mapOf(x to 7u, y to 7u) to Rational(4556, 441), + mapOf(x to 8u, y to 7u) to Rational(3440, 189), + mapOf(y to 8u) to Rational(64, 1), + mapOf(x to 1u, y to 8u) to Rational(-808, 7), + mapOf(x to 2u, y to 8u) to Rational(-360895, 1764), + mapOf(x to 3u, y to 8u) to Rational(257657, 882), + mapOf(x to 4u, y to 8u) to Rational(3779917, 15876), + mapOf(x to 5u, y to 8u) to Rational(-610279, 3969), + mapOf(x to 6u, y to 8u) to Rational(-25091, 441), + mapOf(x to 7u, y to 8u) to Rational(9560, 567), + mapOf(x to 8u, y to 8u) to Rational(400, 81) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-6443599, 10000), + mapOf(x to 1u) to Rational(166251223, 210000), + mapOf(x to 2u) to Rational(-4606805099, 3528000), + mapOf(x to 3u) to Rational(51204379, 19600), + mapOf(x to 4u) to Rational(-529045460659, 277830000), + mapOf(x to 5u) to Rational(2630836709, 1488375), + mapOf(x to 6u) to Rational(-42675691369, 25004700), + mapOf(x to 7u) to Rational(495825223, 1250235), + mapOf(x to 8u) to Rational(-22531756, 1750329), + mapOf(y to 1u) to Rational(-2526552797, 420000), + mapOf(x to 1u, y to 1u) to Rational(31108840471, 2520000), + mapOf(x to 2u, y to 1u) to Rational(-4789740847, 1102500), + mapOf(x to 3u, y to 1u) to Rational(186594307807, 11340000), + mapOf(x to 4u, y to 1u) to Rational(-11677815943, 1488375), + mapOf(x to 5u, y to 1u) to Rational(-181118486447, 27783000), + mapOf(x to 6u, y to 1u) to Rational(-16123292162, 14586075), + mapOf(x to 7u, y to 1u) to Rational(-140339343808, 26254935), + mapOf(x to 8u, y to 1u) to Rational(4570171616, 5250987), + mapOf(y to 2u) to Rational(-181436530573, 10080000), + mapOf(x to 1u, y to 2u) to Rational(6700437957491, 105840000), + mapOf(x to 2u, y to 2u) to Rational(-3527267461, 1417500), + mapOf(x to 3u, y to 2u) to Rational(-38084563451, 5556600), + mapOf(x to 4u, y to 2u) to Rational(-565662040631, 13891500), + mapOf(x to 5u, y to 2u) to Rational(-35479071126397, 583443000), + mapOf(x to 6u, y to 2u) to Rational(-11717559078469, 525098700), + mapOf(x to 7u, y to 2u) to Rational(-2043385293517, 225042300), + mapOf(x to 8u, y to 2u) to Rational(-3644439630451, 551353635), + mapOf(y to 3u) to Rational(-1760423269, 126000), + mapOf(x to 1u, y to 3u) to Rational(310176758299, 2352000), + mapOf(x to 2u, y to 3u) to Rational(-907229584837, 21168000), + mapOf(x to 3u, y to 3u) to Rational(-16717135885963, 95256000), + mapOf(x to 4u, y to 3u) to Rational(-43762928025353, 333396000), + mapOf(x to 5u, y to 3u) to Rational(-328427480571607, 3000564000), + mapOf(x to 6u, y to 3u) to Rational(-7722675917197, 210039480), + mapOf(x to 7u, y to 3u) to Rational(1713350137019, 1225230300), + mapOf(x to 8u, y to 3u) to Rational(156695935643, 31505922), + mapOf(y to 4u) to Rational(18362364269, 1008000), + mapOf(x to 1u, y to 4u) to Rational(955674858553, 10584000), + mapOf(x to 2u, y to 4u) to Rational(-71937470607371, 444528000), + mapOf(x to 3u, y to 4u) to Rational(-34097985615163, 95256000), + mapOf(x to 4u, y to 4u) to Rational(-340736178775883, 2000376000), + mapOf(x to 5u, y to 4u) to Rational(-511324523441897, 10501974000), + mapOf(x to 6u, y to 4u) to Rational(-125375649409151, 8821658160), + mapOf(x to 7u, y to 4u) to Rational(-2813518533421, 1575296100), + mapOf(x to 8u, y to 4u) to Rational(-17044089109, 5250987), + mapOf(y to 5u) to Rational(600086461, 20160), + mapOf(x to 1u, y to 5u) to Rational(-18959931367, 423360), + mapOf(x to 2u, y to 5u) to Rational(-9178804929607, 44452800), + mapOf(x to 3u, y to 5u) to Rational(-1460114275979, 5334336), + mapOf(x to 4u, y to 5u) to Rational(-342533479090169, 4200789600), + mapOf(x to 5u, y to 5u) to Rational(20335453022963, 4200789600), + mapOf(x to 6u, y to 5u) to Rational(-21649775090197, 6301184400), + mapOf(x to 7u, y to 5u) to Rational(-197301716069, 131274675), + mapOf(x to 8u, y to 5u) to Rational(18711357470, 15752961), + mapOf(y to 6u) to Rational(621417991, 100800), + mapOf(x to 1u, y to 6u) to Rational(-159236792977, 2116800), + mapOf(x to 2u, y to 6u) to Rational(-6602528890883, 66679200), + mapOf(x to 3u, y to 6u) to Rational(-1086091664047, 19051200), + mapOf(x to 4u, y to 6u) to Rational(3769375009003, 1680315840), + mapOf(x to 5u, y to 6u) to Rational(-12920385574769, 1050197400), + mapOf(x to 6u, y to 6u) to Rational(-90219591809287, 6301184400), + mapOf(x to 7u, y to 6u) to Rational(656361553391, 1575296100), + mapOf(x to 8u, y to 6u) to Rational(757900793, 2250423), + mapOf(y to 7u) to Rational(-100770017, 15120), + mapOf(x to 1u, y to 7u) to Rational(-316364851, 17640), + mapOf(x to 2u, y to 7u) to Rational(-85118560057, 6667920), + mapOf(x to 3u, y to 7u) to Rational(6286563719, 416745), + mapOf(x to 4u, y to 7u) to Rational(26803885301, 1714608), + mapOf(x to 5u, y to 7u) to Rational(-13767154393, 4286520), + mapOf(x to 6u, y to 7u) to Rational(-3875138933, 1224720), + mapOf(x to 7u, y to 7u) to Rational(65193755, 333396), + mapOf(x to 8u, y to 7u) to Rational(90974351, 2500470), + mapOf(y to 8u) to Rational(-3182197, 1260), + mapOf(x to 1u, y to 8u) to Rational(24899923, 8820), + mapOf(x to 2u, y to 8u) to Rational(-19999556, 19845), + mapOf(x to 3u, y to 8u) to Rational(3276587, 3969), + mapOf(x to 4u, y to 8u) to Rational(13719549239, 5000940), + mapOf(x to 5u, y to 8u) to Rational(-961839938, 1250235), + mapOf(x to 6u, y to 8u) to Rational(-198184871, 833490), + mapOf(x to 7u, y to 8u) to Rational(230659711, 5000940), + mapOf(x to 8u, y to 8u) to Rational(292447, 35721) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(9, 100), + mapOf(x to 1u) to Rational(-21, 50), + mapOf(x to 2u) to Rational(293, 700), + mapOf(x to 3u) to Rational(29, 210), + mapOf(x to 4u) to Rational(3233, 8820), + mapOf(x to 5u) to Rational(-289, 441), + mapOf(x to 6u) to Rational(-1, 9), + mapOf(x to 7u) to Rational(-20, 441), + mapOf(x to 8u) to Rational(100, 441), + mapOf(y to 1u) to Rational(-57, 80), + mapOf(x to 1u, y to 1u) to Rational(-121, 400), + mapOf(x to 2u, y to 1u) to Rational(37117, 8400), + mapOf(x to 3u, y to 1u) to Rational(-4853, 3150), + mapOf(x to 4u, y to 1u) to Rational(1166203, 132300), + mapOf(x to 5u, y to 1u) to Rational(-2708, 567), + mapOf(x to 6u, y to 1u) to Rational(-287159, 416745), + mapOf(x to 7u, y to 1u) to Rational(-478204, 83349), + mapOf(x to 8u, y to 1u) to Rational(176320, 83349), + mapOf(y to 2u) to Rational(-6239, 6400), + mapOf(x to 1u, y to 2u) to Rational(264211, 11200), + mapOf(x to 2u, y to 2u) to Rational(-1591999, 100800), + mapOf(x to 3u, y to 2u) to Rational(12450091, 529200), + mapOf(x to 4u, y to 2u) to Rational(9230759, 226800), + mapOf(x to 5u, y to 2u) to Rational(18995554, 2083725), + mapOf(x to 6u, y to 2u) to Rational(136706258, 6251175), + mapOf(x to 7u, y to 2u) to Rational(-120907496, 3750705), + mapOf(x to 8u, y to 2u) to Rational(117200176, 15752961), + mapOf(y to 3u) to Rational(5653, 320), + mapOf(x to 1u, y to 3u) to Rational(-130853, 8400), + mapOf(x to 2u, y to 3u) to Rational(-20939327, 151200), + mapOf(x to 3u, y to 3u) to Rational(2566691, 25200), + mapOf(x to 4u, y to 3u) to Rational(-68441519, 476280), + mapOf(x to 5u, y to 3u) to Rational(2462904247, 12502350), + mapOf(x to 6u, y to 3u) to Rational(353667161, 18753525), + mapOf(x to 7u, y to 3u) to Rational(-1689134372, 26254935), + mapOf(x to 8u, y to 3u) to Rational(35084104, 2250423), + mapOf(y to 4u) to Rational(-3587, 300), + mapOf(x to 1u, y to 4u) to Rational(-10513243, 33600), + mapOf(x to 2u, y to 4u) to Rational(30766733, 176400), + mapOf(x to 3u, y to 4u) to Rational(-65680021, 198450), + mapOf(x to 4u, y to 4u) to Rational(-8108910547, 20003760), + mapOf(x to 5u, y to 4u) to Rational(2922125159, 6251175), + mapOf(x to 6u, y to 4u) to Rational(-4245279943, 131274675), + mapOf(x to 7u, y to 4u) to Rational(-371946872, 3750705), + mapOf(x to 8u, y to 4u) to Rational(61286752, 2250423), + mapOf(y to 5u) to Rational(-20477, 160), + mapOf(x to 1u, y to 5u) to Rational(215741, 1120), + mapOf(x to 2u, y to 5u) to Rational(30785843, 31752), + mapOf(x to 3u, y to 5u) to Rational(-357495959, 317520), + mapOf(x to 4u, y to 5u) to Rational(-1611242993, 10001880), + mapOf(x to 5u, y to 5u) to Rational(345925495, 500094), + mapOf(x to 6u, y to 5u) to Rational(-755948411, 3750705), + mapOf(x to 7u, y to 5u) to Rational(-108643496, 1250235), + mapOf(x to 8u, y to 5u) to Rational(1122512, 35721), + mapOf(y to 6u) to Rational(358037, 2880), + mapOf(x to 1u, y to 6u) to Rational(3895837, 3360), + mapOf(x to 2u, y to 6u) to Rational(359419201, 1270080), + mapOf(x to 3u, y to 6u) to Rational(-158522587, 105840), + mapOf(x to 4u, y to 6u) to Rational(10909002599, 20003760), + mapOf(x to 5u, y to 6u) to Rational(76846972, 138915), + mapOf(x to 6u, y to 6u) to Rational(-327696553, 1250235), + mapOf(x to 7u, y to 6u) to Rational(-1687328, 35721), + mapOf(x to 8u, y to 6u) to Rational(1016836, 35721), + mapOf(y to 7u) to Rational(658, 3), + mapOf(x to 1u, y to 7u) to Rational(48035, 168), + mapOf(x to 2u, y to 7u) to Rational(-5777875, 5292), + mapOf(x to 3u, y to 7u) to Rational(-7893899, 10584), + mapOf(x to 4u, y to 7u) to Rational(10191652, 11907), + mapOf(x to 5u, y to 7u) to Rational(2920121, 23814), + mapOf(x to 6u, y to 7u) to Rational(-2699780, 11907), + mapOf(x to 7u, y to 7u) to Rational(4556, 441), + mapOf(x to 8u, y to 7u) to Rational(3440, 189), + mapOf(y to 8u) to Rational(64, 1), + mapOf(x to 1u, y to 8u) to Rational(-808, 7), + mapOf(x to 2u, y to 8u) to Rational(-360895, 1764), + mapOf(x to 3u, y to 8u) to Rational(257657, 882), + mapOf(x to 4u, y to 8u) to Rational(3779917, 15876), + mapOf(x to 5u, y to 8u) to Rational(-610279, 3969), + mapOf(x to 6u, y to 8u) to Rational(-25091, 441), + mapOf(x to 7u, y to 8u) to Rational(9560, 567), + mapOf(x to 8u, y to 8u) to Rational(400, 81) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-66677, 3500), + mapOf(x to 1u) to Rational(-206281, 10500), + mapOf(x to 2u) to Rational(-412567, 7056), + mapOf(x to 3u) to Rational(-310081, 11025), + mapOf(x to 4u) to Rational(-575996, 15435), + mapOf(y to 1u) to Rational(-573701, 4200), + mapOf(x to 1u, y to 1u) to Rational(-2239001, 25200), + mapOf(x to 2u, y to 1u) to Rational(-8817889, 132300), + mapOf(x to 3u, y to 1u) to Rational(2317919, 44100), + mapOf(x to 4u, y to 1u) to Rational(1169471, 6615), + mapOf(y to 2u) to Rational(-4057819, 33600), + mapOf(x to 1u, y to 2u) to Rational(1373311, 12600), + mapOf(x to 2u, y to 2u) to Rational(32433493, 52920), + mapOf(x to 3u, y to 2u) to Rational(4998053, 33075), + mapOf(x to 4u, y to 2u) to Rational(-2147779, 8820), + mapOf(y to 3u) to Rational(2018481, 2240), + mapOf(x to 1u, y to 3u) to Rational(941713, 1440), + mapOf(x to 2u, y to 3u) to Rational(183749, 6615), + mapOf(x to 3u, y to 3u) to Rational(-4631023, 15876), + mapOf(x to 4u, y to 3u) to Rational(25609336, 178605), + mapOf(y to 4u) to Rational(11886431, 6720), + mapOf(x to 1u, y to 4u) to Rational(18433, 504), + mapOf(x to 2u, y to 4u) to Rational(-39613331, 45360), + mapOf(x to 3u, y to 4u) to Rational(681619, 5670), + mapOf(x to 4u, y to 4u) to Rational(-864841, 20412), + mapOf(y to 5u) to Rational(343535, 1008), + mapOf(x to 1u, y to 5u) to Rational(-33583, 72), + mapOf(x to 2u, y to 5u) to Rational(1194625, 9072), + mapOf(x to 3u, y to 5u) to Rational(-62917, 2268), + mapOf(x to 4u, y to 5u) to Rational(157645, 10206), + mapOf(y to 6u) to Rational(-1381, 3), + mapOf(x to 1u, y to 6u) to Rational(919, 36), + mapOf(x to 2u, y to 6u) to Rational(-3053, 36), + mapOf(x to 3u, y to 6u) to Rational(2125, 324), + mapOf(x to 4u, y to 6u) to Rational(-236, 243) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-66677, 3500), + mapOf(x to 1u) to Rational(-206281, 10500), + mapOf(x to 2u) to Rational(-412567, 7056), + mapOf(x to 3u) to Rational(-310081, 11025), + mapOf(x to 4u) to Rational(-575996, 15435), + mapOf(y to 1u) to Rational(-573701, 4200), + mapOf(x to 1u, y to 1u) to Rational(-2239001, 25200), + mapOf(x to 2u, y to 1u) to Rational(-8817889, 132300), + mapOf(x to 3u, y to 1u) to Rational(2317919, 44100), + mapOf(x to 4u, y to 1u) to Rational(1169471, 6615), + mapOf(y to 2u) to Rational(-4057819, 33600), + mapOf(x to 1u, y to 2u) to Rational(1373311, 12600), + mapOf(x to 2u, y to 2u) to Rational(32433493, 52920), + mapOf(x to 3u, y to 2u) to Rational(4998053, 33075), + mapOf(x to 4u, y to 2u) to Rational(-2147779, 8820), + mapOf(y to 3u) to Rational(2018481, 2240), + mapOf(x to 1u, y to 3u) to Rational(941713, 1440), + mapOf(x to 2u, y to 3u) to Rational(183749, 6615), + mapOf(x to 3u, y to 3u) to Rational(-4631023, 15876), + mapOf(x to 4u, y to 3u) to Rational(25609336, 178605), + mapOf(y to 4u) to Rational(11886431, 6720), + mapOf(x to 1u, y to 4u) to Rational(18433, 504), + mapOf(x to 2u, y to 4u) to Rational(-39613331, 45360), + mapOf(x to 3u, y to 4u) to Rational(681619, 5670), + mapOf(x to 4u, y to 4u) to Rational(-864841, 20412), + mapOf(y to 5u) to Rational(343535, 1008), + mapOf(x to 1u, y to 5u) to Rational(-33583, 72), + mapOf(x to 2u, y to 5u) to Rational(1194625, 9072), + mapOf(x to 3u, y to 5u) to Rational(-62917, 2268), + mapOf(x to 4u, y to 5u) to Rational(157645, 10206), + mapOf(y to 6u) to Rational(-1381, 3), + mapOf(x to 1u, y to 6u) to Rational(919, 36), + mapOf(x to 2u, y to 6u) to Rational(-3053, 36), + mapOf(x to 3u, y to 6u) to Rational(2125, 324), + mapOf(x to 4u, y to 6u) to Rational(-236, 243) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(17, 5), + mapOf(x to 1u) to Rational(11, 6), + mapOf(x to 2u) to Rational(14, 3), + mapOf(y to 1u) to Rational(17, 1), + mapOf(x to 1u, y to 1u) to Rational(12, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 2), + mapOf(y to 2u) to Rational(17, 1), + mapOf(x to 1u, y to 2u) to Rational(-4, 3), + mapOf(x to 2u, y to 2u) to Rational(2, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(3, 5), + mapOf(x to 1u) to Rational(3, 5), + mapOf(x to 2u) to Rational(3, 7), + mapOf(y to 1u) to Rational(-3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 1), + mapOf(x to 2u, y to 1u) to Rational(17, 9), + mapOf(y to 2u) to Rational(-8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 4), + mapOf(x to 2u, y to 2u) to Rational(10, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(3539, 700), + mapOf(x to 1u) to Rational(-307079, 6300), + mapOf(x to 2u) to Rational(451609, 15120), + mapOf(x to 3u) to Rational(35287733, 396900), + mapOf(x to 4u) to Rational(-37242617, 396900), + mapOf(x to 5u) to Rational(382747, 19845), + mapOf(x to 6u) to Rational(-2407, 3969), + mapOf(y to 1u) to Rational(-226, 175), + mapOf(x to 1u, y to 1u) to Rational(-74113, 1890), + mapOf(x to 2u, y to 1u) to Rational(250931, 1764), + mapOf(x to 3u, y to 1u) to Rational(30071473, 99225), + mapOf(x to 4u, y to 1u) to Rational(-286466, 1323), + mapOf(x to 5u, y to 1u) to Rational(-2285282, 9261), + mapOf(x to 6u, y to 1u) to Rational(17900, 441), + mapOf(y to 2u) to Rational(3817, 3150), + mapOf(x to 1u, y to 2u) to Rational(577568, 11025), + mapOf(x to 2u, y to 2u) to Rational(9073553, 99225), + mapOf(x to 3u, y to 2u) to Rational(-1415849, 79380), + mapOf(x to 4u, y to 2u) to Rational(-124715629, 277830), + mapOf(x to 5u, y to 2u) to Rational(-1328953, 1890), + mapOf(x to 6u, y to 2u) to Rational(-297148, 1323), + mapOf(y to 3u) to Rational(6043, 945), + mapOf(x to 1u, y to 3u) to Rational(160381, 6615), + mapOf(x to 2u, y to 3u) to Rational(-673249, 13230), + mapOf(x to 3u, y to 3u) to Rational(-319255, 2058), + mapOf(x to 4u, y to 3u) to Rational(-98144, 1029), + mapOf(x to 5u, y to 3u) to Rational(-320239, 5145), + mapOf(x to 6u, y to 3u) to Rational(400, 147), + mapOf(y to 4u) to Rational(163, 63), + mapOf(x to 1u, y to 4u) to Rational(-25183, 4410), + mapOf(x to 2u, y to 4u) to Rational(-21369, 1372), + mapOf(x to 3u, y to 4u) to Rational(127499, 30870), + mapOf(x to 4u, y to 4u) to Rational(86971, 12348), + mapOf(x to 5u, y to 4u) to Rational(-11129, 1470), + mapOf(x to 6u, y to 4u) to Rational(544, 147) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(3539, 700), + mapOf(x to 1u) to Rational(-307079, 6300), + mapOf(x to 2u) to Rational(451609, 15120), + mapOf(x to 3u) to Rational(35287733, 396900), + mapOf(x to 4u) to Rational(-37242617, 396900), + mapOf(x to 5u) to Rational(382747, 19845), + mapOf(x to 6u) to Rational(-2407, 3969), + mapOf(y to 1u) to Rational(-226, 175), + mapOf(x to 1u, y to 1u) to Rational(-74113, 1890), + mapOf(x to 2u, y to 1u) to Rational(250931, 1764), + mapOf(x to 3u, y to 1u) to Rational(30071473, 99225), + mapOf(x to 4u, y to 1u) to Rational(-286466, 1323), + mapOf(x to 5u, y to 1u) to Rational(-2285282, 9261), + mapOf(x to 6u, y to 1u) to Rational(17900, 441), + mapOf(y to 2u) to Rational(3817, 3150), + mapOf(x to 1u, y to 2u) to Rational(577568, 11025), + mapOf(x to 2u, y to 2u) to Rational(9073553, 99225), + mapOf(x to 3u, y to 2u) to Rational(-1415849, 79380), + mapOf(x to 4u, y to 2u) to Rational(-124715629, 277830), + mapOf(x to 5u, y to 2u) to Rational(-1328953, 1890), + mapOf(x to 6u, y to 2u) to Rational(-297148, 1323), + mapOf(y to 3u) to Rational(6043, 945), + mapOf(x to 1u, y to 3u) to Rational(160381, 6615), + mapOf(x to 2u, y to 3u) to Rational(-673249, 13230), + mapOf(x to 3u, y to 3u) to Rational(-319255, 2058), + mapOf(x to 4u, y to 3u) to Rational(-98144, 1029), + mapOf(x to 5u, y to 3u) to Rational(-320239, 5145), + mapOf(x to 6u, y to 3u) to Rational(400, 147), + mapOf(y to 4u) to Rational(163, 63), + mapOf(x to 1u, y to 4u) to Rational(-25183, 4410), + mapOf(x to 2u, y to 4u) to Rational(-21369, 1372), + mapOf(x to 3u, y to 4u) to Rational(127499, 30870), + mapOf(x to 4u, y to 4u) to Rational(86971, 12348), + mapOf(x to 5u, y to 4u) to Rational(-11129, 1470), + mapOf(x to 6u, y to 4u) to Rational(544, 147) + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-5, 3), + mapOf(x to 2u) to Rational(35, 9), + mapOf(x to 3u) to Rational(-100, 27), + mapOf(x to 4u) to Rational(100, 81), + mapOf(y to 1u) to Rational(-5, 3), + mapOf(x to 1u, y to 1u) to Rational(14, 9), + mapOf(x to 2u, y to 1u) to Rational(1874, 189), + mapOf(x to 3u, y to 1u) to Rational(-620, 63), + mapOf(x to 4u, y to 1u) to Rational(40, 63), + mapOf(y to 2u) to Rational(16, 9), + mapOf(x to 1u, y to 2u) to Rational(365, 21), + mapOf(x to 2u, y to 2u) to Rational(112, 9), + mapOf(x to 3u, y to 2u) to Rational(-464, 63), + mapOf(x to 4u, y to 2u) to Rational(1996, 441), + mapOf(y to 3u) to Rational(10, 3), + mapOf(x to 1u, y to 3u) to Rational(118, 21), + mapOf(x to 2u, y to 3u) to Rational(-272, 21), + mapOf(x to 3u, y to 3u) to Rational(-764, 49), + mapOf(x to 4u, y to 3u) to Rational(8, 7), + mapOf(y to 4u) to Rational(1, 1), + mapOf(x to 1u, y to 4u) to Rational(-10, 7), + mapOf(x to 2u, y to 4u) to Rational(-171, 49), + mapOf(x to 3u, y to 4u) to Rational(20, 7), + mapOf(x to 4u, y to 4u) to Rational(4, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(18, 5), + mapOf(x to 1u) to Rational(-17, 5), + mapOf(x to 2u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(-5, 1), + mapOf(x to 2u, y to 1u) to Rational(-9, 1), + mapOf(y to 2u) to Rational(-8, 8), + mapOf(x to 1u, y to 2u) to Rational(2, 7), + mapOf(x to 2u, y to 2u) to Rational(-13, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-4, 8), + mapOf(x to 1u) to Rational(15, 9), + mapOf(x to 2u) to Rational(-10, 9), + mapOf(y to 1u) to Rational(5, 3), + mapOf(x to 1u, y to 1u) to Rational(4, 1), + mapOf(x to 2u, y to 1u) to Rational(-2, 7), + mapOf(y to 2u) to Rational(2, 2), + mapOf(x to 1u, y to 2u) to Rational(-5, 7), + mapOf(x to 2u, y to 2u) to Rational(-18, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 5'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(0, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ), + LabeledPolynomialAsIs(mapOf() to Rational(0, 1), + mapOf() to Rational(0, 1) + ) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(15, 7), + mapOf(x to 1u) to Rational(1, 5), + mapOf(x to 2u) to Rational(-7, 4), + mapOf(y to 1u) to Rational(-1, 9), + mapOf(x to 1u, y to 1u) to Rational(-2, 7), + mapOf(x to 2u, y to 1u) to Rational(17, 3), + mapOf(y to 2u) to Rational(2, 6), + mapOf(x to 1u, y to 2u) to Rational(-17, 6), + mapOf(x to 2u, y to 2u) to Rational(-6, 2), + ).substitute(RationalField, mapOf( + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 9), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(10, 9), + mapOf(y to 1u) to Rational(13, 3), + mapOf(x to 1u, y to 1u) to Rational(-12, 4), + mapOf(x to 2u, y to 1u) to Rational(3, 6), + mapOf(y to 2u) to Rational(2, 9), + mapOf(x to 1u, y to 2u) to Rational(7, 3), + mapOf(x to 2u, y to 2u) to Rational(16, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 2), + mapOf(x to 1u) to Rational(6, 2), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 5), + mapOf(y to 2u) to Rational(8, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(17, 4), + ) + ) + )), + "test 6'" + ) + } + @Test + fun test_RationalFunction_substitute_Double_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs(emptyMap() to 0.0), + LabeledPolynomialAsIs(emptyMap() to 1.0), + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 1.0, + mapOf(x to 1u) to -2.0, + mapOf(x to 2u) to 1.0, + ), + LabeledPolynomialAsIs( + mapOf() to 1.0, + ) + ).substitute(mapOf( + x to 1.0 + )), + 0.001, + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf()), + 0.001, + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + iota to 0.9211194782050933 + )), + 0.001, + "test 2'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 151.1502229133916, + mapOf(y to 1u) to -262.3790170577034, + mapOf(y to 2u) to 102.5097937392923, + ), + LabeledPolynomialAsIs( + mapOf() to -367.9969733169944, + mapOf(y to 1u) to 112.4911133334554, + mapOf(y to 2u) to -469.755906895345, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + )), + 0.001, + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 151.1502229133916, + mapOf(y to 1u) to -262.3790170577034, + mapOf(y to 2u) to 102.5097937392923, + ), + LabeledPolynomialAsIs( + mapOf() to -367.9969733169944, + mapOf(y to 1u) to 112.4911133334554, + mapOf(y to 2u) to -469.755906895345, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + iota to 0.9211194782050933 + )), + 0.001, + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 14.24074356896978, + mapOf(x to 1u) to -17.71987055153461, + mapOf(x to 2u) to -2.288056483312383, + ), + LabeledPolynomialAsIs( + mapOf() to 7.480604285873397, + mapOf(x to 1u) to -8.43478016688617, + mapOf(x to 2u) to -9.88934943900592, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + y to 0.795265651276015, + )), + 0.001, + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 14.24074356896978, + mapOf(x to 1u) to -17.71987055153461, + mapOf(x to 2u) to -2.288056483312383, + ), + LabeledPolynomialAsIs( + mapOf() to 7.480604285873397, + mapOf(x to 1u) to -8.43478016688617, + mapOf(x to 2u) to -9.88934943900592, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + y to 0.795265651276015, + iota to 0.9211194782050933 + )), + 0.001, + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 7.321261307532708, + ), + LabeledPolynomialAsIs( + mapOf() to -575.6325831127576, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + y to 0.795265651276015, + )), + 0.001, + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 7.321261307532708, + ), + LabeledPolynomialAsIs( + mapOf() to -575.6325831127576, + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to 6.593754860231304, + mapOf(x to 1u) to -7.853302571550634, + mapOf(x to 2u) to 1.2265042281530025, + mapOf(y to 1u) to 3.762648877294904, + mapOf(x to 1u, y to 1u) to -8.945144619305292, + mapOf(x to 2u, y to 1u) to -5.141384718042281, + mapOf(y to 2u) to 7.359794483988782, + mapOf(x to 1u, y to 2u) to -4.3526172680518815, + mapOf(x to 2u, y to 2u) to 0.907910924854372, + ), + LabeledPolynomialAsIs( + mapOf() to 9.533292132172562, + mapOf(x to 1u) to -1.982814534018857, + mapOf(x to 2u) to -5.974248303415283, + mapOf(y to 1u) to 1.5876716499288879, + mapOf(x to 1u, y to 1u) to -7.535152566659664, + mapOf(x to 2u, y to 1u) to 0.7549300500153517, + mapOf(y to 2u) to -5.242030058021028, + mapOf(x to 1u, y to 2u) to -0.7265704289690582, + mapOf(x to 2u, y to 2u) to -7.139677818189821, + ) + ).substitute(mapOf( + x to -8.11707689492641, + y to 0.795265651276015, + iota to 0.9211194782050933 + )), + 0.001, + "test 5'" + ) + } + @Test + fun test_RationalFunction_substitute_Constant_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + x to Rational(1) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(22047, 2450), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2204953, 147000), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + y to Rational(-13, 7), + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(22047, 2450), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2204953, 147000), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + y to Rational(-13, 7), + iota to Rational(-16, 4), + )), + "test 2'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(4191, 490), + mapOf(x to 1u) to Rational(14975, 1176), + mapOf(x to 2u) to Rational(-10429, 1176) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-775, 147), + mapOf(x to 1u) to Rational(-155, 49), + mapOf(x to 2u) to Rational(-757, 280) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + y to Rational(-13, 7), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(4191, 490), + mapOf(x to 1u) to Rational(14975, 1176), + mapOf(x to 2u) to Rational(-10429, 1176) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-775, 147), + mapOf(x to 1u) to Rational(-155, 49), + mapOf(x to 2u) to Rational(-757, 280) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + y to Rational(-13, 7), + iota to Rational(-16, 4), + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-939, 200), + mapOf(y to 1u) to Rational(123, 50), + mapOf(y to 2u) to Rational(1059, 200) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(121, 25), + mapOf(y to 1u) to Rational(-949, 375), + mapOf(y to 2u) to Rational(-1423, 200) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-939, 200), + mapOf(y to 1u) to Rational(123, 50), + mapOf(y to 2u) to Rational(1059, 200) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(121, 25), + mapOf(y to 1u) to Rational(-949, 375), + mapOf(y to 2u) to Rational(-1423, 200) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + x to Rational(7, 5), + iota to Rational(-16, 4), + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf()), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-3, 5), + mapOf(x to 1u) to Rational(-18, 4), + mapOf(x to 2u) to Rational(9, 8), + mapOf(y to 1u) to Rational(-11, 6), + mapOf(x to 1u, y to 1u) to Rational(-16, 3), + mapOf(x to 2u, y to 1u) to Rational(12, 2), + mapOf(y to 2u) to Rational(5, 3), + mapOf(x to 1u, y to 2u) to Rational(17, 8), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(11, 1), + mapOf(x to 1u) to Rational(4, 1), + mapOf(x to 2u) to Rational(-18, 3), + mapOf(y to 1u) to Rational(12, 9), + mapOf(x to 1u, y to 1u) to Rational(14, 7), + mapOf(x to 2u, y to 1u) to Rational(-17, 5), + mapOf(y to 2u) to Rational(-4, 1), + mapOf(x to 1u, y to 2u) to Rational(-5, 5), + mapOf(x to 2u, y to 2u) to Rational(-7, 8), + ) + ).substitute(RationalField, mapOf( + iota to Rational(-16, 4), + )), + "test 5'" + ) + } + @Test + fun test_RationalFunction_substitute_Polynomial_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(211, 4), + mapOf(x to 2u) to Rational(88, 3), + mapOf(x to 3u) to Rational(-63, 8), + mapOf(x to 4u) to Rational(441, 16), + mapOf(y to 1u) to Rational(-671, 15), + mapOf(x to 1u, y to 1u) to Rational(-551, 21), + mapOf(x to 2u, y to 1u) to Rational(279, 25), + mapOf(x to 3u, y to 1u) to Rational(231, 20), + mapOf(y to 2u) to Rational(-1436, 1575), + mapOf(x to 1u, y to 2u) to Rational(2471, 250), + mapOf(x to 2u, y to 2u) to Rational(-4919, 100), + mapOf(y to 3u) to Rational(-1464, 125), + mapOf(x to 1u, y to 3u) to Rational(-264, 25), + mapOf(y to 4u) to Rational(576, 25), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(-9, 4), + mapOf(x to 2u) to Rational(943, 8), + mapOf(x to 3u) to Rational(117, 8), + mapOf(x to 4u) to Rational(147, 16), + mapOf(y to 1u) to Rational(289, 90), + mapOf(x to 1u, y to 1u) to Rational(-2692, 15), + mapOf(x to 2u, y to 1u) to Rational(-1629, 140), + mapOf(x to 3u, y to 1u) to Rational(77, 20), + mapOf(y to 2u) to Rational(6187, 75), + mapOf(x to 1u, y to 2u) to Rational(-2879, 175), + mapOf(x to 2u, y to 2u) to Rational(-4919, 300), + mapOf(y to 3u) to Rational(336, 25), + mapOf(x to 1u, y to 3u) to Rational(-88, 25), + mapOf(y to 4u) to Rational(192, 25), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(3, 2), + mapOf(y to 1u) to Rational(8, 5), + ), + y to LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-3, 1), + ) + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1202861, 210), + mapOf(x to 1u) to Rational(-215117, 45), + mapOf(x to 2u) to Rational(10889651, 19845), + mapOf(x to 3u) to Rational(-3503956, 6615), + mapOf(x to 4u) to Rational(809066, 2205), + mapOf(x to 5u) to Rational(-9056, 735), + mapOf(x to 6u) to Rational(5396, 315), + mapOf(x to 7u) to Rational(-752, 147), + mapOf(x to 8u) to Rational(16, 49), + mapOf(y to 1u) to Rational(1738469, 1470), + mapOf(x to 1u, y to 1u) to Rational(-926238703, 52920), + mapOf(x to 2u, y to 1u) to Rational(-44113982, 6615), + mapOf(x to 3u, y to 1u) to Rational(10423519, 5292), + mapOf(x to 4u, y to 1u) to Rational(3769712, 2205), + mapOf(x to 5u, y to 1u) to Rational(8905046, 6615), + mapOf(x to 6u, y to 1u) to Rational(1186972, 6615), + mapOf(x to 7u, y to 1u) to Rational(22124, 441), + mapOf(x to 8u, y to 1u) to Rational(-1504, 147), + mapOf(y to 2u) to Rational(-54723628, 2205), + mapOf(x to 1u, y to 2u) to Rational(70109407, 1323), + mapOf(x to 2u, y to 2u) to Rational(151072591, 17640), + mapOf(x to 3u, y to 2u) to Rational(1216428107, 52920), + mapOf(x to 4u, y to 2u) to Rational(2587873193, 317520), + mapOf(x to 5u, y to 2u) to Rational(393536369, 79380), + mapOf(x to 6u, y to 2u) to Rational(137614937, 79380), + mapOf(x to 7u, y to 2u) to Rational(566866, 1323), + mapOf(x to 8u, y to 2u) to Rational(41848, 441), + mapOf(y to 3u) to Rational(-19470406, 2205), + mapOf(x to 1u, y to 3u) to Rational(72514195, 882), + mapOf(x to 2u, y to 3u) to Rational(-78090707, 1764), + mapOf(x to 3u, y to 3u) to Rational(-1988237707, 26460), + mapOf(x to 4u, y to 3u) to Rational(-802137919, 17640), + mapOf(x to 5u, y to 3u) to Rational(-139989463, 5880), + mapOf(x to 6u, y to 3u) to Rational(-26066641, 3780), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 1323), + mapOf(x to 8u, y to 3u) to Rational(-108280, 441), + mapOf(y to 4u) to Rational(14878516, 441), + mapOf(x to 1u, y to 4u) to Rational(-253416724, 2205), + mapOf(x to 2u, y to 4u) to Rational(16699157, 840), + mapOf(x to 3u, y to 4u) to Rational(-105220979, 13230), + mapOf(x to 4u, y to 4u) to Rational(208266383, 5880), + mapOf(x to 5u, y to 4u) to Rational(650135309, 26460), + mapOf(x to 6u, y to 4u) to Rational(123808663, 11760), + mapOf(x to 7u, y to 4u) to Rational(8563385, 2646), + mapOf(x to 8u, y to 4u) to Rational(19721, 49), + mapOf(y to 5u) to Rational(675645, 49), + mapOf(x to 1u, y to 5u) to Rational(-70554077, 588), + mapOf(x to 2u, y to 5u) to Rational(157884029, 980), + mapOf(x to 3u, y to 5u) to Rational(489548623, 4410), + mapOf(x to 4u, y to 5u) to Rational(148540519, 17640), + mapOf(x to 5u, y to 5u) to Rational(-5559551, 392), + mapOf(x to 6u, y to 5u) to Rational(-18335711, 1470), + mapOf(x to 7u, y to 5u) to Rational(-38437, 9), + mapOf(x to 8u, y to 5u) to Rational(-29620, 63), + mapOf(y to 6u) to Rational(-727625, 49), + mapOf(x to 1u, y to 6u) to Rational(7046685, 98), + mapOf(x to 2u, y to 6u) to Rational(-334814231, 7056), + mapOf(x to 3u, y to 6u) to Rational(-243971737, 17640), + mapOf(x to 4u, y to 6u) to Rational(-571116659, 35280), + mapOf(x to 5u, y to 6u) to Rational(567538, 315), + mapOf(x to 6u, y to 6u) to Rational(3199768, 315), + mapOf(x to 7u, y to 6u) to Rational(227744, 63), + mapOf(x to 8u, y to 6u) to Rational(23116, 63), + mapOf(y to 7u) to Rational(-27500, 7), + mapOf(x to 1u, y to 7u) to Rational(120125, 3), + mapOf(x to 2u, y to 7u) to Rational(-279200, 3), + mapOf(x to 3u, y to 7u) to Rational(-100160, 7), + mapOf(x to 4u, y to 7u) to Rational(920452, 21), + mapOf(x to 5u, y to 7u) to Rational(226481, 21), + mapOf(x to 6u, y to 7u) to Rational(-34428, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 3), + mapOf(x to 8u, y to 7u) to Rational(-608, 3), + mapOf(y to 8u) to Rational(2500, 1), + mapOf(x to 1u, y to 8u) to Rational(-19000, 1), + mapOf(x to 2u, y to 8u) to Rational(37900, 1), + mapOf(x to 3u, y to 8u) to Rational(-1840, 1), + mapOf(x to 4u, y to 8u) to Rational(-17876, 1), + mapOf(x to 5u, y to 8u) to Rational(-1240, 1), + mapOf(x to 6u, y to 8u) to Rational(2788, 1), + mapOf(x to 7u, y to 8u) to Rational(800, 1), + mapOf(x to 8u, y to 8u) to Rational(64, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(162487, 63), + mapOf(x to 1u) to Rational(-92713, 54), + mapOf(x to 2u) to Rational(802436, 1323), + mapOf(x to 3u) to Rational(-55088, 441), + mapOf(x to 4u) to Rational(1404034, 9261), + mapOf(x to 5u) to Rational(-5804, 1029), + mapOf(x to 6u) to Rational(51556, 9261), + mapOf(x to 7u) to Rational(-752, 441), + mapOf(x to 8u) to Rational(16, 147), + mapOf(y to 1u) to Rational(296071, 441), + mapOf(x to 1u, y to 1u) to Rational(-4991281, 882), + mapOf(x to 2u, y to 1u) to Rational(-18702811, 9261), + mapOf(x to 3u, y to 1u) to Rational(40759043, 27783), + mapOf(x to 4u, y to 1u) to Rational(19768501, 27783), + mapOf(x to 5u, y to 1u) to Rational(14307337, 27783), + mapOf(x to 6u, y to 1u) to Rational(1655684, 27783), + mapOf(x to 7u, y to 1u) to Rational(22124, 1323), + mapOf(x to 8u, y to 1u) to Rational(-1504, 441), + mapOf(y to 2u) to Rational(-27667474, 3087), + mapOf(x to 1u, y to 2u) to Rational(265605901, 12348), + mapOf(x to 2u, y to 2u) to Rational(160360775, 98784), + mapOf(x to 3u, y to 2u) to Rational(1169992093, 148176), + mapOf(x to 4u, y to 2u) to Rational(3978014077, 1333584), + mapOf(x to 5u, y to 2u) to Rational(567058123, 333396), + mapOf(x to 6u, y to 2u) to Rational(205132579, 333396), + mapOf(x to 7u, y to 2u) to Rational(566866, 3969), + mapOf(x to 8u, y to 2u) to Rational(41848, 1323), + mapOf(y to 3u) to Rational(-2228822, 1029), + mapOf(x to 1u, y to 3u) to Rational(80179390, 3087), + mapOf(x to 2u, y to 3u) to Rational(-1378630487, 74088), + mapOf(x to 3u, y to 3u) to Rational(-3385811693, 111132), + mapOf(x to 4u, y to 3u) to Rational(-820686977, 49392), + mapOf(x to 5u, y to 3u) to Rational(-89101027, 10584), + mapOf(x to 6u, y to 3u) to Rational(-37847387, 15876), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 3969), + mapOf(x to 8u, y to 3u) to Rational(-108280, 1323), + mapOf(y to 4u) to Rational(12619982, 1029), + mapOf(x to 1u, y to 4u) to Rational(-277723177, 6174), + mapOf(x to 2u, y to 4u) to Rational(649414169, 49392), + mapOf(x to 3u, y to 4u) to Rational(14457595, 63504), + mapOf(x to 4u, y to 4u) to Rational(139270339, 10584), + mapOf(x to 5u, y to 4u) to Rational(140367961, 15876), + mapOf(x to 6u, y to 4u) to Rational(25467083, 7056), + mapOf(x to 7u, y to 4u) to Rational(8563385, 7938), + mapOf(x to 8u, y to 4u) to Rational(19721, 147), + mapOf(y to 5u) to Rational(643850, 147), + mapOf(x to 1u, y to 5u) to Rational(-11818025, 294), + mapOf(x to 2u, y to 5u) to Rational(33963203, 588), + mapOf(x to 3u, y to 5u) to Rational(207216235, 5292), + mapOf(x to 4u, y to 5u) to Rational(2861021, 1512), + mapOf(x to 5u, y to 5u) to Rational(-6302335, 1176), + mapOf(x to 6u, y to 5u) to Rational(-3738587, 882), + mapOf(x to 7u, y to 5u) to Rational(-38437, 27), + mapOf(x to 8u, y to 5u) to Rational(-29620, 189), + mapOf(y to 6u) to Rational(-248725, 49), + mapOf(x to 1u, y to 6u) to Rational(2478535, 98), + mapOf(x to 2u, y to 6u) to Rational(-399721367, 21168), + mapOf(x to 3u, y to 6u) to Rational(-54309317, 10584), + mapOf(x to 4u, y to 6u) to Rational(-95398327, 21168), + mapOf(x to 5u, y to 6u) to Rational(173750, 189), + mapOf(x to 6u, y to 6u) to Rational(92216, 27), + mapOf(x to 7u, y to 6u) to Rational(227744, 189), + mapOf(x to 8u, y to 6u) to Rational(23116, 189), + mapOf(y to 7u) to Rational(-27500, 21), + mapOf(x to 1u, y to 7u) to Rational(120125, 9), + mapOf(x to 2u, y to 7u) to Rational(-279200, 9), + mapOf(x to 3u, y to 7u) to Rational(-100160, 21), + mapOf(x to 4u, y to 7u) to Rational(920452, 63), + mapOf(x to 5u, y to 7u) to Rational(226481, 63), + mapOf(x to 6u, y to 7u) to Rational(-11476, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 9), + mapOf(x to 8u, y to 7u) to Rational(-608, 9), + mapOf(y to 8u) to Rational(2500, 3), + mapOf(x to 1u, y to 8u) to Rational(-19000, 3), + mapOf(x to 2u, y to 8u) to Rational(37900, 3), + mapOf(x to 3u, y to 8u) to Rational(-1840, 3), + mapOf(x to 4u, y to 8u) to Rational(-17876, 3), + mapOf(x to 5u, y to 8u) to Rational(-1240, 3), + mapOf(x to 6u, y to 8u) to Rational(2788, 3), + mapOf(x to 7u, y to 8u) to Rational(800, 3), + mapOf(x to 8u, y to 8u) to Rational(64, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1202861, 210), + mapOf(x to 1u) to Rational(-215117, 45), + mapOf(x to 2u) to Rational(10889651, 19845), + mapOf(x to 3u) to Rational(-3503956, 6615), + mapOf(x to 4u) to Rational(809066, 2205), + mapOf(x to 5u) to Rational(-9056, 735), + mapOf(x to 6u) to Rational(5396, 315), + mapOf(x to 7u) to Rational(-752, 147), + mapOf(x to 8u) to Rational(16, 49), + mapOf(y to 1u) to Rational(1738469, 1470), + mapOf(x to 1u, y to 1u) to Rational(-926238703, 52920), + mapOf(x to 2u, y to 1u) to Rational(-44113982, 6615), + mapOf(x to 3u, y to 1u) to Rational(10423519, 5292), + mapOf(x to 4u, y to 1u) to Rational(3769712, 2205), + mapOf(x to 5u, y to 1u) to Rational(8905046, 6615), + mapOf(x to 6u, y to 1u) to Rational(1186972, 6615), + mapOf(x to 7u, y to 1u) to Rational(22124, 441), + mapOf(x to 8u, y to 1u) to Rational(-1504, 147), + mapOf(y to 2u) to Rational(-54723628, 2205), + mapOf(x to 1u, y to 2u) to Rational(70109407, 1323), + mapOf(x to 2u, y to 2u) to Rational(151072591, 17640), + mapOf(x to 3u, y to 2u) to Rational(1216428107, 52920), + mapOf(x to 4u, y to 2u) to Rational(2587873193, 317520), + mapOf(x to 5u, y to 2u) to Rational(393536369, 79380), + mapOf(x to 6u, y to 2u) to Rational(137614937, 79380), + mapOf(x to 7u, y to 2u) to Rational(566866, 1323), + mapOf(x to 8u, y to 2u) to Rational(41848, 441), + mapOf(y to 3u) to Rational(-19470406, 2205), + mapOf(x to 1u, y to 3u) to Rational(72514195, 882), + mapOf(x to 2u, y to 3u) to Rational(-78090707, 1764), + mapOf(x to 3u, y to 3u) to Rational(-1988237707, 26460), + mapOf(x to 4u, y to 3u) to Rational(-802137919, 17640), + mapOf(x to 5u, y to 3u) to Rational(-139989463, 5880), + mapOf(x to 6u, y to 3u) to Rational(-26066641, 3780), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 1323), + mapOf(x to 8u, y to 3u) to Rational(-108280, 441), + mapOf(y to 4u) to Rational(14878516, 441), + mapOf(x to 1u, y to 4u) to Rational(-253416724, 2205), + mapOf(x to 2u, y to 4u) to Rational(16699157, 840), + mapOf(x to 3u, y to 4u) to Rational(-105220979, 13230), + mapOf(x to 4u, y to 4u) to Rational(208266383, 5880), + mapOf(x to 5u, y to 4u) to Rational(650135309, 26460), + mapOf(x to 6u, y to 4u) to Rational(123808663, 11760), + mapOf(x to 7u, y to 4u) to Rational(8563385, 2646), + mapOf(x to 8u, y to 4u) to Rational(19721, 49), + mapOf(y to 5u) to Rational(675645, 49), + mapOf(x to 1u, y to 5u) to Rational(-70554077, 588), + mapOf(x to 2u, y to 5u) to Rational(157884029, 980), + mapOf(x to 3u, y to 5u) to Rational(489548623, 4410), + mapOf(x to 4u, y to 5u) to Rational(148540519, 17640), + mapOf(x to 5u, y to 5u) to Rational(-5559551, 392), + mapOf(x to 6u, y to 5u) to Rational(-18335711, 1470), + mapOf(x to 7u, y to 5u) to Rational(-38437, 9), + mapOf(x to 8u, y to 5u) to Rational(-29620, 63), + mapOf(y to 6u) to Rational(-727625, 49), + mapOf(x to 1u, y to 6u) to Rational(7046685, 98), + mapOf(x to 2u, y to 6u) to Rational(-334814231, 7056), + mapOf(x to 3u, y to 6u) to Rational(-243971737, 17640), + mapOf(x to 4u, y to 6u) to Rational(-571116659, 35280), + mapOf(x to 5u, y to 6u) to Rational(567538, 315), + mapOf(x to 6u, y to 6u) to Rational(3199768, 315), + mapOf(x to 7u, y to 6u) to Rational(227744, 63), + mapOf(x to 8u, y to 6u) to Rational(23116, 63), + mapOf(y to 7u) to Rational(-27500, 7), + mapOf(x to 1u, y to 7u) to Rational(120125, 3), + mapOf(x to 2u, y to 7u) to Rational(-279200, 3), + mapOf(x to 3u, y to 7u) to Rational(-100160, 7), + mapOf(x to 4u, y to 7u) to Rational(920452, 21), + mapOf(x to 5u, y to 7u) to Rational(226481, 21), + mapOf(x to 6u, y to 7u) to Rational(-34428, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 3), + mapOf(x to 8u, y to 7u) to Rational(-608, 3), + mapOf(y to 8u) to Rational(2500, 1), + mapOf(x to 1u, y to 8u) to Rational(-19000, 1), + mapOf(x to 2u, y to 8u) to Rational(37900, 1), + mapOf(x to 3u, y to 8u) to Rational(-1840, 1), + mapOf(x to 4u, y to 8u) to Rational(-17876, 1), + mapOf(x to 5u, y to 8u) to Rational(-1240, 1), + mapOf(x to 6u, y to 8u) to Rational(2788, 1), + mapOf(x to 7u, y to 8u) to Rational(800, 1), + mapOf(x to 8u, y to 8u) to Rational(64, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(162487, 63), + mapOf(x to 1u) to Rational(-92713, 54), + mapOf(x to 2u) to Rational(802436, 1323), + mapOf(x to 3u) to Rational(-55088, 441), + mapOf(x to 4u) to Rational(1404034, 9261), + mapOf(x to 5u) to Rational(-5804, 1029), + mapOf(x to 6u) to Rational(51556, 9261), + mapOf(x to 7u) to Rational(-752, 441), + mapOf(x to 8u) to Rational(16, 147), + mapOf(y to 1u) to Rational(296071, 441), + mapOf(x to 1u, y to 1u) to Rational(-4991281, 882), + mapOf(x to 2u, y to 1u) to Rational(-18702811, 9261), + mapOf(x to 3u, y to 1u) to Rational(40759043, 27783), + mapOf(x to 4u, y to 1u) to Rational(19768501, 27783), + mapOf(x to 5u, y to 1u) to Rational(14307337, 27783), + mapOf(x to 6u, y to 1u) to Rational(1655684, 27783), + mapOf(x to 7u, y to 1u) to Rational(22124, 1323), + mapOf(x to 8u, y to 1u) to Rational(-1504, 441), + mapOf(y to 2u) to Rational(-27667474, 3087), + mapOf(x to 1u, y to 2u) to Rational(265605901, 12348), + mapOf(x to 2u, y to 2u) to Rational(160360775, 98784), + mapOf(x to 3u, y to 2u) to Rational(1169992093, 148176), + mapOf(x to 4u, y to 2u) to Rational(3978014077, 1333584), + mapOf(x to 5u, y to 2u) to Rational(567058123, 333396), + mapOf(x to 6u, y to 2u) to Rational(205132579, 333396), + mapOf(x to 7u, y to 2u) to Rational(566866, 3969), + mapOf(x to 8u, y to 2u) to Rational(41848, 1323), + mapOf(y to 3u) to Rational(-2228822, 1029), + mapOf(x to 1u, y to 3u) to Rational(80179390, 3087), + mapOf(x to 2u, y to 3u) to Rational(-1378630487, 74088), + mapOf(x to 3u, y to 3u) to Rational(-3385811693, 111132), + mapOf(x to 4u, y to 3u) to Rational(-820686977, 49392), + mapOf(x to 5u, y to 3u) to Rational(-89101027, 10584), + mapOf(x to 6u, y to 3u) to Rational(-37847387, 15876), + mapOf(x to 7u, y to 3u) to Rational(-2363369, 3969), + mapOf(x to 8u, y to 3u) to Rational(-108280, 1323), + mapOf(y to 4u) to Rational(12619982, 1029), + mapOf(x to 1u, y to 4u) to Rational(-277723177, 6174), + mapOf(x to 2u, y to 4u) to Rational(649414169, 49392), + mapOf(x to 3u, y to 4u) to Rational(14457595, 63504), + mapOf(x to 4u, y to 4u) to Rational(139270339, 10584), + mapOf(x to 5u, y to 4u) to Rational(140367961, 15876), + mapOf(x to 6u, y to 4u) to Rational(25467083, 7056), + mapOf(x to 7u, y to 4u) to Rational(8563385, 7938), + mapOf(x to 8u, y to 4u) to Rational(19721, 147), + mapOf(y to 5u) to Rational(643850, 147), + mapOf(x to 1u, y to 5u) to Rational(-11818025, 294), + mapOf(x to 2u, y to 5u) to Rational(33963203, 588), + mapOf(x to 3u, y to 5u) to Rational(207216235, 5292), + mapOf(x to 4u, y to 5u) to Rational(2861021, 1512), + mapOf(x to 5u, y to 5u) to Rational(-6302335, 1176), + mapOf(x to 6u, y to 5u) to Rational(-3738587, 882), + mapOf(x to 7u, y to 5u) to Rational(-38437, 27), + mapOf(x to 8u, y to 5u) to Rational(-29620, 189), + mapOf(y to 6u) to Rational(-248725, 49), + mapOf(x to 1u, y to 6u) to Rational(2478535, 98), + mapOf(x to 2u, y to 6u) to Rational(-399721367, 21168), + mapOf(x to 3u, y to 6u) to Rational(-54309317, 10584), + mapOf(x to 4u, y to 6u) to Rational(-95398327, 21168), + mapOf(x to 5u, y to 6u) to Rational(173750, 189), + mapOf(x to 6u, y to 6u) to Rational(92216, 27), + mapOf(x to 7u, y to 6u) to Rational(227744, 189), + mapOf(x to 8u, y to 6u) to Rational(23116, 189), + mapOf(y to 7u) to Rational(-27500, 21), + mapOf(x to 1u, y to 7u) to Rational(120125, 9), + mapOf(x to 2u, y to 7u) to Rational(-279200, 9), + mapOf(x to 3u, y to 7u) to Rational(-100160, 21), + mapOf(x to 4u, y to 7u) to Rational(920452, 63), + mapOf(x to 5u, y to 7u) to Rational(226481, 63), + mapOf(x to 6u, y to 7u) to Rational(-11476, 7), + mapOf(x to 7u, y to 7u) to Rational(-6232, 9), + mapOf(x to 8u, y to 7u) to Rational(-608, 9), + mapOf(y to 8u) to Rational(2500, 3), + mapOf(x to 1u, y to 8u) to Rational(-19000, 3), + mapOf(x to 2u, y to 8u) to Rational(37900, 3), + mapOf(x to 3u, y to 8u) to Rational(-1840, 3), + mapOf(x to 4u, y to 8u) to Rational(-17876, 3), + mapOf(x to 5u, y to 8u) to Rational(-1240, 3), + mapOf(x to 6u, y to 8u) to Rational(2788, 3), + mapOf(x to 7u, y to 8u) to Rational(800, 3), + mapOf(x to 8u, y to 8u) to Rational(64, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(493, 6), + mapOf(x to 1u) to Rational(-15991, 210), + mapOf(x to 2u) to Rational(2734, 63), + mapOf(x to 3u) to Rational(-8213, 245), + mapOf(x to 4u) to Rational(1843, 147), + mapOf(x to 5u) to Rational(-432, 245), + mapOf(x to 6u) to Rational(4, 49), + mapOf(y to 1u) to Rational(-66, 1), + mapOf(x to 1u, y to 1u) to Rational(-92924, 2205), + mapOf(x to 2u, y to 1u) to Rational(-257461, 2205), + mapOf(x to 3u, y to 1u) to Rational(58658, 2205), + mapOf(x to 4u, y to 1u) to Rational(-87884, 2205), + mapOf(x to 5u, y to 1u) to Rational(2726, 105), + mapOf(x to 6u, y to 1u) to Rational(-52, 21), + mapOf(y to 2u) to Rational(-17569, 147), + mapOf(x to 1u, y to 2u) to Rational(368819, 735), + mapOf(x to 2u, y to 2u) to Rational(-644626, 6615), + mapOf(x to 3u, y to 2u) to Rational(221738, 945), + mapOf(x to 4u, y to 2u) to Rational(-18022, 945), + mapOf(x to 5u, y to 2u) to Rational(-1201, 315), + mapOf(x to 6u, y to 2u) to Rational(1327, 63), + mapOf(y to 3u) to Rational(240, 7), + mapOf(x to 1u, y to 3u) to Rational(-868, 9), + mapOf(x to 2u, y to 3u) to Rational(-8936, 315), + mapOf(x to 3u, y to 3u) to Rational(-77146, 315), + mapOf(x to 4u, y to 3u) to Rational(-4072, 315), + mapOf(x to 5u, y to 3u) to Rational(-2218, 15), + mapOf(x to 6u, y to 3u) to Rational(-104, 3), + mapOf(y to 4u) to Rational(100, 3), + mapOf(x to 1u, y to 4u) to Rational(-725, 3), + mapOf(x to 2u, y to 4u) to Rational(459, 1), + mapOf(x to 3u, y to 4u) to Rational(-2071, 15), + mapOf(x to 4u, y to 4u) to Rational(2831, 15), + mapOf(x to 5u, y to 4u) to Rational(632, 5), + mapOf(x to 6u, y to 4u) to Rational(16, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1255, 9), + mapOf(x to 1u) to Rational(-24781, 126), + mapOf(x to 2u) to Rational(1195, 14), + mapOf(x to 3u) to Rational(-1931, 147), + mapOf(x to 4u) to Rational(439, 147), + mapOf(x to 5u) to Rational(-172, 343), + mapOf(x to 6u) to Rational(4, 147), + mapOf(y to 1u) to Rational(-183, 1), + mapOf(x to 1u, y to 1u) to Rational(-30988, 441), + mapOf(x to 2u, y to 1u) to Rational(-56137, 294), + mapOf(x to 3u, y to 1u) to Rational(204308, 1029), + mapOf(x to 4u, y to 1u) to Rational(-3263, 441), + mapOf(x to 5u, y to 1u) to Rational(2662, 441), + mapOf(x to 6u, y to 1u) to Rational(-52, 63), + mapOf(y to 2u) to Rational(-87119, 294), + mapOf(x to 1u, y to 2u) to Rational(1077919, 686), + mapOf(x to 2u, y to 2u) to Rational(-35209, 147), + mapOf(x to 3u, y to 2u) to Rational(15041, 147), + mapOf(x to 4u, y to 2u) to Rational(240889, 1323), + mapOf(x to 5u, y to 2u) to Rational(27778, 1323), + mapOf(x to 6u, y to 2u) to Rational(1327, 189), + mapOf(y to 3u) to Rational(1620, 7), + mapOf(x to 1u, y to 3u) to Rational(-25716, 49), + mapOf(x to 2u, y to 3u) to Rational(-32078, 49), + mapOf(x to 3u, y to 3u) to Rational(-704038, 441), + mapOf(x to 4u, y to 3u) to Rational(-30190, 63), + mapOf(x to 5u, y to 3u) to Rational(-5414, 63), + mapOf(x to 6u, y to 3u) to Rational(-104, 9), + mapOf(y to 4u) to Rational(225, 1), + mapOf(x to 1u, y to 4u) to Rational(-10560, 7), + mapOf(x to 2u, y to 4u) to Rational(44176, 21), + mapOf(x to 3u, y to 4u) to Rational(28996, 21), + mapOf(x to 4u, y to 4u) to Rational(2405, 7), + mapOf(x to 5u, y to 4u) to Rational(1240, 21), + mapOf(x to 6u, y to 4u) to Rational(16, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(493, 6), + mapOf(x to 1u) to Rational(-15991, 210), + mapOf(x to 2u) to Rational(2734, 63), + mapOf(x to 3u) to Rational(-8213, 245), + mapOf(x to 4u) to Rational(1843, 147), + mapOf(x to 5u) to Rational(-432, 245), + mapOf(x to 6u) to Rational(4, 49), + mapOf(y to 1u) to Rational(-66, 1), + mapOf(x to 1u, y to 1u) to Rational(-92924, 2205), + mapOf(x to 2u, y to 1u) to Rational(-257461, 2205), + mapOf(x to 3u, y to 1u) to Rational(58658, 2205), + mapOf(x to 4u, y to 1u) to Rational(-87884, 2205), + mapOf(x to 5u, y to 1u) to Rational(2726, 105), + mapOf(x to 6u, y to 1u) to Rational(-52, 21), + mapOf(y to 2u) to Rational(-17569, 147), + mapOf(x to 1u, y to 2u) to Rational(368819, 735), + mapOf(x to 2u, y to 2u) to Rational(-644626, 6615), + mapOf(x to 3u, y to 2u) to Rational(221738, 945), + mapOf(x to 4u, y to 2u) to Rational(-18022, 945), + mapOf(x to 5u, y to 2u) to Rational(-1201, 315), + mapOf(x to 6u, y to 2u) to Rational(1327, 63), + mapOf(y to 3u) to Rational(240, 7), + mapOf(x to 1u, y to 3u) to Rational(-868, 9), + mapOf(x to 2u, y to 3u) to Rational(-8936, 315), + mapOf(x to 3u, y to 3u) to Rational(-77146, 315), + mapOf(x to 4u, y to 3u) to Rational(-4072, 315), + mapOf(x to 5u, y to 3u) to Rational(-2218, 15), + mapOf(x to 6u, y to 3u) to Rational(-104, 3), + mapOf(y to 4u) to Rational(100, 3), + mapOf(x to 1u, y to 4u) to Rational(-725, 3), + mapOf(x to 2u, y to 4u) to Rational(459, 1), + mapOf(x to 3u, y to 4u) to Rational(-2071, 15), + mapOf(x to 4u, y to 4u) to Rational(2831, 15), + mapOf(x to 5u, y to 4u) to Rational(632, 5), + mapOf(x to 6u, y to 4u) to Rational(16, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1255, 9), + mapOf(x to 1u) to Rational(-24781, 126), + mapOf(x to 2u) to Rational(1195, 14), + mapOf(x to 3u) to Rational(-1931, 147), + mapOf(x to 4u) to Rational(439, 147), + mapOf(x to 5u) to Rational(-172, 343), + mapOf(x to 6u) to Rational(4, 147), + mapOf(y to 1u) to Rational(-183, 1), + mapOf(x to 1u, y to 1u) to Rational(-30988, 441), + mapOf(x to 2u, y to 1u) to Rational(-56137, 294), + mapOf(x to 3u, y to 1u) to Rational(204308, 1029), + mapOf(x to 4u, y to 1u) to Rational(-3263, 441), + mapOf(x to 5u, y to 1u) to Rational(2662, 441), + mapOf(x to 6u, y to 1u) to Rational(-52, 63), + mapOf(y to 2u) to Rational(-87119, 294), + mapOf(x to 1u, y to 2u) to Rational(1077919, 686), + mapOf(x to 2u, y to 2u) to Rational(-35209, 147), + mapOf(x to 3u, y to 2u) to Rational(15041, 147), + mapOf(x to 4u, y to 2u) to Rational(240889, 1323), + mapOf(x to 5u, y to 2u) to Rational(27778, 1323), + mapOf(x to 6u, y to 2u) to Rational(1327, 189), + mapOf(y to 3u) to Rational(1620, 7), + mapOf(x to 1u, y to 3u) to Rational(-25716, 49), + mapOf(x to 2u, y to 3u) to Rational(-32078, 49), + mapOf(x to 3u, y to 3u) to Rational(-704038, 441), + mapOf(x to 4u, y to 3u) to Rational(-30190, 63), + mapOf(x to 5u, y to 3u) to Rational(-5414, 63), + mapOf(x to 6u, y to 3u) to Rational(-104, 9), + mapOf(y to 4u) to Rational(225, 1), + mapOf(x to 1u, y to 4u) to Rational(-10560, 7), + mapOf(x to 2u, y to 4u) to Rational(44176, 21), + mapOf(x to 3u, y to 4u) to Rational(28996, 21), + mapOf(x to 4u, y to 4u) to Rational(2405, 7), + mapOf(x to 5u, y to 4u) to Rational(1240, 21), + mapOf(x to 6u, y to 4u) to Rational(16, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + y to LabeledPolynomialAsIs( + mapOf() to Rational(8, 2), + mapOf(x to 1u) to Rational(-15, 5), + mapOf(x to 2u) to Rational(2, 7), + mapOf(y to 1u) to Rational(-18, 7), + mapOf(x to 1u, y to 1u) to Rational(-16, 6), + mapOf(x to 2u, y to 1u) to Rational(-13, 3), + mapOf(y to 2u) to Rational(-5, 1), + mapOf(x to 1u, y to 2u) to Rational(17, 1), + mapOf(x to 2u, y to 2u) to Rational(8, 2), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-409, 6), + mapOf(x to 1u) to Rational(-376, 9), + mapOf(x to 2u) to Rational(-1781, 81), + mapOf(x to 3u) to Rational(-128, 27), + mapOf(x to 4u) to Rational(-8, 9), + mapOf(y to 1u) to Rational(18701, 210), + mapOf(x to 1u, y to 1u) to Rational(614183, 7560), + mapOf(x to 2u, y to 1u) to Rational(90941, 1890), + mapOf(x to 3u, y to 1u) to Rational(1802, 135), + mapOf(x to 4u, y to 1u) to Rational(112, 45), + mapOf(y to 2u) to Rational(181421, 315), + mapOf(x to 1u, y to 2u) to Rational(77813, 378), + mapOf(x to 2u, y to 2u) to Rational(598583, 7560), + mapOf(x to 3u, y to 2u) to Rational(85, 27), + mapOf(x to 4u, y to 2u) to Rational(2, 5), + mapOf(y to 3u) to Rational(130997, 315), + mapOf(x to 1u, y to 3u) to Rational(1093, 420), + mapOf(x to 2u, y to 3u) to Rational(9551, 2520), + mapOf(x to 3u, y to 3u) to Rational(-14, 45), + mapOf(x to 4u, y to 3u) to Rational(22, 45), + mapOf(y to 4u) to Rational(-2801, 9), + mapOf(x to 1u, y to 4u) to Rational(4033, 90), + mapOf(x to 2u, y to 4u) to Rational(6429, 80), + mapOf(x to 3u, y to 4u) to Rational(2851, 90), + mapOf(x to 4u, y to 4u) to Rational(293, 45), + mapOf(y to 5u) to Rational(-220, 1), + mapOf(x to 1u, y to 5u) to Rational(127, 1), + mapOf(x to 2u, y to 5u) to Rational(202, 5), + mapOf(x to 3u, y to 5u) to Rational(-63, 5), + mapOf(x to 4u, y to 5u) to Rational(-12, 5), + mapOf(y to 6u) to Rational(100, 1), + mapOf(x to 1u, y to 6u) to Rational(-80, 1), + mapOf(x to 2u, y to 6u) to Rational(-24, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 1), + mapOf(x to 4u, y to 6u) to Rational(4, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5407, 9), + mapOf(x to 1u) to Rational(9568, 27), + mapOf(x to 2u) to Rational(4996, 27), + mapOf(x to 3u) to Rational(352, 9), + mapOf(x to 4u) to Rational(22, 3), + mapOf(y to 1u) to Rational(104411, 126), + mapOf(x to 1u, y to 1u) to Rational(6001, 126), + mapOf(x to 2u, y to 1u) to Rational(-796, 21), + mapOf(x to 3u, y to 1u) to Rational(-5389, 126), + mapOf(x to 4u, y to 1u) to Rational(-166, 21), + mapOf(y to 2u) to Rational(-35327, 126), + mapOf(x to 1u, y to 2u) to Rational(53, 252), + mapOf(x to 2u, y to 2u) to Rational(849197, 6048), + mapOf(x to 3u, y to 2u) to Rational(22361, 252), + mapOf(x to 4u, y to 2u) to Rational(773, 42), + mapOf(y to 3u) to Rational(-6067, 21), + mapOf(x to 1u, y to 3u) to Rational(39049, 126), + mapOf(x to 2u, y to 3u) to Rational(80303, 1008), + mapOf(x to 3u, y to 3u) to Rational(-3035, 63), + mapOf(x to 4u, y to 3u) to Rational(-209, 21), + mapOf(y to 4u) to Rational(3113, 21), + mapOf(x to 1u, y to 4u) to Rational(-22345, 126), + mapOf(x to 2u, y to 4u) to Rational(-30931, 1008), + mapOf(x to 3u, y to 4u) to Rational(5837, 126), + mapOf(x to 4u, y to 4u) to Rational(229, 21), + mapOf(y to 5u) to Rational(-2120, 21), + mapOf(x to 1u, y to 5u) to Rational(451, 7), + mapOf(x to 2u, y to 5u) to Rational(422, 21), + mapOf(x to 3u, y to 5u) to Rational(-181, 21), + mapOf(x to 4u, y to 5u) to Rational(-40, 21), + mapOf(y to 6u) to Rational(100, 3), + mapOf(x to 1u, y to 6u) to Rational(-80, 3), + mapOf(x to 2u, y to 6u) to Rational(-8, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 3), + mapOf(x to 4u, y to 6u) to Rational(4, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + )), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-409, 6), + mapOf(x to 1u) to Rational(-376, 9), + mapOf(x to 2u) to Rational(-1781, 81), + mapOf(x to 3u) to Rational(-128, 27), + mapOf(x to 4u) to Rational(-8, 9), + mapOf(y to 1u) to Rational(18701, 210), + mapOf(x to 1u, y to 1u) to Rational(614183, 7560), + mapOf(x to 2u, y to 1u) to Rational(90941, 1890), + mapOf(x to 3u, y to 1u) to Rational(1802, 135), + mapOf(x to 4u, y to 1u) to Rational(112, 45), + mapOf(y to 2u) to Rational(181421, 315), + mapOf(x to 1u, y to 2u) to Rational(77813, 378), + mapOf(x to 2u, y to 2u) to Rational(598583, 7560), + mapOf(x to 3u, y to 2u) to Rational(85, 27), + mapOf(x to 4u, y to 2u) to Rational(2, 5), + mapOf(y to 3u) to Rational(130997, 315), + mapOf(x to 1u, y to 3u) to Rational(1093, 420), + mapOf(x to 2u, y to 3u) to Rational(9551, 2520), + mapOf(x to 3u, y to 3u) to Rational(-14, 45), + mapOf(x to 4u, y to 3u) to Rational(22, 45), + mapOf(y to 4u) to Rational(-2801, 9), + mapOf(x to 1u, y to 4u) to Rational(4033, 90), + mapOf(x to 2u, y to 4u) to Rational(6429, 80), + mapOf(x to 3u, y to 4u) to Rational(2851, 90), + mapOf(x to 4u, y to 4u) to Rational(293, 45), + mapOf(y to 5u) to Rational(-220, 1), + mapOf(x to 1u, y to 5u) to Rational(127, 1), + mapOf(x to 2u, y to 5u) to Rational(202, 5), + mapOf(x to 3u, y to 5u) to Rational(-63, 5), + mapOf(x to 4u, y to 5u) to Rational(-12, 5), + mapOf(y to 6u) to Rational(100, 1), + mapOf(x to 1u, y to 6u) to Rational(-80, 1), + mapOf(x to 2u, y to 6u) to Rational(-24, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 1), + mapOf(x to 4u, y to 6u) to Rational(4, 1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5407, 9), + mapOf(x to 1u) to Rational(9568, 27), + mapOf(x to 2u) to Rational(4996, 27), + mapOf(x to 3u) to Rational(352, 9), + mapOf(x to 4u) to Rational(22, 3), + mapOf(y to 1u) to Rational(104411, 126), + mapOf(x to 1u, y to 1u) to Rational(6001, 126), + mapOf(x to 2u, y to 1u) to Rational(-796, 21), + mapOf(x to 3u, y to 1u) to Rational(-5389, 126), + mapOf(x to 4u, y to 1u) to Rational(-166, 21), + mapOf(y to 2u) to Rational(-35327, 126), + mapOf(x to 1u, y to 2u) to Rational(53, 252), + mapOf(x to 2u, y to 2u) to Rational(849197, 6048), + mapOf(x to 3u, y to 2u) to Rational(22361, 252), + mapOf(x to 4u, y to 2u) to Rational(773, 42), + mapOf(y to 3u) to Rational(-6067, 21), + mapOf(x to 1u, y to 3u) to Rational(39049, 126), + mapOf(x to 2u, y to 3u) to Rational(80303, 1008), + mapOf(x to 3u, y to 3u) to Rational(-3035, 63), + mapOf(x to 4u, y to 3u) to Rational(-209, 21), + mapOf(y to 4u) to Rational(3113, 21), + mapOf(x to 1u, y to 4u) to Rational(-22345, 126), + mapOf(x to 2u, y to 4u) to Rational(-30931, 1008), + mapOf(x to 3u, y to 4u) to Rational(5837, 126), + mapOf(x to 4u, y to 4u) to Rational(229, 21), + mapOf(y to 5u) to Rational(-2120, 21), + mapOf(x to 1u, y to 5u) to Rational(451, 7), + mapOf(x to 2u, y to 5u) to Rational(422, 21), + mapOf(x to 3u, y to 5u) to Rational(-181, 21), + mapOf(x to 4u, y to 5u) to Rational(-40, 21), + mapOf(y to 6u) to Rational(100, 3), + mapOf(x to 1u, y to 6u) to Rational(-80, 3), + mapOf(x to 2u, y to 6u) to Rational(-8, 1), + mapOf(x to 3u, y to 6u) to Rational(16, 3), + mapOf(x to 4u, y to 6u) to Rational(4, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + x to LabeledPolynomialAsIs( + mapOf() to Rational(18, 1), + mapOf(x to 1u) to Rational(16, 3), + mapOf(x to 2u) to Rational(12, 6), + mapOf(y to 1u) to Rational(13, 1), + mapOf(x to 1u, y to 1u) to Rational(-11, 4), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(-10, 1), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 5'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 6), + mapOf(x to 1u) to Rational(1, 6), + mapOf(x to 2u) to Rational(-2, 9), + mapOf(y to 1u) to Rational(15, 1), + mapOf(x to 1u, y to 1u) to Rational(18, 7), + mapOf(x to 2u, y to 1u) to Rational(2, 5), + mapOf(y to 2u) to Rational(12, 9), + mapOf(x to 1u, y to 2u) to Rational(-3, 5), + mapOf(x to 2u, y to 2u) to Rational(4, 4), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-11, 9), + mapOf(x to 1u) to Rational(4, 9), + mapOf(x to 2u) to Rational(11, 6), + mapOf(y to 1u) to Rational(-5, 6), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(-1, 7), + mapOf(y to 2u) to Rational(9, 1), + mapOf(x to 1u, y to 2u) to Rational(6, 7), + mapOf(x to 2u, y to 2u) to Rational(1, 3), + ) + ).substitute(RationalField, mapOf( + iota to LabeledPolynomialAsIs( + mapOf() to Rational(-6, 1), + mapOf(x to 1u) to Rational(-9, 8), + mapOf(x to 2u) to Rational(17, 5), + mapOf(y to 1u) to Rational(-2, 3), + mapOf(x to 1u, y to 1u) to Rational(1, 5), + mapOf(x to 2u, y to 1u) to Rational(-11, 7), + mapOf(y to 2u) to Rational(13, 6), + mapOf(x to 1u, y to 2u) to Rational(-15, 2), + mapOf(x to 2u, y to 2u) to Rational(-14, 4), + ) + )), + "test 6'" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction_Map() { + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(0) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ), + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1) + ) + ) + )), + "test 1" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(-17166109, 793800), + mapOf(x to 3u, y to 1u) to Rational(-930960143, 5556600), + mapOf(x to 2u, y to 2u) to Rational(-144665109691, 350065800), + mapOf(x to 1u, y to 3u) to Rational(-17232577, 52920), + mapOf(y to 4u) to Rational(-68141, 1323), + ), + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(-57522533, 14288400), + mapOf(x to 3u, y to 1u) to Rational(-13085162953, 300056400), + mapOf(x to 2u, y to 2u) to Rational(-92093367341, 525098700), + mapOf(x to 1u, y to 3u) to Rational(-1979342797, 6667920), + mapOf(y to 4u) to Rational(-3082727, 21168), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(11, 5), + mapOf(y to 1u) to Rational(8, 4), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1, 9), + mapOf(y to 1u) to Rational(11, 7), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-2, 7), + mapOf(y to 1u) to Rational(-4, 3), + ), + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(3, 6), + mapOf(y to 1u) to Rational(12, 8), + ) + ), + )), + "test 2" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-130778291, 76800), + mapOf(x to 1u) to Rational(-445270919, 230400), + mapOf(x to 2u) to Rational(44578444937, 14515200), + mapOf(x to 3u) to Rational(17329402153, 1555200), + mapOf(x to 4u) to Rational(89239926809, 2332800), + mapOf(x to 5u) to Rational(2808812267, 145152), + mapOf(x to 6u) to Rational(-21362661007, 725760), + mapOf(x to 7u) to Rational(-258455443, 2016), + mapOf(x to 8u) to Rational(-21454693, 96), + mapOf(y to 1u) to Rational(-1002137, 15360), + mapOf(x to 1u, y to 1u) to Rational(-1704849697, 430080), + mapOf(x to 2u, y to 1u) to Rational(-57657676789, 4838400), + mapOf(x to 3u, y to 1u) to Rational(-101331731, 89600), + mapOf(x to 4u, y to 1u) to Rational(5362280079329, 130636800), + mapOf(x to 5u, y to 1u) to Rational(4069896167053, 130636800), + mapOf(x to 6u, y to 1u) to Rational(12011514569, 544320), + mapOf(x to 7u, y to 1u) to Rational(138293195623, 725760), + mapOf(x to 8u, y to 1u) to Rational(6228779419, 48384), + mapOf(y to 2u) to Rational(-32395872823, 8064000), + mapOf(x to 1u, y to 2u) to Rational(-7398505523, 2304000), + mapOf(x to 2u, y to 2u) to Rational(95217051699521, 3048192000), + mapOf(x to 3u, y to 2u) to Rational(198026968812079, 3657830400), + mapOf(x to 4u, y to 2u) to Rational(4291645618499, 228614400), + mapOf(x to 5u, y to 2u) to Rational(-33211690942439, 914457600), + mapOf(x to 6u, y to 2u) to Rational(-637385538163153, 1371686400), + mapOf(x to 7u, y to 2u) to Rational(-138671528276273, 182891520), + mapOf(x to 8u, y to 2u) to Rational(-14566368751, 217728), + mapOf(y to 3u) to Rational(-10538718719, 2016000), + mapOf(x to 1u, y to 3u) to Rational(-1844485375199, 84672000), + mapOf(x to 2u, y to 3u) to Rational(103968665891, 12096000), + mapOf(x to 3u, y to 3u) to Rational(175402107278351, 1828915200), + mapOf(x to 4u, y to 3u) to Rational(8020699588879, 114307200), + mapOf(x to 5u, y to 3u) to Rational(3414841894991, 38102400), + mapOf(x to 6u, y to 3u) to Rational(1848405591611, 4665600), + mapOf(x to 7u, y to 3u) to Rational(39486708738989, 137168640), + mapOf(x to 8u, y to 3u) to Rational(255926289517, 9144576), + mapOf(y to 4u) to Rational(-655379564629, 105840000), + mapOf(x to 1u, y to 4u) to Rational(-208336039441, 127008000), + mapOf(x to 2u, y to 4u) to Rational(40173146771411, 1143072000), + mapOf(x to 3u, y to 4u) to Rational(150473493581239, 2667168000), + mapOf(x to 4u, y to 4u) to Rational(38833783990483, 1143072000), + mapOf(x to 5u, y to 4u) to Rational(-1963676248203053, 4800902400), + mapOf(x to 6u, y to 4u) to Rational(-2598759412825747, 3200601600), + mapOf(x to 7u, y to 4u) to Rational(-192895352019667, 1280240640), + mapOf(x to 8u, y to 4u) to Rational(3737382679, 6858432), + mapOf(y to 5u) to Rational(-16959378721, 1890000), + mapOf(x to 1u, y to 5u) to Rational(-1864802244743, 79380000), + mapOf(x to 2u, y to 5u) to Rational(13449261536489, 666792000), + mapOf(x to 3u, y to 5u) to Rational(215272234137329, 2667168000), + mapOf(x to 4u, y to 5u) to Rational(6040691379277, 83349000), + mapOf(x to 5u, y to 5u) to Rational(153687143525887, 800150400), + mapOf(x to 6u, y to 5u) to Rational(475602854903563, 2400451200), + mapOf(x to 7u, y to 5u) to Rational(27315599358749, 640120320), + mapOf(x to 8u, y to 5u) to Rational(-2630413357, 10668672), + mapOf(y to 6u) to Rational(-6654999511, 2646000), + mapOf(x to 1u, y to 6u) to Rational(-67885252327, 15876000), + mapOf(x to 2u, y to 6u) to Rational(5786776220983, 2667168000), + mapOf(x to 3u, y to 6u) to Rational(60615922629083, 1143072000), + mapOf(x to 4u, y to 6u) to Rational(-34703539637627407, 672126336000), + mapOf(x to 5u, y to 6u) to Rational(-744694192134101, 2240421120), + mapOf(x to 6u, y to 6u) to Rational(-1782470617231, 14817600), + mapOf(x to 7u, y to 6u) to Rational(59123208433, 8890560), + mapOf(x to 8u, y to 6u) to Rational(-141653, 5292), + mapOf(y to 7u) to Rational(-338051969, 441000), + mapOf(x to 1u, y to 7u) to Rational(468850013, 1764000), + mapOf(x to 2u, y to 7u) to Rational(2102343426101, 222264000), + mapOf(x to 3u, y to 7u) to Rational(7836130602007, 1333584000), + mapOf(x to 4u, y to 7u) to Rational(16239111865997, 746807040), + mapOf(x to 5u, y to 7u) to Rational(3824649185383, 88905600), + mapOf(x to 6u, y to 7u) to Rational(56058614459, 3457440), + mapOf(x to 7u, y to 7u) to Rational(-396766339, 493920), + mapOf(x to 8u, y to 7u) to Rational(-165147, 2744), + mapOf(y to 8u) to Rational(-3088619, 58800), + mapOf(x to 1u, y to 8u) to Rational(155343347, 88200), + mapOf(x to 2u, y to 8u) to Rational(100098736469, 7408800), + mapOf(x to 3u, y to 8u) to Rational(109725511381, 7408800), + mapOf(x to 4u, y to 8u) to Rational(-2431199641013, 59270400), + mapOf(x to 5u, y to 8u) to Rational(-102872383249, 3457440), + mapOf(x to 6u, y to 8u) to Rational(1449461309, 576240), + mapOf(x to 7u, y to 8u) to Rational(812775, 1372), + mapOf(x to 8u, y to 8u) to Rational(-16461, 343) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(164202773, 230400), + mapOf(x to 1u) to Rational(-70345303, 518400), + mapOf(x to 2u) to Rational(-4229702731, 4665600), + mapOf(x to 3u) to Rational(3262171027, 6998400), + mapOf(x to 4u) to Rational(-25423104169, 13996800), + mapOf(x to 5u) to Rational(64061869, 349920), + mapOf(x to 6u) to Rational(-1655878091, 116640), + mapOf(x to 7u) to Rational(-7991441, 648), + mapOf(x to 8u) to Rational(-502591, 18), + mapOf(y to 1u) to Rational(-8780429, 3840), + mapOf(x to 1u, y to 1u) to Rational(434272361, 115200), + mapOf(x to 2u, y to 1u) to Rational(429825727, 41472), + mapOf(x to 3u, y to 1u) to Rational(-10066790339, 6998400), + mapOf(x to 4u, y to 1u) to Rational(70022035471, 20995200), + mapOf(x to 5u, y to 1u) to Rational(-32070283493, 1399680), + mapOf(x to 6u, y to 1u) to Rational(-22051101001, 1399680), + mapOf(x to 7u, y to 1u) to Rational(-126493427, 12960), + mapOf(x to 8u, y to 1u) to Rational(3050245, 864), + mapOf(y to 2u) to Rational(-1194654631, 345600), + mapOf(x to 1u, y to 2u) to Rational(-542961452671, 31104000), + mapOf(x to 2u, y to 2u) to Rational(-234000873607, 48988800), + mapOf(x to 3u, y to 2u) to Rational(140520538087, 3628800), + mapOf(x to 4u, y to 2u) to Rational(9215088876563, 130636800), + mapOf(x to 5u, y to 2u) to Rational(27590569647253, 293932800), + mapOf(x to 6u, y to 2u) to Rational(5129057792891, 97977600), + mapOf(x to 7u, y to 2u) to Rational(-106334191, 5103), + mapOf(x to 8u, y to 2u) to Rational(-1024113911, 435456), + mapOf(y to 3u) to Rational(76223843, 6000), + mapOf(x to 1u, y to 3u) to Rational(57425857357, 2592000), + mapOf(x to 2u, y to 3u) to Rational(-2044736497573, 46656000), + mapOf(x to 3u, y to 3u) to Rational(-26155810120031, 293932800), + mapOf(x to 4u, y to 3u) to Rational(-1064419459813, 6998400), + mapOf(x to 5u, y to 3u) to Rational(-753782018389, 4082400), + mapOf(x to 6u, y to 3u) to Rational(-291973360873, 2799360), + mapOf(x to 7u, y to 3u) to Rational(-46372122599, 816480), + mapOf(x to 8u, y to 3u) to Rational(3579859657, 653184), + mapOf(y to 4u) to Rational(-13374241901, 4320000), + mapOf(x to 1u, y to 4u) to Rational(306606499811, 54432000), + mapOf(x to 2u, y to 4u) to Rational(964267124745437, 13716864000), + mapOf(x to 3u, y to 4u) to Rational(21603809415373, 182891520), + mapOf(x to 4u, y to 4u) to Rational(1097860214654027, 6858432000), + mapOf(x to 5u, y to 4u) to Rational(161615254570669, 914457600), + mapOf(x to 6u, y to 4u) to Rational(758415239461, 22861440), + mapOf(x to 7u, y to 4u) to Rational(2585568355471, 274337280), + mapOf(x to 8u, y to 4u) to Rational(-70433747863, 9144576), + mapOf(y to 5u) to Rational(-9582586217, 2520000), + mapOf(x to 1u, y to 5u) to Rational(-19093471394171, 635040000), + mapOf(x to 2u, y to 5u) to Rational(-13010261944411, 381024000), + mapOf(x to 3u, y to 5u) to Rational(-259039825301861, 4572288000), + mapOf(x to 4u, y to 5u) to Rational(-305081119071079, 2286144000), + mapOf(x to 5u, y to 5u) to Rational(-1923114383311, 19595520), + mapOf(x to 6u, y to 5u) to Rational(-14181787253231, 228614400), + mapOf(x to 7u, y to 5u) to Rational(-3959584789, 4354560), + mapOf(x to 8u, y to 5u) to Rational(4691742523, 762048), + mapOf(y to 6u) to Rational(-588323437, 180000), + mapOf(x to 1u, y to 6u) to Rational(5952234691, 52920000), + mapOf(x to 2u, y to 6u) to Rational(21001851056959, 1088640000), + mapOf(x to 3u, y to 6u) to Rational(84668034357563, 2133734400), + mapOf(x to 4u, y to 6u) to Rational(2029754605811557, 25604812800), + mapOf(x to 5u, y to 6u) to Rational(11721216739823, 426746880), + mapOf(x to 6u, y to 6u) to Rational(-8275903187003, 2133734400), + mapOf(x to 7u, y to 6u) to Rational(-4730447299, 2540160), + mapOf(x to 8u, y to 6u) to Rational(-46069985, 21168), + mapOf(y to 7u) to Rational(-75711301, 117600), + mapOf(x to 1u, y to 7u) to Rational(32430417413, 7056000), + mapOf(x to 2u, y to 7u) to Rational(677988533153, 98784000), + mapOf(x to 3u, y to 7u) to Rational(-948417645827, 71124480), + mapOf(x to 4u, y to 7u) to Rational(-11320265215207, 711244800), + mapOf(x to 5u, y to 7u) to Rational(-676438627783, 50803200), + mapOf(x to 6u, y to 7u) to Rational(-7382274253, 1975680), + mapOf(x to 7u, y to 7u) to Rational(6505733, 2205), + mapOf(x to 8u, y to 7u) to Rational(450137, 882), + mapOf(y to 8u) to Rational(-8368253, 78400), + mapOf(x to 1u, y to 8u) to Rational(6833783, 117600), + mapOf(x to 2u, y to 8u) to Rational(4528971133, 5927040), + mapOf(x to 3u, y to 8u) to Rational(146252636617, 29635200), + mapOf(x to 4u, y to 8u) to Rational(8321882556889, 1659571200), + mapOf(x to 5u, y to 8u) to Rational(-4686033011, 1975680), + mapOf(x to 6u, y to 8u) to Rational(-1074445963, 987840), + mapOf(x to 7u, y to 8u) to Rational(-142313, 588), + mapOf(x to 8u, y to 8u) to Rational(-4281, 49) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + )), + "test 3" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-130778291, 76800), + mapOf(x to 1u) to Rational(-445270919, 230400), + mapOf(x to 2u) to Rational(44578444937, 14515200), + mapOf(x to 3u) to Rational(17329402153, 1555200), + mapOf(x to 4u) to Rational(89239926809, 2332800), + mapOf(x to 5u) to Rational(2808812267, 145152), + mapOf(x to 6u) to Rational(-21362661007, 725760), + mapOf(x to 7u) to Rational(-258455443, 2016), + mapOf(x to 8u) to Rational(-21454693, 96), + mapOf(y to 1u) to Rational(-1002137, 15360), + mapOf(x to 1u, y to 1u) to Rational(-1704849697, 430080), + mapOf(x to 2u, y to 1u) to Rational(-57657676789, 4838400), + mapOf(x to 3u, y to 1u) to Rational(-101331731, 89600), + mapOf(x to 4u, y to 1u) to Rational(5362280079329, 130636800), + mapOf(x to 5u, y to 1u) to Rational(4069896167053, 130636800), + mapOf(x to 6u, y to 1u) to Rational(12011514569, 544320), + mapOf(x to 7u, y to 1u) to Rational(138293195623, 725760), + mapOf(x to 8u, y to 1u) to Rational(6228779419, 48384), + mapOf(y to 2u) to Rational(-32395872823, 8064000), + mapOf(x to 1u, y to 2u) to Rational(-7398505523, 2304000), + mapOf(x to 2u, y to 2u) to Rational(95217051699521, 3048192000), + mapOf(x to 3u, y to 2u) to Rational(198026968812079, 3657830400), + mapOf(x to 4u, y to 2u) to Rational(4291645618499, 228614400), + mapOf(x to 5u, y to 2u) to Rational(-33211690942439, 914457600), + mapOf(x to 6u, y to 2u) to Rational(-637385538163153, 1371686400), + mapOf(x to 7u, y to 2u) to Rational(-138671528276273, 182891520), + mapOf(x to 8u, y to 2u) to Rational(-14566368751, 217728), + mapOf(y to 3u) to Rational(-10538718719, 2016000), + mapOf(x to 1u, y to 3u) to Rational(-1844485375199, 84672000), + mapOf(x to 2u, y to 3u) to Rational(103968665891, 12096000), + mapOf(x to 3u, y to 3u) to Rational(175402107278351, 1828915200), + mapOf(x to 4u, y to 3u) to Rational(8020699588879, 114307200), + mapOf(x to 5u, y to 3u) to Rational(3414841894991, 38102400), + mapOf(x to 6u, y to 3u) to Rational(1848405591611, 4665600), + mapOf(x to 7u, y to 3u) to Rational(39486708738989, 137168640), + mapOf(x to 8u, y to 3u) to Rational(255926289517, 9144576), + mapOf(y to 4u) to Rational(-655379564629, 105840000), + mapOf(x to 1u, y to 4u) to Rational(-208336039441, 127008000), + mapOf(x to 2u, y to 4u) to Rational(40173146771411, 1143072000), + mapOf(x to 3u, y to 4u) to Rational(150473493581239, 2667168000), + mapOf(x to 4u, y to 4u) to Rational(38833783990483, 1143072000), + mapOf(x to 5u, y to 4u) to Rational(-1963676248203053, 4800902400), + mapOf(x to 6u, y to 4u) to Rational(-2598759412825747, 3200601600), + mapOf(x to 7u, y to 4u) to Rational(-192895352019667, 1280240640), + mapOf(x to 8u, y to 4u) to Rational(3737382679, 6858432), + mapOf(y to 5u) to Rational(-16959378721, 1890000), + mapOf(x to 1u, y to 5u) to Rational(-1864802244743, 79380000), + mapOf(x to 2u, y to 5u) to Rational(13449261536489, 666792000), + mapOf(x to 3u, y to 5u) to Rational(215272234137329, 2667168000), + mapOf(x to 4u, y to 5u) to Rational(6040691379277, 83349000), + mapOf(x to 5u, y to 5u) to Rational(153687143525887, 800150400), + mapOf(x to 6u, y to 5u) to Rational(475602854903563, 2400451200), + mapOf(x to 7u, y to 5u) to Rational(27315599358749, 640120320), + mapOf(x to 8u, y to 5u) to Rational(-2630413357, 10668672), + mapOf(y to 6u) to Rational(-6654999511, 2646000), + mapOf(x to 1u, y to 6u) to Rational(-67885252327, 15876000), + mapOf(x to 2u, y to 6u) to Rational(5786776220983, 2667168000), + mapOf(x to 3u, y to 6u) to Rational(60615922629083, 1143072000), + mapOf(x to 4u, y to 6u) to Rational(-34703539637627407, 672126336000), + mapOf(x to 5u, y to 6u) to Rational(-744694192134101, 2240421120), + mapOf(x to 6u, y to 6u) to Rational(-1782470617231, 14817600), + mapOf(x to 7u, y to 6u) to Rational(59123208433, 8890560), + mapOf(x to 8u, y to 6u) to Rational(-141653, 5292), + mapOf(y to 7u) to Rational(-338051969, 441000), + mapOf(x to 1u, y to 7u) to Rational(468850013, 1764000), + mapOf(x to 2u, y to 7u) to Rational(2102343426101, 222264000), + mapOf(x to 3u, y to 7u) to Rational(7836130602007, 1333584000), + mapOf(x to 4u, y to 7u) to Rational(16239111865997, 746807040), + mapOf(x to 5u, y to 7u) to Rational(3824649185383, 88905600), + mapOf(x to 6u, y to 7u) to Rational(56058614459, 3457440), + mapOf(x to 7u, y to 7u) to Rational(-396766339, 493920), + mapOf(x to 8u, y to 7u) to Rational(-165147, 2744), + mapOf(y to 8u) to Rational(-3088619, 58800), + mapOf(x to 1u, y to 8u) to Rational(155343347, 88200), + mapOf(x to 2u, y to 8u) to Rational(100098736469, 7408800), + mapOf(x to 3u, y to 8u) to Rational(109725511381, 7408800), + mapOf(x to 4u, y to 8u) to Rational(-2431199641013, 59270400), + mapOf(x to 5u, y to 8u) to Rational(-102872383249, 3457440), + mapOf(x to 6u, y to 8u) to Rational(1449461309, 576240), + mapOf(x to 7u, y to 8u) to Rational(812775, 1372), + mapOf(x to 8u, y to 8u) to Rational(-16461, 343) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(164202773, 230400), + mapOf(x to 1u) to Rational(-70345303, 518400), + mapOf(x to 2u) to Rational(-4229702731, 4665600), + mapOf(x to 3u) to Rational(3262171027, 6998400), + mapOf(x to 4u) to Rational(-25423104169, 13996800), + mapOf(x to 5u) to Rational(64061869, 349920), + mapOf(x to 6u) to Rational(-1655878091, 116640), + mapOf(x to 7u) to Rational(-7991441, 648), + mapOf(x to 8u) to Rational(-502591, 18), + mapOf(y to 1u) to Rational(-8780429, 3840), + mapOf(x to 1u, y to 1u) to Rational(434272361, 115200), + mapOf(x to 2u, y to 1u) to Rational(429825727, 41472), + mapOf(x to 3u, y to 1u) to Rational(-10066790339, 6998400), + mapOf(x to 4u, y to 1u) to Rational(70022035471, 20995200), + mapOf(x to 5u, y to 1u) to Rational(-32070283493, 1399680), + mapOf(x to 6u, y to 1u) to Rational(-22051101001, 1399680), + mapOf(x to 7u, y to 1u) to Rational(-126493427, 12960), + mapOf(x to 8u, y to 1u) to Rational(3050245, 864), + mapOf(y to 2u) to Rational(-1194654631, 345600), + mapOf(x to 1u, y to 2u) to Rational(-542961452671, 31104000), + mapOf(x to 2u, y to 2u) to Rational(-234000873607, 48988800), + mapOf(x to 3u, y to 2u) to Rational(140520538087, 3628800), + mapOf(x to 4u, y to 2u) to Rational(9215088876563, 130636800), + mapOf(x to 5u, y to 2u) to Rational(27590569647253, 293932800), + mapOf(x to 6u, y to 2u) to Rational(5129057792891, 97977600), + mapOf(x to 7u, y to 2u) to Rational(-106334191, 5103), + mapOf(x to 8u, y to 2u) to Rational(-1024113911, 435456), + mapOf(y to 3u) to Rational(76223843, 6000), + mapOf(x to 1u, y to 3u) to Rational(57425857357, 2592000), + mapOf(x to 2u, y to 3u) to Rational(-2044736497573, 46656000), + mapOf(x to 3u, y to 3u) to Rational(-26155810120031, 293932800), + mapOf(x to 4u, y to 3u) to Rational(-1064419459813, 6998400), + mapOf(x to 5u, y to 3u) to Rational(-753782018389, 4082400), + mapOf(x to 6u, y to 3u) to Rational(-291973360873, 2799360), + mapOf(x to 7u, y to 3u) to Rational(-46372122599, 816480), + mapOf(x to 8u, y to 3u) to Rational(3579859657, 653184), + mapOf(y to 4u) to Rational(-13374241901, 4320000), + mapOf(x to 1u, y to 4u) to Rational(306606499811, 54432000), + mapOf(x to 2u, y to 4u) to Rational(964267124745437, 13716864000), + mapOf(x to 3u, y to 4u) to Rational(21603809415373, 182891520), + mapOf(x to 4u, y to 4u) to Rational(1097860214654027, 6858432000), + mapOf(x to 5u, y to 4u) to Rational(161615254570669, 914457600), + mapOf(x to 6u, y to 4u) to Rational(758415239461, 22861440), + mapOf(x to 7u, y to 4u) to Rational(2585568355471, 274337280), + mapOf(x to 8u, y to 4u) to Rational(-70433747863, 9144576), + mapOf(y to 5u) to Rational(-9582586217, 2520000), + mapOf(x to 1u, y to 5u) to Rational(-19093471394171, 635040000), + mapOf(x to 2u, y to 5u) to Rational(-13010261944411, 381024000), + mapOf(x to 3u, y to 5u) to Rational(-259039825301861, 4572288000), + mapOf(x to 4u, y to 5u) to Rational(-305081119071079, 2286144000), + mapOf(x to 5u, y to 5u) to Rational(-1923114383311, 19595520), + mapOf(x to 6u, y to 5u) to Rational(-14181787253231, 228614400), + mapOf(x to 7u, y to 5u) to Rational(-3959584789, 4354560), + mapOf(x to 8u, y to 5u) to Rational(4691742523, 762048), + mapOf(y to 6u) to Rational(-588323437, 180000), + mapOf(x to 1u, y to 6u) to Rational(5952234691, 52920000), + mapOf(x to 2u, y to 6u) to Rational(21001851056959, 1088640000), + mapOf(x to 3u, y to 6u) to Rational(84668034357563, 2133734400), + mapOf(x to 4u, y to 6u) to Rational(2029754605811557, 25604812800), + mapOf(x to 5u, y to 6u) to Rational(11721216739823, 426746880), + mapOf(x to 6u, y to 6u) to Rational(-8275903187003, 2133734400), + mapOf(x to 7u, y to 6u) to Rational(-4730447299, 2540160), + mapOf(x to 8u, y to 6u) to Rational(-46069985, 21168), + mapOf(y to 7u) to Rational(-75711301, 117600), + mapOf(x to 1u, y to 7u) to Rational(32430417413, 7056000), + mapOf(x to 2u, y to 7u) to Rational(677988533153, 98784000), + mapOf(x to 3u, y to 7u) to Rational(-948417645827, 71124480), + mapOf(x to 4u, y to 7u) to Rational(-11320265215207, 711244800), + mapOf(x to 5u, y to 7u) to Rational(-676438627783, 50803200), + mapOf(x to 6u, y to 7u) to Rational(-7382274253, 1975680), + mapOf(x to 7u, y to 7u) to Rational(6505733, 2205), + mapOf(x to 8u, y to 7u) to Rational(450137, 882), + mapOf(y to 8u) to Rational(-8368253, 78400), + mapOf(x to 1u, y to 8u) to Rational(6833783, 117600), + mapOf(x to 2u, y to 8u) to Rational(4528971133, 5927040), + mapOf(x to 3u, y to 8u) to Rational(146252636617, 29635200), + mapOf(x to 4u, y to 8u) to Rational(8321882556889, 1659571200), + mapOf(x to 5u, y to 8u) to Rational(-4686033011, 1975680), + mapOf(x to 6u, y to 8u) to Rational(-1074445963, 987840), + mapOf(x to 7u, y to 8u) to Rational(-142313, 588), + mapOf(x to 8u, y to 8u) to Rational(-4281, 49) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 3'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(2303, 64), + mapOf(x to 1u) to Rational(31843, 192), + mapOf(x to 2u) to Rational(118891, 576), + mapOf(x to 3u) to Rational(94453, 168), + mapOf(x to 4u) to Rational(-179203, 1512), + mapOf(x to 5u) to Rational(-16979, 126), + mapOf(x to 6u) to Rational(-13499, 12), + mapOf(y to 1u) to Rational(-4767, 64), + mapOf(x to 1u, y to 1u) to Rational(-58689, 256), + mapOf(x to 2u, y to 1u) to Rational(-757333, 4032), + mapOf(x to 3u, y to 1u) to Rational(-4921205, 4032), + mapOf(x to 4u, y to 1u) to Rational(-2930815, 4032), + mapOf(x to 5u, y to 1u) to Rational(-398803, 1512), + mapOf(x to 6u, y to 1u) to Rational(18835, 36), + mapOf(y to 2u) to Rational(224101, 960), + mapOf(x to 1u, y to 2u) to Rational(9139699, 40320), + mapOf(x to 2u, y to 2u) to Rational(3848803, 5760), + mapOf(x to 3u, y to 2u) to Rational(93102371, 241920), + mapOf(x to 4u, y to 2u) to Rational(-65821229, 141120), + mapOf(x to 5u, y to 2u) to Rational(-15675899, 7056), + mapOf(x to 6u, y to 2u) to Rational(10459, 189), + mapOf(y to 3u) to Rational(2411, 16), + mapOf(x to 1u, y to 3u) to Rational(1294543, 10080), + mapOf(x to 2u, y to 3u) to Rational(-1740199, 1440), + mapOf(x to 3u, y to 3u) to Rational(-266994841, 282240), + mapOf(x to 4u, y to 3u) to Rational(-41261893, 211680), + mapOf(x to 5u, y to 3u) to Rational(1717357, 3528), + mapOf(x to 6u, y to 3u) to Rational(69, 14), + mapOf(y to 4u) to Rational(13231, 360), + mapOf(x to 1u, y to 4u) to Rational(4858831, 25200), + mapOf(x to 2u, y to 4u) to Rational(15565759, 75600), + mapOf(x to 3u, y to 4u) to Rational(-15583391, 35280), + mapOf(x to 4u, y to 4u) to Rational(-13345747, 11760), + mapOf(x to 5u, y to 4u) to Rational(140103, 686), + mapOf(x to 6u, y to 4u) to Rational(-765, 49) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(31409, 576), + mapOf(x to 1u) to Rational(-337099, 1728), + mapOf(x to 2u) to Rational(-211429, 1728), + mapOf(x to 3u) to Rational(-259241, 432), + mapOf(x to 4u) to Rational(-13777, 36), + mapOf(x to 5u) to Rational(-41389, 72), + mapOf(x to 6u) to Rational(-7679, 48), + mapOf(y to 1u) to Rational(-3269, 12), + mapOf(x to 1u, y to 1u) to Rational(629569, 864), + mapOf(x to 2u, y to 1u) to Rational(53867, 324), + mapOf(x to 3u, y to 1u) to Rational(2290577, 1728), + mapOf(x to 4u, y to 1u) to Rational(101507, 216), + mapOf(x to 5u, y to 1u) to Rational(213109, 288), + mapOf(x to 6u, y to 1u) to Rational(17927, 144), + mapOf(y to 2u) to Rational(314587, 1080), + mapOf(x to 1u, y to 2u) to Rational(-109771, 144), + mapOf(x to 2u, y to 2u) to Rational(-6469, 16), + mapOf(x to 3u, y to 2u) to Rational(-298291681, 181440), + mapOf(x to 4u, y to 2u) to Rational(-59147357, 48384), + mapOf(x to 5u, y to 2u) to Rational(-4982365, 6048), + mapOf(x to 6u, y to 2u) to Rational(-18727, 576), + mapOf(y to 3u) to Rational(12379, 90), + mapOf(x to 1u, y to 3u) to Rational(-542911, 1620), + mapOf(x to 2u, y to 3u) to Rational(143123, 1260), + mapOf(x to 3u, y to 3u) to Rational(9859177, 30240), + mapOf(x to 4u, y to 3u) to Rational(9312529, 20160), + mapOf(x to 5u, y to 3u) to Rational(207001, 672), + mapOf(x to 6u, y to 3u) to Rational(203, 24), + mapOf(y to 4u) to Rational(9442, 675), + mapOf(x to 1u, y to 4u) to Rational(-13729, 300), + mapOf(x to 2u, y to 4u) to Rational(-3490471, 25200), + mapOf(x to 3u, y to 4u) to Rational(-333031, 840), + mapOf(x to 4u, y to 4u) to Rational(-7572211, 47040), + mapOf(x to 5u, y to 4u) to Rational(-1189, 56), + mapOf(x to 6u, y to 4u) to Rational(-405, 196) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + )), + "test 4" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(2303, 64), + mapOf(x to 1u) to Rational(31843, 192), + mapOf(x to 2u) to Rational(118891, 576), + mapOf(x to 3u) to Rational(94453, 168), + mapOf(x to 4u) to Rational(-179203, 1512), + mapOf(x to 5u) to Rational(-16979, 126), + mapOf(x to 6u) to Rational(-13499, 12), + mapOf(y to 1u) to Rational(-4767, 64), + mapOf(x to 1u, y to 1u) to Rational(-58689, 256), + mapOf(x to 2u, y to 1u) to Rational(-757333, 4032), + mapOf(x to 3u, y to 1u) to Rational(-4921205, 4032), + mapOf(x to 4u, y to 1u) to Rational(-2930815, 4032), + mapOf(x to 5u, y to 1u) to Rational(-398803, 1512), + mapOf(x to 6u, y to 1u) to Rational(18835, 36), + mapOf(y to 2u) to Rational(224101, 960), + mapOf(x to 1u, y to 2u) to Rational(9139699, 40320), + mapOf(x to 2u, y to 2u) to Rational(3848803, 5760), + mapOf(x to 3u, y to 2u) to Rational(93102371, 241920), + mapOf(x to 4u, y to 2u) to Rational(-65821229, 141120), + mapOf(x to 5u, y to 2u) to Rational(-15675899, 7056), + mapOf(x to 6u, y to 2u) to Rational(10459, 189), + mapOf(y to 3u) to Rational(2411, 16), + mapOf(x to 1u, y to 3u) to Rational(1294543, 10080), + mapOf(x to 2u, y to 3u) to Rational(-1740199, 1440), + mapOf(x to 3u, y to 3u) to Rational(-266994841, 282240), + mapOf(x to 4u, y to 3u) to Rational(-41261893, 211680), + mapOf(x to 5u, y to 3u) to Rational(1717357, 3528), + mapOf(x to 6u, y to 3u) to Rational(69, 14), + mapOf(y to 4u) to Rational(13231, 360), + mapOf(x to 1u, y to 4u) to Rational(4858831, 25200), + mapOf(x to 2u, y to 4u) to Rational(15565759, 75600), + mapOf(x to 3u, y to 4u) to Rational(-15583391, 35280), + mapOf(x to 4u, y to 4u) to Rational(-13345747, 11760), + mapOf(x to 5u, y to 4u) to Rational(140103, 686), + mapOf(x to 6u, y to 4u) to Rational(-765, 49) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(31409, 576), + mapOf(x to 1u) to Rational(-337099, 1728), + mapOf(x to 2u) to Rational(-211429, 1728), + mapOf(x to 3u) to Rational(-259241, 432), + mapOf(x to 4u) to Rational(-13777, 36), + mapOf(x to 5u) to Rational(-41389, 72), + mapOf(x to 6u) to Rational(-7679, 48), + mapOf(y to 1u) to Rational(-3269, 12), + mapOf(x to 1u, y to 1u) to Rational(629569, 864), + mapOf(x to 2u, y to 1u) to Rational(53867, 324), + mapOf(x to 3u, y to 1u) to Rational(2290577, 1728), + mapOf(x to 4u, y to 1u) to Rational(101507, 216), + mapOf(x to 5u, y to 1u) to Rational(213109, 288), + mapOf(x to 6u, y to 1u) to Rational(17927, 144), + mapOf(y to 2u) to Rational(314587, 1080), + mapOf(x to 1u, y to 2u) to Rational(-109771, 144), + mapOf(x to 2u, y to 2u) to Rational(-6469, 16), + mapOf(x to 3u, y to 2u) to Rational(-298291681, 181440), + mapOf(x to 4u, y to 2u) to Rational(-59147357, 48384), + mapOf(x to 5u, y to 2u) to Rational(-4982365, 6048), + mapOf(x to 6u, y to 2u) to Rational(-18727, 576), + mapOf(y to 3u) to Rational(12379, 90), + mapOf(x to 1u, y to 3u) to Rational(-542911, 1620), + mapOf(x to 2u, y to 3u) to Rational(143123, 1260), + mapOf(x to 3u, y to 3u) to Rational(9859177, 30240), + mapOf(x to 4u, y to 3u) to Rational(9312529, 20160), + mapOf(x to 5u, y to 3u) to Rational(207001, 672), + mapOf(x to 6u, y to 3u) to Rational(203, 24), + mapOf(y to 4u) to Rational(9442, 675), + mapOf(x to 1u, y to 4u) to Rational(-13729, 300), + mapOf(x to 2u, y to 4u) to Rational(-3490471, 25200), + mapOf(x to 3u, y to 4u) to Rational(-333031, 840), + mapOf(x to 4u, y to 4u) to Rational(-7572211, 47040), + mapOf(x to 5u, y to 4u) to Rational(-1189, 56), + mapOf(x to 6u, y to 4u) to Rational(-405, 196) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + y to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(14, 4), + mapOf(x to 1u) to Rational(7, 6), + mapOf(x to 2u) to Rational(7, 2), + mapOf(y to 1u) to Rational(-15, 2), + mapOf(x to 1u, y to 1u) to Rational(-13, 8), + mapOf(x to 2u, y to 1u) to Rational(-14, 3), + mapOf(y to 2u) to Rational(-7, 6), + mapOf(x to 1u, y to 2u) to Rational(7, 4), + mapOf(x to 2u, y to 2u) to Rational(9, 7), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-7, 4), + mapOf(x to 1u) to Rational(-6, 3), + mapOf(x to 2u) to Rational(-16, 2), + mapOf(y to 1u) to Rational(-15, 5), + mapOf(x to 1u, y to 1u) to Rational(4, 6), + mapOf(x to 2u, y to 1u) to Rational(5, 4), + mapOf(y to 2u) to Rational(-12, 5), + mapOf(x to 1u, y to 2u) to Rational(-18, 2), + mapOf(x to 2u, y to 2u) to Rational(6, 7), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 4'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-506213, 2800), + mapOf(x to 1u) to Rational(9859, 315), + mapOf(x to 2u) to Rational(17384377, 11340), + mapOf(x to 3u) to Rational(-9662, 63), + mapOf(x to 4u) to Rational(-12563, 4), + mapOf(y to 1u) to Rational(-486293, 22400), + mapOf(x to 1u, y to 1u) to Rational(-6530947, 25200), + mapOf(x to 2u, y to 1u) to Rational(866125, 18144), + mapOf(x to 3u, y to 1u) to Rational(2948747, 2520), + mapOf(x to 4u, y to 1u) to Rational(1196611, 2016), + mapOf(y to 2u) to Rational(-20266021, 117600), + mapOf(x to 1u, y to 2u) to Rational(26656339, 44100), + mapOf(x to 2u, y to 2u) to Rational(19499183, 18144), + mapOf(x to 3u, y to 2u) to Rational(-19801849, 7560), + mapOf(x to 4u, y to 2u) to Rational(-2639635, 1296), + mapOf(y to 3u) to Rational(-5017697, 29400), + mapOf(x to 1u, y to 3u) to Rational(-606007, 1575), + mapOf(x to 2u, y to 3u) to Rational(127494487, 132300), + mapOf(x to 3u, y to 3u) to Rational(166567, 105), + mapOf(x to 4u, y to 3u) to Rational(486403, 18144), + mapOf(y to 4u) to Rational(-32182, 735), + mapOf(x to 1u, y to 4u) to Rational(2420671, 8820), + mapOf(x to 2u, y to 4u) to Rational(-12619193, 26460), + mapOf(x to 3u, y to 4u) to Rational(-6823067, 5670), + mapOf(x to 4u, y to 4u) to Rational(-2311693, 13608), + mapOf(y to 5u) to Rational(-13324, 245), + mapOf(x to 1u, y to 5u) to Rational(1966, 35), + mapOf(x to 2u, y to 5u) to Rational(1052719, 2520), + mapOf(x to 3u, y to 5u) to Rational(19153, 270), + mapOf(x to 4u, y to 5u) to Rational(701, 54), + mapOf(y to 6u) to Rational(4647, 196), + mapOf(x to 1u, y to 6u) to Rational(2197, 28), + mapOf(x to 2u, y to 6u) to Rational(-43853, 336), + mapOf(x to 3u, y to 6u) to Rational(-301, 3), + mapOf(x to 4u, y to 6u) to Rational(34, 3) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2843, 1600), + mapOf(x to 1u) to Rational(-1483, 240), + mapOf(x to 2u) to Rational(110623, 1296), + mapOf(x to 3u) to Rational(1265, 72), + mapOf(x to 4u) to Rational(-5011, 16), + mapOf(y to 1u) to Rational(47743, 1800), + mapOf(x to 1u, y to 1u) to Rational(619229, 32400), + mapOf(x to 2u, y to 1u) to Rational(-5978369, 58320), + mapOf(x to 3u, y to 1u) to Rational(-86081, 1620), + mapOf(x to 4u, y to 1u) to Rational(6325, 72), + mapOf(y to 2u) to Rational(110951, 3360), + mapOf(x to 1u, y to 2u) to Rational(-9550649, 302400), + mapOf(x to 2u, y to 2u) to Rational(6542933, 85050), + mapOf(x to 3u, y to 2u) to Rational(4708291, 38880), + mapOf(x to 4u, y to 2u) to Rational(-433327, 1296), + mapOf(y to 3u) to Rational(56143, 600), + mapOf(x to 1u, y to 3u) to Rational(94243, 720), + mapOf(x to 2u, y to 3u) to Rational(-46779139, 226800), + mapOf(x to 3u, y to 3u) to Rational(-6948253, 12960), + mapOf(x to 4u, y to 3u) to Rational(-260261, 486), + mapOf(y to 4u) to Rational(-3205317, 19600), + mapOf(x to 1u, y to 4u) to Rational(-201253, 1050), + mapOf(x to 2u, y to 4u) to Rational(332192677, 302400), + mapOf(x to 3u, y to 4u) to Rational(351511, 360), + mapOf(x to 4u, y to 4u) to Rational(-40547, 81), + mapOf(y to 5u) to Rational(-65421, 1960), + mapOf(x to 1u, y to 5u) to Rational(-10118, 35), + mapOf(x to 2u, y to 5u) to Rational(-4341709, 10080), + mapOf(x to 3u, y to 5u) to Rational(-91703, 360), + mapOf(x to 4u, y to 5u) to Rational(-85, 9), + mapOf(y to 6u) to Rational(-25965, 784), + mapOf(x to 1u, y to 6u) to Rational(3351, 16), + mapOf(x to 2u, y to 6u) to Rational(595159, 1344), + mapOf(x to 3u, y to 6u) to Rational(-1381, 12), + mapOf(x to 4u, y to 6u) to Rational(-155, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + )), + "test 5" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-506213, 2800), + mapOf(x to 1u) to Rational(9859, 315), + mapOf(x to 2u) to Rational(17384377, 11340), + mapOf(x to 3u) to Rational(-9662, 63), + mapOf(x to 4u) to Rational(-12563, 4), + mapOf(y to 1u) to Rational(-486293, 22400), + mapOf(x to 1u, y to 1u) to Rational(-6530947, 25200), + mapOf(x to 2u, y to 1u) to Rational(866125, 18144), + mapOf(x to 3u, y to 1u) to Rational(2948747, 2520), + mapOf(x to 4u, y to 1u) to Rational(1196611, 2016), + mapOf(y to 2u) to Rational(-20266021, 117600), + mapOf(x to 1u, y to 2u) to Rational(26656339, 44100), + mapOf(x to 2u, y to 2u) to Rational(19499183, 18144), + mapOf(x to 3u, y to 2u) to Rational(-19801849, 7560), + mapOf(x to 4u, y to 2u) to Rational(-2639635, 1296), + mapOf(y to 3u) to Rational(-5017697, 29400), + mapOf(x to 1u, y to 3u) to Rational(-606007, 1575), + mapOf(x to 2u, y to 3u) to Rational(127494487, 132300), + mapOf(x to 3u, y to 3u) to Rational(166567, 105), + mapOf(x to 4u, y to 3u) to Rational(486403, 18144), + mapOf(y to 4u) to Rational(-32182, 735), + mapOf(x to 1u, y to 4u) to Rational(2420671, 8820), + mapOf(x to 2u, y to 4u) to Rational(-12619193, 26460), + mapOf(x to 3u, y to 4u) to Rational(-6823067, 5670), + mapOf(x to 4u, y to 4u) to Rational(-2311693, 13608), + mapOf(y to 5u) to Rational(-13324, 245), + mapOf(x to 1u, y to 5u) to Rational(1966, 35), + mapOf(x to 2u, y to 5u) to Rational(1052719, 2520), + mapOf(x to 3u, y to 5u) to Rational(19153, 270), + mapOf(x to 4u, y to 5u) to Rational(701, 54), + mapOf(y to 6u) to Rational(4647, 196), + mapOf(x to 1u, y to 6u) to Rational(2197, 28), + mapOf(x to 2u, y to 6u) to Rational(-43853, 336), + mapOf(x to 3u, y to 6u) to Rational(-301, 3), + mapOf(x to 4u, y to 6u) to Rational(34, 3) + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-2843, 1600), + mapOf(x to 1u) to Rational(-1483, 240), + mapOf(x to 2u) to Rational(110623, 1296), + mapOf(x to 3u) to Rational(1265, 72), + mapOf(x to 4u) to Rational(-5011, 16), + mapOf(y to 1u) to Rational(47743, 1800), + mapOf(x to 1u, y to 1u) to Rational(619229, 32400), + mapOf(x to 2u, y to 1u) to Rational(-5978369, 58320), + mapOf(x to 3u, y to 1u) to Rational(-86081, 1620), + mapOf(x to 4u, y to 1u) to Rational(6325, 72), + mapOf(y to 2u) to Rational(110951, 3360), + mapOf(x to 1u, y to 2u) to Rational(-9550649, 302400), + mapOf(x to 2u, y to 2u) to Rational(6542933, 85050), + mapOf(x to 3u, y to 2u) to Rational(4708291, 38880), + mapOf(x to 4u, y to 2u) to Rational(-433327, 1296), + mapOf(y to 3u) to Rational(56143, 600), + mapOf(x to 1u, y to 3u) to Rational(94243, 720), + mapOf(x to 2u, y to 3u) to Rational(-46779139, 226800), + mapOf(x to 3u, y to 3u) to Rational(-6948253, 12960), + mapOf(x to 4u, y to 3u) to Rational(-260261, 486), + mapOf(y to 4u) to Rational(-3205317, 19600), + mapOf(x to 1u, y to 4u) to Rational(-201253, 1050), + mapOf(x to 2u, y to 4u) to Rational(332192677, 302400), + mapOf(x to 3u, y to 4u) to Rational(351511, 360), + mapOf(x to 4u, y to 4u) to Rational(-40547, 81), + mapOf(y to 5u) to Rational(-65421, 1960), + mapOf(x to 1u, y to 5u) to Rational(-10118, 35), + mapOf(x to 2u, y to 5u) to Rational(-4341709, 10080), + mapOf(x to 3u, y to 5u) to Rational(-91703, 360), + mapOf(x to 4u, y to 5u) to Rational(-85, 9), + mapOf(y to 6u) to Rational(-25965, 784), + mapOf(x to 1u, y to 6u) to Rational(3351, 16), + mapOf(x to 2u, y to 6u) to Rational(595159, 1344), + mapOf(x to 3u, y to 6u) to Rational(-1381, 12), + mapOf(x to 4u, y to 6u) to Rational(-155, 3) + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + x to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(-17, 5), + mapOf(x to 1u) to Rational(2, 6), + mapOf(x to 2u) to Rational(14, 1), + mapOf(y to 1u) to Rational(-6, 6), + mapOf(x to 1u, y to 1u) to Rational(-7, 3), + mapOf(x to 2u, y to 1u) to Rational(-2, 9), + mapOf(y to 2u) to Rational(-9, 6), + mapOf(x to 1u, y to 2u) to Rational(17, 4), + mapOf(x to 2u, y to 2u) to Rational(2, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(5, 4), + mapOf(x to 1u) to Rational(-5, 9), + mapOf(x to 2u) to Rational(-3, 6), + mapOf(y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 1u) to Rational(14, 5), + mapOf(x to 2u, y to 1u) to Rational(5, 2), + mapOf(y to 2u) to Rational(-18, 7), + mapOf(x to 1u, y to 2u) to Rational(-8, 2), + mapOf(x to 2u, y to 2u) to Rational(18, 9), + ) + ), + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 5'" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf>()), + "test 6" + ) + assertEquals( + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ), + LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(10, 2), + mapOf(x to 1u) to Rational(6, 7), + mapOf(x to 2u) to Rational(-16, 1), + mapOf(y to 1u) to Rational(13, 8), + mapOf(x to 1u, y to 1u) to Rational(-12, 1), + mapOf(x to 2u, y to 1u) to Rational(16, 8), + mapOf(y to 2u) to Rational(10, 4), + mapOf(x to 1u, y to 2u) to Rational(4, 1), + mapOf(x to 2u, y to 2u) to Rational(-11, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1, 4), + mapOf(x to 1u) to Rational(-17, 4), + mapOf(x to 2u) to Rational(-14, 8), + mapOf(y to 1u) to Rational(17, 9), + mapOf(x to 1u, y to 1u) to Rational(1, 3), + mapOf(x to 2u, y to 1u) to Rational(7, 6), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-17, 1), + mapOf(x to 2u, y to 2u) to Rational(-10, 8), + ) + ).substitute(RationalField, mapOf( + iota to LabeledRationalFunction( + LabeledPolynomialAsIs( + mapOf() to Rational(5, 8), + mapOf(x to 1u) to Rational(-12, 6), + mapOf(x to 2u) to Rational(7, 6), + mapOf(y to 1u) to Rational(-10, 4), + mapOf(x to 1u, y to 1u) to Rational(-7, 6), + mapOf(x to 2u, y to 1u) to Rational(8, 9), + mapOf(y to 2u) to Rational(16, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(5, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(10, 6), + mapOf(x to 1u) to Rational(-18, 6), + mapOf(x to 2u) to Rational(5, 1), + mapOf(y to 1u) to Rational(17, 7), + mapOf(x to 1u, y to 1u) to Rational(8, 4), + mapOf(x to 2u, y to 1u) to Rational(-4, 9), + mapOf(y to 2u) to Rational(-6, 5), + mapOf(x to 1u, y to 2u) to Rational(-15, 8), + mapOf(x to 2u, y to 2u) to Rational(-18, 5), + ) + ), + )), + "test 6'" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_derivativeWithRespectTo_variable() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).derivativeWithRespectTo(RationalField, x), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 3), + mapOf(x to 1u) to Rational(1, 1), + mapOf(x to 2u) to Rational(-33, 8), + mapOf(x to 3u) to Rational(72, 1), + mapOf(y to 1u) to Rational(2, 3), + mapOf(x to 1u, y to 1u) to Rational(-22, 1), + mapOf(x to 2u, y to 1u) to Rational(-1, 1), + mapOf(x to 3u, y to 1u) to Rational(-36, 1), + mapOf(y to 2u) to Rational(-8, 5), + mapOf(x to 1u, y to 2u) to Rational(-1, 4), + mapOf(x to 2u, y to 2u) to Rational(12, 7), + mapOf(x to 3u, y to 2u) to Rational(-2, 1), + mapOf(y to 3u) to Rational(16, 8), + mapOf(x to 1u, y to 3u) to Rational(-4, 1), + mapOf(x to 2u, y to 3u) to Rational(9, 2), + mapOf(x to 3u, y to 3u) to Rational(20, 9), + mapOf(y to 4u) to Rational(-10, 1), + mapOf(x to 1u, y to 4u) to Rational(-14, 1), + mapOf(x to 2u, y to 4u) to Rational(3, 7), + mapOf(x to 3u, y to 4u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, x), + "test 2a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-18, 3), + mapOf(x to 1u) to Rational(2, 3), + mapOf(x to 2u) to Rational(-11, 1), + mapOf(x to 3u) to Rational(-1, 3), + mapOf(x to 4u) to Rational(-18, 2), + mapOf(y to 1u) to Rational(-20, 3), + mapOf(x to 1u, y to 1u) to Rational(-16, 5), + mapOf(x to 2u, y to 1u) to Rational(-1, 4), + mapOf(x to 3u, y to 1u) to Rational(8, 7), + mapOf(x to 4u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(9, 7), + mapOf(x to 1u, y to 2u) to Rational(6, 1), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(x to 3u, y to 2u) to Rational(9, 2), + mapOf(x to 4u, y to 2u) to Rational(5, 3), + mapOf(y to 3u) to Rational(-9, 1), + mapOf(x to 1u, y to 3u) to Rational(-40, 1), + mapOf(x to 2u, y to 3u) to Rational(-28, 1), + mapOf(x to 3u, y to 3u) to Rational(4, 7), + mapOf(x to 4u, y to 3u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, y), + "test 2b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-1, 4), + mapOf(x to 2u, y to 2u) to Rational(12, 7), + mapOf(x to 3u, y to 2u) to Rational(-2, 1), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(-4, 1), + mapOf(x to 2u, y to 3u) to Rational(9, 2), + mapOf(x to 3u, y to 3u) to Rational(20, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(-14, 1), + mapOf(x to 2u, y to 4u) to Rational(3, 7), + mapOf(x to 3u, y to 4u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, x), + "test 3a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-1, 4), + mapOf(x to 3u, y to 1u) to Rational(8, 7), + mapOf(x to 4u, y to 1u) to Rational(-1, 1), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(x to 3u, y to 2u) to Rational(9, 2), + mapOf(x to 4u, y to 2u) to Rational(5, 3), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-28, 1), + mapOf(x to 3u, y to 3u) to Rational(4, 7), + mapOf(x to 4u, y to 3u) to Rational(20, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, y), + "test 3b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2, 3), + mapOf(x to 1u) to Rational(1, 1), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(2, 3), + mapOf(x to 1u, y to 1u) to Rational(-22, 1), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-8, 5), + mapOf(x to 1u, y to 2u) to Rational(-1, 4), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, x), + "test 4a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-18, 3), + mapOf(x to 1u) to Rational(2, 3), + mapOf(x to 2u) to Rational(-11, 1), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-20, 3), + mapOf(x to 1u, y to 1u) to Rational(-16, 5), + mapOf(x to 2u, y to 1u) to Rational(-1, 4), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).derivativeWithRespectTo(RationalField, y), + "test 4b" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).derivativeWithRespectTo(RationalField, iota), + "test 5" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthDerivativeWithRespectTo_variable_order() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 1u), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 0u), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 3u), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, x, 4u), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, y, 0u), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, y, 1u), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(-33, 4), + mapOf(x to 2u) to Rational(216, 1), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(-2, 1), + mapOf(x to 2u, y to 1u) to Rational(-108, 1), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 9a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(18, 7), + mapOf(x to 1u, y to 1u) to Rational(12, 1), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(-27, 1), + mapOf(x to 1u, y to 2u) to Rational(-120, 1), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 9b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 10a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 10b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, x, 2u), + "test 11a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, y, 2u), + "test 11b" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthDerivativeWithRespectTo_variablesAndOrders() { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u)), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 0u)), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 3u)), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 4u)), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 0u)), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 1u)), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-2), + mapOf(x to 1u) to Rational(2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + x to 1u, + y to 0u + )), + "test 10" + ) + assertEquals( + LabeledPolynomialAsIs(), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthDerivativeWithRespectTo(RationalField, mapOf( + x to 0u, + y to 1u + )), + "test 11" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(-33, 4), + mapOf(x to 2u) to Rational(216, 1), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(-2, 1), + mapOf(x to 2u, y to 1u) to Rational(-108, 1), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 12a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2, 3), + mapOf(x to 1u) to Rational(-22, 1), + mapOf(x to 2u) to Rational(-1, 1), + mapOf(x to 3u) to Rational(-36, 1), + mapOf(y to 1u) to Rational(-16, 5), + mapOf(x to 1u, y to 1u) to Rational(-1, 2), + mapOf(x to 2u, y to 1u) to Rational(24, 7), + mapOf(x to 3u, y to 1u) to Rational(-4, 1), + mapOf(y to 2u) to Rational(6, 1), + mapOf(x to 1u, y to 2u) to Rational(-12, 1), + mapOf(x to 2u, y to 2u) to Rational(27, 2), + mapOf(x to 3u, y to 2u) to Rational(20, 3), + mapOf(y to 3u) to Rational(-40, 1), + mapOf(x to 1u, y to 3u) to Rational(-56, 1), + mapOf(x to 2u, y to 3u) to Rational(12, 7), + mapOf(x to 3u, y to 3u) to Rational(80, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 12b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(18, 7), + mapOf(x to 1u, y to 1u) to Rational(12, 1), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(-27, 1), + mapOf(x to 1u, y to 2u) to Rational(-120, 1), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 12c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(24, 7), + mapOf(x to 2u, y to 2u) to Rational(-6, 1), + mapOf(y to 3u) to Rational(-4, 1), + mapOf(x to 1u, y to 3u) to Rational(9, 1), + mapOf(x to 2u, y to 3u) to Rational(20, 3), + mapOf(y to 4u) to Rational(-14, 1), + mapOf(x to 1u, y to 4u) to Rational(6, 7), + mapOf(x to 2u, y to 4u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 13a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(-1, 2), + mapOf(x to 2u, y to 1u) to Rational(24, 7), + mapOf(x to 3u, y to 1u) to Rational(-4, 1), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-12, 1), + mapOf(x to 2u, y to 2u) to Rational(27, 2), + mapOf(x to 3u, y to 2u) to Rational(20, 3), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(-56, 1), + mapOf(x to 2u, y to 3u) to Rational(12, 7), + mapOf(x to 3u, y to 3u) to Rational(80, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 13b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(8, 7), + mapOf(x to 4u) to Rational(-1, 1), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-12, 1), + mapOf(x to 3u, y to 1u) to Rational(9, 1), + mapOf(x to 4u, y to 1u) to Rational(10, 3), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-84, 1), + mapOf(x to 3u, y to 2u) to Rational(12, 7), + mapOf(x to 4u, y to 2u) to Rational(60, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 13c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1, 1), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(y to 1u) to Rational(-22, 1), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-1, 4), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 14a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(2, 3), + mapOf(x to 1u) to Rational(-22, 1), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(y to 1u) to Rational(-16, 5), + mapOf(x to 1u, y to 1u) to Rational(-1, 2), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 14b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-20, 3), + mapOf(x to 1u) to Rational(-16, 5), + mapOf(x to 2u) to Rational(-1, 4), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthDerivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 14c" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_antiderivativeWithRespectTo_variable() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).antiderivativeWithRespectTo(RationalField, x), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-6, 8), + mapOf(x to 2u) to Rational(-1, 3), + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(-11, 32), + mapOf(x to 5u) to Rational(18, 5), + mapOf(x to 1u, y to 1u) to Rational(-18, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 3), + mapOf(x to 3u, y to 1u) to Rational(-11, 3), + mapOf(x to 4u, y to 1u) to Rational(-1, 12), + mapOf(x to 5u, y to 1u) to Rational(-18, 10), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(-4, 5), + mapOf(x to 3u, y to 2u) to Rational(-1, 24), + mapOf(x to 4u, y to 2u) to Rational(1, 7), + mapOf(x to 5u, y to 2u) to Rational(-1, 10), + mapOf(x to 1u, y to 3u) to Rational(3, 7), + mapOf(x to 2u, y to 3u) to Rational(1, 1), + mapOf(x to 3u, y to 3u) to Rational(-2, 3), + mapOf(x to 4u, y to 3u) to Rational(3, 8), + mapOf(x to 5u, y to 3u) to Rational(1, 9), + mapOf(x to 1u, y to 4u) to Rational(-18, 8), + mapOf(x to 2u, y to 4u) to Rational(-5, 1), + mapOf(x to 3u, y to 4u) to Rational(-7, 3), + mapOf(x to 4u, y to 4u) to Rational(1, 28), + mapOf(x to 5u, y to 4u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, x), + "test 2a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-6, 8), + mapOf(x to 1u, y to 1u) to Rational(-2, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 2), + mapOf(x to 3u, y to 1u) to Rational(-11, 8), + mapOf(x to 4u, y to 1u) to Rational(18, 1), + mapOf(y to 2u) to Rational(-9, 3), + mapOf(x to 1u, y to 2u) to Rational(1, 3), + mapOf(x to 2u, y to 2u) to Rational(-11, 2), + mapOf(x to 3u, y to 2u) to Rational(-1, 6), + mapOf(x to 4u, y to 2u) to Rational(-9, 2), + mapOf(y to 3u) to Rational(-10, 9), + mapOf(x to 1u, y to 3u) to Rational(-8, 15), + mapOf(x to 2u, y to 3u) to Rational(-1, 24), + mapOf(x to 3u, y to 3u) to Rational(4, 21), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(y to 4u) to Rational(3, 28), + mapOf(x to 1u, y to 4u) to Rational(1, 2), + mapOf(x to 2u, y to 4u) to Rational(-1, 2), + mapOf(x to 3u, y to 4u) to Rational(3, 8), + mapOf(x to 4u, y to 4u) to Rational(5, 36), + mapOf(y to 5u) to Rational(-9, 20), + mapOf(x to 1u, y to 5u) to Rational(-2, 1), + mapOf(x to 2u, y to 5u) to Rational(-7, 5), + mapOf(x to 3u, y to 5u) to Rational(1, 35), + mapOf(x to 4u, y to 5u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, y), + "test 2b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(-1, 24), + mapOf(x to 4u, y to 2u) to Rational(1, 7), + mapOf(x to 5u, y to 2u) to Rational(-1, 10), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(-2, 3), + mapOf(x to 4u, y to 3u) to Rational(3, 8), + mapOf(x to 5u, y to 3u) to Rational(1, 9), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(-7, 3), + mapOf(x to 4u, y to 4u) to Rational(1, 28), + mapOf(x to 5u, y to 4u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, x), + "test 3a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-1, 24), + mapOf(x to 3u, y to 3u) to Rational(4, 21), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-1, 2), + mapOf(x to 3u, y to 4u) to Rational(3, 8), + mapOf(x to 4u, y to 4u) to Rational(5, 36), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(-7, 5), + mapOf(x to 3u, y to 5u) to Rational(1, 35), + mapOf(x to 4u, y to 5u) to Rational(1, 1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, y), + "test 3b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-6, 8), + mapOf(x to 2u) to Rational(-1, 3), + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(-18, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 3), + mapOf(x to 3u, y to 1u) to Rational(-11, 3), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-10, 3), + mapOf(x to 2u, y to 2u) to Rational(-4, 5), + mapOf(x to 3u, y to 2u) to Rational(-1, 24), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, x), + "test 4a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-6, 8), + mapOf(x to 1u, y to 1u) to Rational(-2, 3), + mapOf(x to 2u, y to 1u) to Rational(1, 2), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-9, 3), + mapOf(x to 1u, y to 2u) to Rational(1, 3), + mapOf(x to 2u, y to 2u) to Rational(-11, 2), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(-10, 9), + mapOf(x to 1u, y to 3u) to Rational(-8, 15), + mapOf(x to 2u, y to 3u) to Rational(-1, 24), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).antiderivativeWithRespectTo(RationalField, y), + "test 4b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(iota to 1u) to Rational(-6, 8), + mapOf(x to 1u, iota to 1u) to Rational(-2, 3), + mapOf(x to 2u, iota to 1u) to Rational(1, 2), + mapOf(x to 3u, iota to 1u) to Rational(-11, 8), + mapOf(x to 4u, iota to 1u) to Rational(18, 1), + mapOf(y to 1u, iota to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u, iota to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u, iota to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u, iota to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u, iota to 1u) to Rational(-18, 2), + mapOf(y to 2u, iota to 1u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u, iota to 1u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u, iota to 1u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u, iota to 1u) to Rational(4, 7), + mapOf(x to 4u, y to 2u, iota to 1u) to Rational(-4, 8), + mapOf(y to 3u, iota to 1u) to Rational(3, 7), + mapOf(x to 1u, y to 3u, iota to 1u) to Rational(16, 8), + mapOf(x to 2u, y to 3u, iota to 1u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u, iota to 1u) to Rational(12, 8), + mapOf(x to 4u, y to 3u, iota to 1u) to Rational(5, 9), + mapOf(y to 4u, iota to 1u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u, iota to 1u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u, iota to 1u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u, iota to 1u) to Rational(1, 7), + mapOf(x to 4u, y to 4u, iota to 1u) to Rational(15, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).antiderivativeWithRespectTo(RationalField, iota), + "test 5" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthAntiderivativeWithRespectTo_variable_order() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 1u), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 0u), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-1, 3), + mapOf(x to 4u) to Rational(1, 12), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(-1, 12), + mapOf(x to 5u) to Rational(1, 60), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 3u), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-1, 60), + mapOf(x to 6u) to Rational(1, 360), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 4u), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 0u), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(1), + mapOf(x to 1u, y to 1u) to Rational(-2), + mapOf(x to 2u, y to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 1u), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(1, 2), + mapOf(x to 1u, y to 2u) to Rational(-1), + mapOf(x to 2u, y to 2u) to Rational(1, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-11, 160), + mapOf(x to 6u) to Rational(3, 5), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(-1, 60), + mapOf(x to 6u, y to 1u) to Rational(-3, 10), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(3, 14), + mapOf(x to 3u, y to 3u) to Rational(1, 3), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(-9, 8), + mapOf(x to 3u, y to 4u) to Rational(-5, 3), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 9a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(-11, 16), + mapOf(x to 4u, y to 2u) to Rational(9, 1), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(-1, 18), + mapOf(x to 4u, y to 3u) to Rational(-9, 6), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(3, 140), + mapOf(x to 1u, y to 5u) to Rational(1, 10), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(-3, 40), + mapOf(x to 1u, y to 6u) to Rational(-1, 3), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 9b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 10a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 10b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 6u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 6u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + mapOf(x to 6u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 11a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(0), + mapOf(x to 3u, y to 6u) to Rational(0), + mapOf(x to 4u, y to 6u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 11b" + ) + } + @Test + @OptIn(UnstableKMathAPI::class) + fun test_Polynomial_nthAntiderivativeWithRespectTo_variablesAndOrders() { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u)), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 0u), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-1, 3), + mapOf(x to 4u) to Rational(1, 12), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 2u), + "test 3" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 3u) to Rational(1, 6), + mapOf(x to 4u) to Rational(-1, 12), + mapOf(x to 5u) to Rational(1, 60), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 3u), + "test 4" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-1, 60), + mapOf(x to 6u) to Rational(1, 360), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, x, 4u), + "test 5" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 0u), + "test 6" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(1), + mapOf(x to 1u, y to 1u) to Rational(-2), + mapOf(x to 2u, y to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 1u), + "test 7" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(1, 2), + mapOf(x to 1u, y to 2u) to Rational(-1), + mapOf(x to 2u, y to 2u) to Rational(1, 2), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, y, 2u), + "test 8" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf()), + "test 9" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(x to 2u) to Rational(-1), + mapOf(x to 3u) to Rational(1, 3), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + x to 1u, + y to 0u + )), + "test 10" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(1), + mapOf(x to 1u, y to 1u) to Rational(-2), + mapOf(x to 2u, y to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(1), + mapOf(x to 1u) to Rational(-2), + mapOf(x to 2u) to Rational(1), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf( + x to 0u, + y to 1u + )), + "test 11" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(-11, 160), + mapOf(x to 6u) to Rational(3, 5), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(-1, 60), + mapOf(x to 6u, y to 1u) to Rational(-3, 10), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(3, 14), + mapOf(x to 3u, y to 3u) to Rational(1, 3), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(-9, 8), + mapOf(x to 3u, y to 4u) to Rational(-5, 3), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 12a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(-6, 8), + mapOf(x to 2u, y to 1u) to Rational(-1, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 6), + mapOf(x to 4u, y to 1u) to Rational(-11, 32), + mapOf(x to 5u, y to 1u) to Rational(18, 5), + mapOf(x to 1u, y to 2u) to Rational(-9, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 6), + mapOf(x to 3u, y to 2u) to Rational(-11, 6), + mapOf(x to 4u, y to 2u) to Rational(-1, 24), + mapOf(x to 5u, y to 2u) to Rational(-9, 10), + mapOf(x to 1u, y to 3u) to Rational(-10, 9), + mapOf(x to 2u, y to 3u) to Rational(-4, 15), + mapOf(x to 3u, y to 3u) to Rational(-1, 72), + mapOf(x to 4u, y to 3u) to Rational(1, 21), + mapOf(x to 5u, y to 3u) to Rational(-1, 30), + mapOf(x to 1u, y to 4u) to Rational(3, 28), + mapOf(x to 2u, y to 4u) to Rational(1, 4), + mapOf(x to 3u, y to 4u) to Rational(-1, 6), + mapOf(x to 4u, y to 4u) to Rational(3, 32), + mapOf(x to 5u, y to 4u) to Rational(1, 36), + mapOf(x to 1u, y to 5u) to Rational(-9, 20), + mapOf(x to 2u, y to 5u) to Rational(-1, 1), + mapOf(x to 3u, y to 5u) to Rational(-7, 15), + mapOf(x to 4u, y to 5u) to Rational(1, 140), + mapOf(x to 5u, y to 5u) to Rational(1, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 12b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(-11, 16), + mapOf(x to 4u, y to 2u) to Rational(9, 1), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(-1, 18), + mapOf(x to 4u, y to 3u) to Rational(-9, 6), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(3, 140), + mapOf(x to 1u, y to 5u) to Rational(1, 10), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(-3, 40), + mapOf(x to 1u, y to 6u) to Rational(-1, 3), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(-11, 8), + mapOf(x to 4u) to Rational(18, 1), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(-1, 3), + mapOf(x to 4u, y to 1u) to Rational(-18, 2), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(3, 7), + mapOf(x to 1u, y to 3u) to Rational(16, 8), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(-18, 8), + mapOf(x to 1u, y to 4u) to Rational(-10, 1), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 12c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(1, 35), + mapOf(x to 6u, y to 2u) to Rational(-1, 60), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(-1, 6), + mapOf(x to 5u, y to 3u) to Rational(3, 40), + mapOf(x to 6u, y to 3u) to Rational(1, 54), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(-7, 12), + mapOf(x to 5u, y to 4u) to Rational(1, 140), + mapOf(x to 6u, y to 4u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 13a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(-1, 72), + mapOf(x to 4u, y to 3u) to Rational(1, 21), + mapOf(x to 5u, y to 3u) to Rational(-1, 30), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(-1, 6), + mapOf(x to 4u, y to 4u) to Rational(3, 32), + mapOf(x to 5u, y to 4u) to Rational(1, 36), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(-7, 15), + mapOf(x to 4u, y to 5u) to Rational(1, 140), + mapOf(x to 5u, y to 5u) to Rational(1, 5), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 13b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(0), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(1, 21), + mapOf(x to 4u, y to 4u) to Rational(-1, 24), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(-1, 10), + mapOf(x to 3u, y to 5u) to Rational(3, 40), + mapOf(x to 4u, y to 5u) to Rational(1, 36), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(-7, 30), + mapOf(x to 3u, y to 6u) to Rational(1, 210), + mapOf(x to 4u, y to 6u) to Rational(1, 6), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(0), + mapOf(x to 2u) to Rational(0), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(0), + mapOf(x to 1u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(0), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(4, 7), + mapOf(x to 4u, y to 2u) to Rational(-4, 8), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(-16, 8), + mapOf(x to 3u, y to 3u) to Rational(12, 8), + mapOf(x to 4u, y to 3u) to Rational(5, 9), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(-14, 2), + mapOf(x to 3u, y to 4u) to Rational(1, 7), + mapOf(x to 4u, y to 4u) to Rational(15, 3), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 13c" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(-3, 8), + mapOf(x to 3u) to Rational(-1, 9), + mapOf(x to 4u) to Rational(1, 24), + mapOf(x to 5u) to Rational(0), + mapOf(x to 6u) to Rational(0), + mapOf(x to 2u, y to 1u) to Rational(-9, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 9), + mapOf(x to 4u, y to 1u) to Rational(-11, 12), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 6u, y to 1u) to Rational(0), + mapOf(x to 2u, y to 2u) to Rational(-5, 3), + mapOf(x to 3u, y to 2u) to Rational(-4, 15), + mapOf(x to 4u, y to 2u) to Rational(-1, 96), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 6u, y to 2u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 6u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + mapOf(x to 6u, y to 4u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 2u)), + "test 14a" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(-6, 8), + mapOf(x to 2u, y to 1u) to Rational(-1, 3), + mapOf(x to 3u, y to 1u) to Rational(1, 6), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(x to 5u, y to 1u) to Rational(0), + mapOf(x to 1u, y to 2u) to Rational(-9, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 6), + mapOf(x to 3u, y to 2u) to Rational(-11, 6), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(x to 5u, y to 2u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(-10, 9), + mapOf(x to 2u, y to 3u) to Rational(-4, 15), + mapOf(x to 3u, y to 3u) to Rational(-1, 72), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(x to 5u, y to 3u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(x to 5u, y to 4u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + mapOf(x to 5u, y to 5u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(x to 1u, y to 1u)), + "test 14b" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 2u) to Rational(-3, 8), + mapOf(x to 1u, y to 2u) to Rational(-1, 3), + mapOf(x to 2u, y to 2u) to Rational(1, 4), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(-1, 1), + mapOf(x to 1u, y to 3u) to Rational(1, 9), + mapOf(x to 2u, y to 3u) to Rational(-11, 6), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(-5, 18), + mapOf(x to 1u, y to 4u) to Rational(-2, 15), + mapOf(x to 2u, y to 4u) to Rational(-1, 96), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + mapOf(y to 5u) to Rational(0), + mapOf(x to 1u, y to 5u) to Rational(0), + mapOf(x to 2u, y to 5u) to Rational(0), + mapOf(x to 3u, y to 5u) to Rational(0), + mapOf(x to 4u, y to 5u) to Rational(0), + mapOf(y to 6u) to Rational(0), + mapOf(x to 1u, y to 6u) to Rational(0), + mapOf(x to 2u, y to 6u) to Rational(0), + mapOf(x to 3u, y to 6u) to Rational(0), + mapOf(x to 4u, y to 6u) to Rational(0), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-6, 8), + mapOf(x to 1u) to Rational(-2, 3), + mapOf(x to 2u) to Rational(1, 2), + mapOf(x to 3u) to Rational(0), + mapOf(x to 4u) to Rational(0), + mapOf(y to 1u) to Rational(-18, 3), + mapOf(x to 1u, y to 1u) to Rational(2, 3), + mapOf(x to 2u, y to 1u) to Rational(-11, 1), + mapOf(x to 3u, y to 1u) to Rational(0), + mapOf(x to 4u, y to 1u) to Rational(0), + mapOf(y to 2u) to Rational(-10, 3), + mapOf(x to 1u, y to 2u) to Rational(-8, 5), + mapOf(x to 2u, y to 2u) to Rational(-1, 8), + mapOf(x to 3u, y to 2u) to Rational(0), + mapOf(x to 4u, y to 2u) to Rational(0), + mapOf(y to 3u) to Rational(0), + mapOf(x to 1u, y to 3u) to Rational(0), + mapOf(x to 2u, y to 3u) to Rational(0), + mapOf(x to 3u, y to 3u) to Rational(0), + mapOf(x to 4u, y to 3u) to Rational(0), + mapOf(y to 4u) to Rational(0), + mapOf(x to 1u, y to 4u) to Rational(0), + mapOf(x to 2u, y to 4u) to Rational(0), + mapOf(x to 3u, y to 4u) to Rational(0), + mapOf(x to 4u, y to 4u) to Rational(0), + ).nthAntiderivativeWithRespectTo(RationalField, mapOf(y to 2u)), + "test 14c" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index f0a1128b4..007c3e5e9 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -7,14 +7,19 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.test.misc.* -import kotlin.test.* +import space.kscience.kmath.test.misc.IntModuloRing +import space.kscience.kmath.test.misc.Rational +import space.kscience.kmath.test.misc.RationalField +import space.kscience.kmath.test.misc.m +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame +import kotlin.test.fail -@UnstableKMathAPI class NumberedPolynomialTest { - private val o = Rational(0) + val o = Rational(0) + @Test fun test_Polynomial_Int_plus() { RationalField.numberedPolynomialSpace { @@ -557,6 +562,7 @@ class NumberedPolynomialTest { ) assertEquals( NumberedPolynomial( + listOf() to Rational(0), listOf(3u) to Rational(-8, 9), listOf(0u, 4u) to Rational(-8, 7), ), @@ -650,6 +656,7 @@ class NumberedPolynomialTest { ) assertEquals( NumberedPolynomial( + listOf() to Rational(0), listOf(3u) to Rational(-8, 9), listOf(0u, 4u) to Rational(-8, 7), ), @@ -816,6 +823,7 @@ class NumberedPolynomialTest { ) assertEquals( NumberedPolynomial( + listOf() to Rational(0), listOf(3u) to Rational(-8, 9), listOf(0u, 4u) to Rational(-8, 7), ), diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt index 3ad482454..85180bd2a 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.test.misc +import space.kscience.kmath.functions.LabeledPolynomial +import space.kscience.kmath.functions.LabeledRationalFunction import space.kscience.kmath.functions.NumberedPolynomial import space.kscience.kmath.functions.NumberedRationalFunction import kotlin.test.assertEquals @@ -28,6 +30,18 @@ fun assertEquals( message ) +fun assertEquals( + expected: LabeledPolynomial, + actual: LabeledPolynomial, + absoluteTolerance: Double, + message: String? = null +) = assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message +) + fun assertEquals( expected: NumberedRationalFunction, actual: NumberedRationalFunction, @@ -48,6 +62,26 @@ fun assertEquals( ) } +fun assertEquals( + expected: LabeledRationalFunction, + actual: LabeledRationalFunction, + absoluteTolerance: Double, + message: String? = null +) { + assertEquals( + expected.numerator, + actual.numerator, + absoluteTolerance, + message + ) + assertEquals( + expected.denominator, + actual.denominator, + absoluteTolerance, + message + ) +} + inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, From d3be07987c30e5dd786cdfb04cec4801d22b6d30 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 6 Jul 2022 23:16:25 +0300 Subject: [PATCH 112/174] Simplify usages of LabeledPolynomial constructing fabrics. Fix bugs. Add tests for variable's interoperability. --- .../kmath/functions/LabeledPolynomial.kt | 150 ++-- .../kmath/functions/ListPolynomial.kt | 5 - .../kmath/functions/NumberedPolynomial.kt | 5 - .../kscience/kmath/functions/Polynomial.kt | 2 +- .../kmath/functions/LabeledPolynomialTest.kt | 800 ++++++++++++++++-- 5 files changed, 816 insertions(+), 146 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 1477796ea..7f107a87f 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -77,63 +77,63 @@ public class LabeledPolynomialSpace>( * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ public override operator fun Symbol.plus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomialAsIs(mapOf( + if (other == 0) LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, emptyMap() to constantOne * other, - )) + ) /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. */ public override operator fun Symbol.minus(other: Int): LabeledPolynomial = - if (other == 0) LabeledPolynomialAsIs(mapOf( - mapOf(this@minus to 1U) to -constantOne, - )) - else LabeledPolynomialAsIs(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to constantOne * other, - )) + if (other == 0) LabeledPolynomialAsIs( + mapOf(this@minus to 1U) to constantOne, + ) + else LabeledPolynomialAsIs( + mapOf(this@minus to 1U) to constantOne, + emptyMap() to constantOne * -other, + ) /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero - else LabeledPolynomialAsIs(mapOf( + else LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne * other, - )) + ) /** * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun Int.plus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomialAsIs(mapOf( + if (this == 0) LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, emptyMap() to constantOne * this@plus, - )) + ) /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun Int.minus(other: Symbol): LabeledPolynomial = - if (this == 0) LabeledPolynomialAsIs(mapOf( + if (this == 0) LabeledPolynomialAsIs( mapOf(other to 1U) to -constantOne, - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(other to 1U) to -constantOne, emptyMap() to constantOne * this@minus, - )) + ) /** * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero - else LabeledPolynomialAsIs(mapOf( + else LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne * this@times, - )) + ) /** * Returns sum of the polynomial and the integer represented as a polynomial. @@ -143,7 +143,7 @@ public class LabeledPolynomialSpace>( public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = if (other == 0) this else with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other.asConstant())) + if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -161,7 +161,7 @@ public class LabeledPolynomialSpace>( public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = if (other == 0) this else with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to (-other).asConstant())) + if (isEmpty()) (-other).asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -180,7 +180,7 @@ public class LabeledPolynomialSpace>( when(other) { 0 -> zero 1 -> this - else -> LabeledPolynomial( + else -> LabeledPolynomialAsIs( coefficients .toMutableMap() .apply { @@ -197,7 +197,7 @@ public class LabeledPolynomialSpace>( public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus.asConstant())) + if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -215,7 +215,7 @@ public class LabeledPolynomialSpace>( public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = if (this == 0) -other else with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus.asConstant())) + if (isEmpty()) this@minus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -236,7 +236,7 @@ public class LabeledPolynomialSpace>( when(this) { 0 -> zero 1 -> other - else -> LabeledPolynomial( + else -> LabeledPolynomialAsIs( other.coefficients .toMutableMap() .apply { @@ -245,65 +245,60 @@ public class LabeledPolynomialSpace>( ) } - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): LabeledPolynomial = number(constantNumber(value)) - /** * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ public override operator fun Symbol.plus(other: C): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, emptyMap() to other, - )) + ) /** * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. */ public override operator fun Symbol.minus(other: C): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( - mapOf(this@minus to 1U) to -constantOne, - emptyMap() to other, - )) + LabeledPolynomialAsIs( + mapOf(this@minus to 1U) to constantOne, + emptyMap() to -other, + ) /** * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ public override operator fun Symbol.times(other: C): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this@times to 1U) to other, - )) + ) /** * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun C.plus(other: Symbol): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, emptyMap() to this@plus, - )) + ) /** * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun C.minus(other: Symbol): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(other to 1U) to -constantOne, emptyMap() to this@minus, - )) + ) /** * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ public override operator fun C.times(other: Symbol): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(other to 1U) to this@times, - )) + ) /** * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@plus)) + if (isEmpty()) this@plus.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -318,7 +313,7 @@ public class LabeledPolynomialSpace>( */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to this@minus)) + if (isEmpty()) this@minus.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -347,7 +342,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -362,7 +357,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap() to other)) + if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -387,60 +382,59 @@ public class LabeledPolynomialSpace>( /** * Converts the constant [value] to polynomial. */ - public override fun number(value: C): LabeledPolynomial = - LabeledPolynomial(mapOf(emptyMap() to value)) + public override fun number(value: C): LabeledPolynomial = value.asLabeledPolynomial() /** * Represents the variable as a monic monomial. */ public override operator fun Symbol.unaryPlus(): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne, - )) + ) /** * Returns negation of representation of the variable as a monic monomial. */ public override operator fun Symbol.unaryMinus(): LabeledPolynomial = - LabeledPolynomialAsIs(mapOf( + LabeledPolynomialAsIs( mapOf(this to 1U) to -constantOne, - )) + ) /** * Returns sum of the variables represented as monic monomials. */ public override operator fun Symbol.plus(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomialAsIs(mapOf( + if (this == other) LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne * 2 - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to constantOne, - )) + ) /** * Returns difference between the variables represented as monic monomials. */ public override operator fun Symbol.minus(other: Symbol): LabeledPolynomial = if (this == other) zero - else LabeledPolynomialAsIs(mapOf( + else LabeledPolynomialAsIs( mapOf(this to 1U) to constantOne, mapOf(other to 1U) to -constantOne, - )) + ) /** * Returns product of the variables represented as monic monomials. */ public override operator fun Symbol.times(other: Symbol): LabeledPolynomial = - if (this == other) LabeledPolynomialAsIs(mapOf( + if (this == other) LabeledPolynomialAsIs( mapOf(this to 2U) to constantOne - )) - else LabeledPolynomialAsIs(mapOf( + ) + else LabeledPolynomialAsIs( mapOf(this to 1U, other to 1U) to constantOne, - )) + ) /** * Returns sum of the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@plus to 1u) to constantOne)) + if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -455,15 +449,15 @@ public class LabeledPolynomialSpace>( */ public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = with(other.coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(this@minus to 1u) to constantOne)) + if (isEmpty()) this@minus.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { - val degs = mapOf(this@minus to 1U) + val theVariableDegs = mapOf(this@minus to 1U) - forEach { (degs, c) -> if(degs != degs) this[degs] = -c } + forEach { (degs, c) -> if(degs != theVariableDegs) this[degs] = -c } - this[degs] = constantOne - getOrElse(degs) { constantZero } + this[theVariableDegs] = constantOne - getOrElse(theVariableDegs) { constantZero } } ) } @@ -481,7 +475,7 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { @@ -496,13 +490,13 @@ public class LabeledPolynomialSpace>( */ public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = with(coefficients) { - if (isEmpty()) LabeledPolynomialAsIs(mapOf(mapOf(other to 1u) to constantOne)) + if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( toMutableMap() .apply { val degs = mapOf(other to 1U) - this[degs] = constantOne - getOrElse(degs) { constantZero } + this[degs] = getOrElse(degs) { constantZero } - constantOne } ) } @@ -560,11 +554,11 @@ public class LabeledPolynomialSpace>( /** * Instance of zero polynomial (zero of the polynomial ring). */ - override val zero: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantZero)) + override val zero: LabeledPolynomial = LabeledPolynomialAsIs() /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: LabeledPolynomial = LabeledPolynomialAsIs(mapOf(emptyMap() to constantOne)) + override val one: LabeledPolynomial = constantOne.asLabeledPolynomial() /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index a83b3915a..76e1a6bb6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -172,11 +172,6 @@ public open class ListPolynomialSpace>( ) } - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): ListPolynomial = number(constantNumber(value)) - /** * Returns sum of the constant represented as a polynomial and the polynomial. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index ad421d7d3..f7dd9d8de 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -169,11 +169,6 @@ public class NumberedPolynomialSpace>( ) } - /** - * Converts the integer [value] to polynomial. - */ - public override fun number(value: Int): NumberedPolynomial = number(constantNumber(value)) - /** * Returns sum of the constant represented as a polynomial and the polynomial. */ 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 12490d133..61ea5a342 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 @@ -112,7 +112,7 @@ public interface PolynomialSpace> : Ring

{ /** * Converts the integer [value] to polynomial. */ - public fun number(value: Int): P = one * value + public fun number(value: Int): P = number(constantNumber(value)) /** * Converts the integer to polynomial. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index 15c4c3656..95481f2ef 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol @@ -26,34 +28,118 @@ class LabeledPolynomialTest { val o = Rational(0) @Test - @Ignore fun test_Variable_Int_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + x + 5, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + x + 0, + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Int_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-5), + mapOf(x to 1u) to Rational(1), + ), + x - 5, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + x - 0, + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Int_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + x * 5, + "test 1" + ) + assertSame( + zero, + x * 0, + "test 2" + ) + } } @Test - @Ignore fun test_Int_Variable_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + 5 + x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + 0 + x, + "test 2" + ) + } } @Test - @Ignore fun test_Int_Variable_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(-1), + ), + 5 - x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-1), + ), + 0 - x, + "test 2" + ) + } } @Test - @Ignore fun test_Int_Variable_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + 5 * x, + "test 1" + ) + assertSame( + zero, + 0 * x, + "test 2" + ) + } } @Test fun test_Polynomial_Int_plus() { @@ -516,34 +602,126 @@ class LabeledPolynomialTest { } } @Test - @Ignore fun test_Variable_Constant_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + x + Rational(5), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(1), + ), + x + Rational(0), + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Constant_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-5), + mapOf(x to 1u) to Rational(1), + ), + x - Rational(5), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(1), + ), + x - Rational(0), + "test 2" + ) + } } @Test - @Ignore fun test_Variable_Constant_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + x * Rational(5), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0), + ), + x * Rational(0), + "test 2" + ) + } } @Test - @Ignore fun test_Constant_Variable_plus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(1), + ), + Rational(5) + x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(1), + ), + Rational(0) + x, + "test 2" + ) + } } @Test - @Ignore fun test_Constant_Variable_minus() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(5), + mapOf(x to 1u) to Rational(-1), + ), + Rational(5) - x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(0), + mapOf(x to 1u) to Rational(-1), + ), + Rational(0) - x, + "test 2" + ) + } } @Test - @Ignore fun test_Constant_Variable_times() { - // TODO + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(5), + ), + Rational(5) * x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(0), + ), + Rational(0) * x, + "test 2" + ) + } } @Test fun test_Polynomial_Constant_plus() { @@ -1068,59 +1246,567 @@ class LabeledPolynomialTest { } } @Test - @Ignore - fun test_Variable_unaryPlus(){ - // TODO + fun test_Variable_unaryPlus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + ), + +x + ) + } } @Test - @Ignore - fun test_Variable_unaryMinus(){ - // TODO + fun test_Variable_unaryMinus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-1), + ), + -x + ) + } } @Test - @Ignore - fun test_Variable_Variable_plus(){ - // TODO + fun test_Variable_Variable_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(y to 1u) to Rational(1), + ), + x + y, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(2), + ), + x + x, + "test 2" + ) + } } @Test - @Ignore - fun test_Variable_Variable_minus(){ - // TODO + fun test_Variable_Variable_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(1), + mapOf(y to 1u) to Rational(-1), + ), + x - y, + "test 1" + ) + assertSame( + zero, + x - x, + "test 2" + ) + } } @Test - @Ignore - fun test_Variable_Variable_times(){ - // TODO + fun test_Variable_Variable_times() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u, y to 1u) to Rational(1), + ), + x * y, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 2u) to Rational(1), + ), + x * x, + "test 2" + ) + } } @Test - @Ignore - fun test_Variable_Polynomial_plus(){ - // TODO + fun test_Variable_Polynomial_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + x + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(6, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + y + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + mapOf(iota to 1u) to Rational(1), + ), + iota + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 3" + ) + } } @Test - @Ignore - fun test_Variable_Polynomial_minus(){ - // TODO + fun test_Variable_Polynomial_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(16, 4), + mapOf(x to 1u) to Rational(-1, 3), + mapOf(x to 2u) to Rational(-3, 8), + mapOf(y to 1u) to Rational(1, 7), + mapOf(x to 1u, y to 1u) to Rational(15, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 5), + mapOf(y to 2u) to Rational(13, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(-11, 8), + ), + x - LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(16, 4), + mapOf(x to 1u) to Rational(-4, 3), + mapOf(x to 2u) to Rational(-3, 8), + mapOf(y to 1u) to Rational(8, 7), + mapOf(x to 1u, y to 1u) to Rational(15, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 5), + mapOf(y to 2u) to Rational(13, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(-11, 8), + ), + y - LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(16, 4), + mapOf(x to 1u) to Rational(-4, 3), + mapOf(x to 2u) to Rational(-3, 8), + mapOf(y to 1u) to Rational(1, 7), + mapOf(x to 1u, y to 1u) to Rational(15, 3), + mapOf(x to 2u, y to 1u) to Rational(-6, 5), + mapOf(y to 2u) to Rational(13, 3), + mapOf(x to 1u, y to 2u) to Rational(-13, 4), + mapOf(x to 2u, y to 2u) to Rational(-11, 8), + mapOf(iota to 1u) to Rational(1), + ), + iota - LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 3" + ) + } } @Test - @Ignore - fun test_Variable_Polynomial_times(){ - // TODO + fun test_Variable_Polynomial_times() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-16, 4), + mapOf(x to 2u) to Rational(4, 3), + mapOf(x to 3u) to Rational(3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 7), + mapOf(x to 2u, y to 1u) to Rational(-15, 3), + mapOf(x to 3u, y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 2u) to Rational(-13, 3), + mapOf(x to 2u, y to 2u) to Rational(13, 4), + mapOf(x to 3u, y to 2u) to Rational(11, 8), + ), + x * LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-16, 4), + mapOf(x to 1u, y to 1u) to Rational(4, 3), + mapOf(x to 2u, y to 1u) to Rational(3, 8), + mapOf(y to 2u) to Rational(-1, 7), + mapOf(x to 1u, y to 2u) to Rational(-15, 3), + mapOf(x to 2u, y to 2u) to Rational(6, 5), + mapOf(y to 3u) to Rational(-13, 3), + mapOf(x to 1u, y to 3u) to Rational(13, 4), + mapOf(x to 2u, y to 3u) to Rational(11, 8), + ), + y * LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(iota to 1u) to Rational(-16, 4), + mapOf(x to 1u, iota to 1u) to Rational(4, 3), + mapOf(x to 2u, iota to 1u) to Rational(3, 8), + mapOf(y to 1u, iota to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u, iota to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u, iota to 1u) to Rational(6, 5), + mapOf(y to 2u, iota to 1u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u, iota to 1u) to Rational(13, 4), + mapOf(x to 2u, y to 2u, iota to 1u) to Rational(11, 8), + ), + iota * LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + "test 3" + ) + } } @Test - @Ignore - fun test_Polynomial_Variable_plus(){ - // TODO + fun test_Polynomial_Variable_plus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(7, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) + x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(6, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) + y, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + mapOf(iota to 1u) to Rational(1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) + iota, + "test 3" + ) + } } @Test - @Ignore - fun test_Polynomial_Variable_minus(){ - // TODO + fun test_Polynomial_Variable_minus() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(1, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) - x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-8, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) - y, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + mapOf(iota to 1u) to Rational(-1), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) - iota, + "test 3" + ) + } } @Test - @Ignore - fun test_Polynomial_Variable_times(){ - // TODO + fun test_Polynomial_Variable_times() { + RationalField.labeledPolynomialSpace { + assertEquals( + LabeledPolynomialAsIs( + mapOf(x to 1u) to Rational(-16, 4), + mapOf(x to 2u) to Rational(4, 3), + mapOf(x to 3u) to Rational(3, 8), + mapOf(x to 1u, y to 1u) to Rational(-1, 7), + mapOf(x to 2u, y to 1u) to Rational(-15, 3), + mapOf(x to 3u, y to 1u) to Rational(6, 5), + mapOf(x to 1u, y to 2u) to Rational(-13, 3), + mapOf(x to 2u, y to 2u) to Rational(13, 4), + mapOf(x to 3u, y to 2u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) * x, + "test 1" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(y to 1u) to Rational(-16, 4), + mapOf(x to 1u, y to 1u) to Rational(4, 3), + mapOf(x to 2u, y to 1u) to Rational(3, 8), + mapOf(y to 2u) to Rational(-1, 7), + mapOf(x to 1u, y to 2u) to Rational(-15, 3), + mapOf(x to 2u, y to 2u) to Rational(6, 5), + mapOf(y to 3u) to Rational(-13, 3), + mapOf(x to 1u, y to 3u) to Rational(13, 4), + mapOf(x to 2u, y to 3u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) * y, + "test 2" + ) + assertEquals( + LabeledPolynomialAsIs( + mapOf(iota to 1u) to Rational(-16, 4), + mapOf(x to 1u, iota to 1u) to Rational(4, 3), + mapOf(x to 2u, iota to 1u) to Rational(3, 8), + mapOf(y to 1u, iota to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u, iota to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u, iota to 1u) to Rational(6, 5), + mapOf(y to 2u, iota to 1u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u, iota to 1u) to Rational(13, 4), + mapOf(x to 2u, y to 2u, iota to 1u) to Rational(11, 8), + ), + LabeledPolynomialAsIs( + mapOf() to Rational(-16, 4), + mapOf(x to 1u) to Rational(4, 3), + mapOf(x to 2u) to Rational(3, 8), + mapOf(y to 1u) to Rational(-1, 7), + mapOf(x to 1u, y to 1u) to Rational(-15, 3), + mapOf(x to 2u, y to 1u) to Rational(6, 5), + mapOf(y to 2u) to Rational(-13, 3), + mapOf(x to 1u, y to 2u) to Rational(13, 4), + mapOf(x to 2u, y to 2u) to Rational(11, 8), + ) * iota, + "test 3" + ) + } } @Test fun test_Polynomial_unaryMinus() { From d44a48bdb1c7d9fa1d8d0918373cf068d04a4c6a Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:27:59 +0300 Subject: [PATCH 113/174] Moving to new modules. --- kmath-functions/build.gradle.kts | 13 +- .../kmath/functions/ListPolynomialTest.kt | 5 +- .../kmath/functions/ListPolynomialUtilTest.kt | 14 +- kmath-polynomialX/build.gradle.kts | 30 ++++ .../LabeledPolynomial.kt | 0 .../LabeledRationalFunction.kt | 0 .../NumberedPolynomial.kt | 0 .../NumberedRationalFunction.kt | 0 .../algebraicStub.kt | 146 ++++++++++++++++++ .../labeledConstructors.kt | 0 .../labeledUtil.kt | 0 .../numberedConstructors.kt | 0 .../numberedUtil.kt | 0 .../functions/LabeledConstructorsTest.kt | 10 +- .../kmath/functions/LabeledPolynomialTest.kt | 25 ++- .../functions/LabeledPolynomialUtilTest.kt | 14 +- .../functions/NumberedConstructorsTest.kt | 0 .../kmath/functions/NumberedPolynomialTest.kt | 11 +- .../functions/NumberedPolynomialUtilTest.kt | 13 +- settings.gradle.kts | 3 + test-utils-functions/build.gradle.kts | 14 ++ .../kmath/functions/testUtils}/IntModulo.kt | 55 +++---- .../functions/testUtils/IntModuloUtils.kt | 19 +++ .../kmath/functions/testUtils}/Rational.kt | 56 +++---- .../kmath/functions/testUtils/assertion.kt | 22 +++ .../kmath/functions/testUtils}/misc.kt | 8 +- test-utils-polynomialX/build.gradle.kts | 16 ++ .../kmath/functions/testUtils/BufferUtils.kt | 12 ++ .../kmath/functions/testUtils}/assertion.kt | 53 ++++--- .../kmath/functions/testUtils/misc.kt | 19 +++ 30 files changed, 419 insertions(+), 139 deletions(-) create mode 100644 kmath-polynomialX/build.gradle.kts rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/LabeledPolynomial.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/LabeledRationalFunction.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/NumberedPolynomial.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/NumberedRationalFunction.kt (100%) create mode 100644 kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/labeledConstructors.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/labeledUtil.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/numberedConstructors.kt (100%) rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions}/numberedUtil.kt (100%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt (94%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt (99%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt (99%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt (100%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt (99%) rename {kmath-functions => kmath-polynomialX}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt (99%) create mode 100644 test-utils-functions/build.gradle.kts rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/IntModulo.kt (70%) create mode 100644 test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/Rational.kt (77%) create mode 100644 test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/misc.kt (76%) create mode 100644 test-utils-polynomialX/build.gradle.kts create mode 100644 test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt rename {kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc => test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils}/assertion.kt (72%) create mode 100644 test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index fadbac091..0a8e8a1be 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -6,9 +6,16 @@ plugins { description = "Functions, integration and interpolation" -kotlin.sourceSets.commonMain { - dependencies { - api(project(":kmath-core")) +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + } + } + commonTest { + dependencies { + api(projects.testUtilsFunctions) + } } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index c4a7cc564..e7d8dfd8c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -7,7 +7,10 @@ package space.kscience.kmath.functions -import space.kscience.kmath.test.misc.* +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.ListPolynomial +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField import kotlin.test.* diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 685a2a506..339643d02 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -6,9 +6,9 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals @@ -64,7 +64,7 @@ class ListPolynomialUtilTest { ) assertEquals( Rational(25057, 21000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) .substitute(RationalField, Rational(1, 5)), "test 2" ) @@ -76,13 +76,13 @@ class ListPolynomialUtilTest { ) assertEquals( Rational(4961, 4200), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(4, 7), Rational(0)) + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) .substitute(RationalField, Rational(1, 5)), "test 4" ) assertEquals( Rational(3511, 3000), - ListPolynomial(Rational(5,8), Rational(8, 3), Rational(0), Rational(3, 2)) + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) .substitute(RationalField, Rational(1, 5)), "test 5" ) @@ -233,7 +233,7 @@ class ListPolynomialUtilTest { ListPolynomial( Rational(-13, 9), Rational(5, 3), - Rational(-5, 4) , + Rational(-5, 4), Rational(0), Rational(0), Rational(0), diff --git a/kmath-polynomialX/build.gradle.kts b/kmath-polynomialX/build.gradle.kts new file mode 100644 index 000000000..51b3c0665 --- /dev/null +++ b/kmath-polynomialX/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") +} + +description = "Polynomial extra utilities and rational functions" + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmathCore) + api(projects.kmathFunctions) + } + } + commonTest { + dependencies { + api(projects.testUtilsFunctions) + api(projects.testUtilsPolynomialX) + api(kotlin("test")) + } + } +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + +// feature("TODO") { "TODO" } +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt new file mode 100644 index 000000000..b40aa4775 --- /dev/null +++ b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt @@ -0,0 +1,146 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.* + + +// TODO: All of this should be moved to algebraic structures' place for utilities +// FIXME: Move receiver to context receiver +/** + * Returns product of [arg] and integer [multiplier]. + * + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal fun Group.multiplyByDoubling(arg: C, multiplier: Int): C = + if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt()) + else multiplyByDoubling(-arg, (-multiplier).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C = + if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt()) + else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Returns product of [arg] and integer [multiplier]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun Group.multiplyByDoubling(arg: C, multiplier: UInt): C = + when { + multiplier == 0u -> zero + multiplier == 1u -> arg + multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// FIXME: Move receiver to context receiver +/** + * Adds product of [arg] and [multiplier] to [base]. + * + * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) + * + * @param base the augend. + * @param arg the multiplicand. + * @param multiplier the integer multiplier. + * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. + * @author Gleb Minaev + */ +internal tailrec fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C = + when { + multiplier == 0u -> base + multiplier == 1u -> base + arg + multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1) + multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1) + else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") + } + +// FIXME: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal fun Field.exponentiateBySquaring(arg: C, exponent: Int): C = + if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt()) + else exponentiateBySquaring(one / arg, (-exponent).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Multiplies [base] and [arg] raised to the integer power [exponent]. + * + * @param base the multiplicand. + * @param arg the base of the power. + * @param exponent the exponent of the power. + * @return product of [base] and [arg] raised to the power [exponent]. + * @author Gleb Minaev + */ +internal fun Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = + if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) + else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) + +// FIXME: Move receiver to context receiver +/** + * Raises [arg] to the integer power [exponent]. + * + * 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.exponentiateBySquaring(arg: C, exponent: UInt): C = + when { + exponent == 0u -> zero + exponent == 1u -> arg + exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(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") + } + +// FIXME: 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.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: UInt): C = + when { + exponent == 0u -> base + exponent == 1u -> base * arg + exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1) + exponent and 1u == 1u -> multiplyExponentiatedBySquaring(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/labeledConstructors.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt rename to kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt similarity index 94% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt index edeaef6a7..081cf06e4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -6,19 +6,17 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke +import space.kscience.kmath.functions.testUtils.t +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.functions.testUtils.z import kotlin.test.Test import kotlin.test.assertEquals class LabeledConstructorsTest { - val x by symbol - val y by symbol - val z by symbol - val t by symbol - @Test @UnstableKMathAPI fun testDSL1() { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index 95481f2ef..d2d417a02 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -8,25 +8,22 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.test.misc.IntModuloRing -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.m +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.o +import space.kscience.kmath.functions.testUtils.m import kotlin.test.* +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.functions.testUtils.z +import space.kscience.kmath.functions.testUtils.t +import space.kscience.kmath.functions.testUtils.s +import space.kscience.kmath.functions.testUtils.iota // TODO: Тесты на конвертацию. class LabeledPolynomialTest { - val x by symbol - val y by symbol - val z by symbol - val t by symbol - val s by symbol - val iota by symbol - - val o = Rational(0) - @Test fun test_Variable_Int_plus() { RationalField.labeledPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index cdfe309f9..37329a318 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -6,20 +6,18 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertEquals +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.functions.testUtils.iota +import space.kscience.kmath.functions.testUtils.assertEquals class LabeledPolynomialUtilTest { - val x by symbol - val y by symbol - val iota by symbol - @Test fun test_Polynomial_substitute_Double() { assertEquals( diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt similarity index 100% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index 007c3e5e9..ec2e34520 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -7,10 +7,11 @@ package space.kscience.kmath.functions -import space.kscience.kmath.test.misc.IntModuloRing -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.m +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.m +import space.kscience.kmath.functions.testUtils.o import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertSame @@ -18,8 +19,6 @@ import kotlin.test.fail class NumberedPolynomialTest { - val o = Rational(0) - @Test fun test_Polynomial_Int_plus() { RationalField.numberedPolynomialSpace { diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt similarity index 99% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt rename to kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 1b87d3fcf..82f1e561a 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -6,19 +6,16 @@ package space.kscience.kmath.functions import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.test.misc.Rational -import space.kscience.kmath.test.misc.RationalField -import space.kscience.kmath.test.misc.assertEquals -import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals +import space.kscience.kmath.functions.testUtils.bufferOf +import space.kscience.kmath.functions.testUtils.assertEquals -fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() - class NumberedPolynomialUtilTest { @Test fun test_Polynomial_substitute_Double_Map() { diff --git a/settings.gradle.kts b/settings.gradle.kts index e3c621e9a..543d08001 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,9 @@ include( ":kmath-core", ":kmath-coroutines", ":kmath-functions", + ":test-utils-functions", + ":kmath-polynomialX", + ":test-utils-polynomialX", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", diff --git a/test-utils-functions/build.gradle.kts b/test-utils-functions/build.gradle.kts new file mode 100644 index 000000000..8476abecc --- /dev/null +++ b/test-utils-functions/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") + id("ru.mipt.npm.gradle.native") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmathCore) + api(projects.kmathFunctions) + api(kotlin("test")) + } + } +} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt similarity index 70% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt rename to test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index f6e8457bb..933c4dc4c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/IntModulo.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -5,40 +5,37 @@ @file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") -package space.kscience.kmath.test.misc +package space.kscience.kmath.functions.testUtils -import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.functions.PolynomialSpaceOverRing import space.kscience.kmath.operations.Ring -class IntModulo { - val residue: Int - val modulus: Int +public class IntModulo { + public val residue: Int + public val modulus: Int @PublishedApi internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { if (toCheckInput) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus - this.residue = residue.mod(modulus) + this.residue = residue.mod(this.modulus) } else { this.residue = residue this.modulus = modulus } } - constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - operator fun unaryPlus(): IntModulo = this - operator fun unaryMinus(): IntModulo = + public operator fun unaryPlus(): IntModulo = this + public operator fun unaryMinus(): IntModulo = IntModulo( if (residue == 0) 0 else modulus - residue, modulus, toCheckInput = false ) - operator fun plus(other: IntModulo): IntModulo { + public operator fun plus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not add two residue different modulo" } return IntModulo( (residue + other.residue) % modulus, @@ -46,13 +43,13 @@ class IntModulo { toCheckInput = false ) } - operator fun plus(other: Int): IntModulo = + public operator fun plus(other: Int): IntModulo = IntModulo( (residue + other) % modulus, modulus, toCheckInput = false ) - operator fun minus(other: IntModulo): IntModulo { + public operator fun minus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not subtract two residue different modulo" } return IntModulo( (residue - other.residue) % modulus, @@ -60,13 +57,13 @@ class IntModulo { toCheckInput = false ) } - operator fun minus(other: Int): IntModulo = + public operator fun minus(other: Int): IntModulo = IntModulo( (residue - other) % modulus, modulus, toCheckInput = false ) - operator fun times(other: IntModulo): IntModulo { + public operator fun times(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not multiply two residue different modulo" } return IntModulo( (residue * other.residue) % modulus, @@ -74,13 +71,13 @@ class IntModulo { toCheckInput = false ) } - operator fun times(other: Int): IntModulo = + public operator fun times(other: Int): IntModulo = IntModulo( (residue * other) % modulus, modulus, toCheckInput = false ) - operator fun div(other: IntModulo): IntModulo { + public operator fun div(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not divide two residue different modulo" } val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } @@ -90,7 +87,7 @@ class IntModulo { toCheckInput = false ) } - operator fun div(other: Int): IntModulo { + public operator fun div(other: Int): IntModulo { val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } return IntModulo( @@ -111,11 +108,11 @@ class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -class IntModuloRing : Ring { +public class IntModuloRing : Ring { - val modulus: Int + public val modulus: Int - constructor(modulus: Int) { + public constructor(modulus: Int) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus } @@ -123,7 +120,7 @@ class IntModuloRing : Ring { override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - fun number(arg: Int) = IntModulo(arg, modulus, toCheckInput = false) + public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right @@ -132,13 +129,5 @@ class IntModuloRing : Ring { override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg -} - -fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) - -fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus) -fun PolynomialSpaceOverRing.m(arg: Int) = IntModulo(arg, ring.modulus) \ No newline at end of file + public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt new file mode 100644 index 000000000..4b65fbea1 --- /dev/null +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -0,0 +1,19 @@ +/* + * 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.testUtils + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing + + +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt similarity index 77% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt rename to test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 731621658..27b0eb21e 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/Rational.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -5,21 +5,21 @@ @file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") -package space.kscience.kmath.test.misc +package space.kscience.kmath.functions.testUtils import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps @Suppress("NAME_SHADOWING") -class Rational { - companion object { - val ZERO: Rational = Rational(0L) - val ONE: Rational = Rational(1L) +public class Rational { + public companion object { + public val ZERO: Rational = Rational(0L) + public val ONE: Rational = Rational(1L) } - val numerator: Long - val denominator: Long + public val numerator: Long + public val denominator: Long internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { @@ -35,16 +35,16 @@ class Rational { } } - 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) + public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + public 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 { + public operator fun unaryPlus(): Rational = this + public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + public operator fun plus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -56,19 +56,19 @@ class Rational { toCheckInput = false ) } - operator fun plus(other: Int): Rational = + public operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), denominator, toCheckInput = false ) - operator fun plus(other: Long): Rational = + public operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator, toCheckInput = false ) - operator fun minus(other: Rational): Rational { + public operator fun minus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -80,19 +80,19 @@ class Rational { toCheckInput = false ) } - operator fun minus(other: Int): Rational = + public operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), denominator, toCheckInput = false ) - operator fun minus(other: Long): Rational = + public operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator, toCheckInput = false ) - operator fun times(other: Rational): Rational { + public operator fun times(other: Rational): Rational { val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) return Rational( @@ -101,7 +101,7 @@ class Rational { toCheckInput = false ) } - operator fun times(other: Int): Rational { + public operator fun times(other: Int): Rational { val other = other.toLong() val denominatorAndOtherGcd = gcd(denominator, other) return Rational( @@ -110,7 +110,7 @@ class Rational { toCheckInput = false ) } - operator fun times(other: Long): Rational { + public operator fun times(other: Long): Rational { val denominatorAndOtherGcd = gcd(denominator, other) return Rational( numerator * (other / denominatorAndOtherGcd), @@ -118,7 +118,7 @@ class Rational { toCheckInput = false ) } - operator fun div(other: Rational): Rational { + public operator fun div(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val numeratorsGcd = gcd(numerator, other.numerator) return Rational( @@ -126,7 +126,7 @@ class Rational { (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) } - operator fun div(other: Int): Rational { + public operator fun div(other: Int): Rational { val other = other.toLong() val numeratorAndOtherGcd = gcd(numerator, other) return Rational( @@ -135,7 +135,7 @@ class Rational { toCheckInput = false ) } - operator fun div(other: Long): Rational { + public operator fun div(other: Long): Rational { val numeratorAndOtherGcd = gcd(numerator, other) return Rational( numerator / numeratorAndOtherGcd, @@ -158,7 +158,7 @@ class Rational { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -object RationalField : Field, NumbersAddOps { +public object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt new file mode 100644 index 000000000..5cf82996f --- /dev/null +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -0,0 +1,22 @@ +/* + * 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.testUtils + +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + + +public inline fun assertFailsWithTypeAndMessage( + expectedMessage: String? = null, + assertionMessage: String? = null, + block: () -> Unit +) { + assertEquals( + expectedMessage, + assertFailsWith(T::class, assertionMessage, block).message, + assertionMessage + ) +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 76% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt rename to test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt index ed41b9245..ff67f19d8 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/misc.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -3,16 +3,16 @@ * 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 +package space.kscience.kmath.functions.testUtils import kotlin.math.abs -data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) +internal data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) -tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) +internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) -fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = +internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = when { a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } diff --git a/test-utils-polynomialX/build.gradle.kts b/test-utils-polynomialX/build.gradle.kts new file mode 100644 index 000000000..f20e1b8bb --- /dev/null +++ b/test-utils-polynomialX/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") + id("ru.mipt.npm.gradle.native") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(projects.kmathCore) + api(projects.kmathFunctions) + api(projects.testUtilsFunctions) + api(projects.kmathPolynomialX) + api(kotlin("test")) + } + } +} diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt new file mode 100644 index 000000000..afd26dd36 --- /dev/null +++ b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt @@ -0,0 +1,12 @@ +/* + * 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.testUtils + +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + + +public fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt similarity index 72% rename from kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt rename to test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 85180bd2a..9ca5f43a3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/test/misc/assertion.kt +++ b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -3,7 +3,7 @@ * 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 +package space.kscience.kmath.functions.testUtils import space.kscience.kmath.functions.LabeledPolynomial import space.kscience.kmath.functions.LabeledRationalFunction @@ -13,36 +13,45 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -fun assertContentEquals(expected: Map, actual: Map, absoluteTolerance: Double, message: String? = null) { +public fun assertContentEquals( + expected: Map, + actual: Map, + absoluteTolerance: Double, + message: String? = null +) { assertEquals(expected.keys, actual.keys, message) for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) } -fun assertEquals( +public fun assertEquals( expected: NumberedPolynomial, actual: NumberedPolynomial, absoluteTolerance: Double, message: String? = null -) = assertContentEquals( - expected.coefficients, - actual.coefficients, - absoluteTolerance, - message -) +) { + assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message + ) +} -fun assertEquals( +public fun assertEquals( expected: LabeledPolynomial, actual: LabeledPolynomial, absoluteTolerance: Double, message: String? = null -) = assertContentEquals( - expected.coefficients, - actual.coefficients, - absoluteTolerance, - message -) +) { + assertContentEquals( + expected.coefficients, + actual.coefficients, + absoluteTolerance, + message + ) +} -fun assertEquals( +public fun assertEquals( expected: NumberedRationalFunction, actual: NumberedRationalFunction, absoluteTolerance: Double, @@ -62,7 +71,7 @@ fun assertEquals( ) } -fun assertEquals( +public fun assertEquals( expected: LabeledRationalFunction, actual: LabeledRationalFunction, absoluteTolerance: Double, @@ -82,13 +91,15 @@ fun assertEquals( ) } -inline fun assertFailsWithTypeAndMessage( +// FIXME: Don't understand why but the same function from test-utils-functions module can not be used +public inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, block: () -> Unit -) = +) { assertEquals( expectedMessage, assertFailsWith(T::class, assertionMessage, block).message, assertionMessage - ) \ No newline at end of file + ) +} \ No newline at end of file diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt new file mode 100644 index 000000000..051fc0f37 --- /dev/null +++ b/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -0,0 +1,19 @@ +/* + * 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.testUtils + +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.symbol + + +public val o: Rational = Rational(0) + +public val x: Symbol by symbol +public val y: Symbol by symbol +public val z: Symbol by symbol +public val t: Symbol by symbol +public val s: Symbol by symbol +public val iota: Symbol by symbol \ No newline at end of file From 1c719b9e709ec07920545a99db6c7c9f274b8908 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:52:46 +0300 Subject: [PATCH 114/174] Fix examples. --- examples/build.gradle.kts | 2 ++ .../main/kotlin/space/kscience/kmath/functions/polynomials.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 60f8f5aed..67b28cd85 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -15,6 +15,8 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) + implementation(project(":kmath-functions")) + implementation(project(":kmath-polynomialX")) implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index 7843a0210..4151b0283 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("LocalVariableName") + package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol From 51dd72e48f2043a00bc2a5da75dbf8b6c1c2039b Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 22:39:13 +0300 Subject: [PATCH 115/174] Finish move. --- examples/build.gradle.kts | 2 +- .../build.gradle.kts | 4 +- .../LabeledPolynomial.kt | 0 .../LabeledRationalFunction.kt | 0 .../ListPolynomial.kt | 387 ++++++++++++++ .../ListRationalFunction.kt | 0 .../NumberedPolynomial.kt | 0 .../NumberedRationalFunction.kt | 0 .../Polynomial.kt | 502 ++++++++++++++++++ .../RationalFunction.kt | 3 +- .../algebraicStub.kt | 0 .../labeledConstructors.kt | 0 .../labeledUtil.kt | 2 +- .../listConstructors.kt | 92 ++++ .../listUtil.kt | 255 +++++++++ .../space.kscience.kmath.functions/misc.kt | 22 + .../numberedConstructors.kt | 0 .../numberedUtil.kt | 0 .../functions/LabeledConstructorsTest.kt | 6 +- .../kmath/functions/LabeledPolynomialTest.kt | 10 +- .../functions/LabeledPolynomialUtilTest.kt | 9 +- .../functions/NumberedConstructorsTest.kt | 0 .../kmath/functions/NumberedPolynomialTest.kt | 0 .../functions/NumberedPolynomialUtilTest.kt | 0 settings.gradle.kts | 4 +- .../build.gradle.kts | 4 +- .../kmath/functions/testUtils/BufferUtils.kt | 0 .../kmath/functions/testUtils/assertion.kt | 0 .../kmath/functions/testUtils/misc.kt | 0 29 files changed, 1278 insertions(+), 24 deletions(-) rename {kmath-polynomialX => kmath-polynomial}/build.gradle.kts (81%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt (100%) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions}/ListRationalFunction.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt (100%) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt rename {kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions => kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions}/RationalFunction.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt (99%) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt (99%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt (100%) rename {kmath-polynomialX => kmath-polynomial}/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt (100%) rename {test-utils-polynomialX => test-utils-polynomial}/build.gradle.kts (63%) rename {test-utils-polynomialX => test-utils-polynomial}/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt (100%) rename {test-utils-polynomialX => test-utils-polynomial}/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt (100%) rename {test-utils-polynomialX => test-utils-polynomial}/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt (100%) diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 67b28cd85..aa5c1f47a 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -16,7 +16,7 @@ dependencies { implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) implementation(project(":kmath-functions")) - implementation(project(":kmath-polynomialX")) + implementation(project(":kmath-polynomial")) implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) diff --git a/kmath-polynomialX/build.gradle.kts b/kmath-polynomial/build.gradle.kts similarity index 81% rename from kmath-polynomialX/build.gradle.kts rename to kmath-polynomial/build.gradle.kts index 51b3c0665..dcfcb1b46 100644 --- a/kmath-polynomialX/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -10,13 +10,11 @@ kotlin.sourceSets { commonMain { dependencies { api(projects.kmathCore) - api(projects.kmathFunctions) } } commonTest { dependencies { - api(projects.testUtilsFunctions) - api(projects.testUtilsPolynomialX) + api(projects.testUtilsPolynomial) api(kotlin("test")) } } diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt new file mode 100644 index 000000000..76e1a6bb6 --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -0,0 +1,387 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke +import kotlin.math.max +import kotlin.math.min + + +/** + * Represents univariate polynomial that stores its coefficients in a [List]. + * + * @param C the type of constants. + */ +public data class ListPolynomial( + /** + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. + */ + public val coefficients: List +) : Polynomial { + override fun toString(): String = "ListPolynomial$coefficients" +} + +/** + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public open class ListPolynomialSpace>( + public override val ring: A, +) : PolynomialSpaceOverRing, A> { + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } + other + + if(size == 0) add(result) + else this[0] = result + } + ) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = + if (other == 0) this + else + ListPolynomial( + coefficients + .toMutableList() + .apply { + val result = getOrElse(0) { constantZero } - other + + if(size == 0) add(result) + else this[0] = result + } + ) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun ListPolynomial.times(other: Int): ListPolynomial = + when (other) { + 0 -> zero + 1 -> this + else -> ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = + if (this == 0) other + else + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + val result = this@plus + getOrElse(0) { constantZero } + + if(size == 0) add(result) + else this[0] = result + } + ) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + if (this@minus == 0) { + indices.forEach { this[it] = -this[it] } + } else { + (1..lastIndex).forEach { this[it] = -this[it] } + + val result = this@minus - getOrElse(0) { constantZero } + + if (size == 0) add(result) + else this[0] = result + } + } + ) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: ListPolynomial): ListPolynomial = + when (this) { + 0 -> zero + 1 -> other + else -> ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public override operator fun C.plus(other: ListPolynomial): ListPolynomial = + with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@plus)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) this@plus else this@plus + get(0) + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public override operator fun C.minus(other: ListPolynomial): ListPolynomial = + with(other.coefficients) { + if (isEmpty()) ListPolynomial(listOf(this@minus)) + else ListPolynomial( + toMutableList() + .apply { + (1 .. lastIndex).forEach { this[it] = -this[it] } + + val result = if (size == 0) this@minus else this@minus - get(0) + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public override operator fun C.times(other: ListPolynomial): ListPolynomial = + ListPolynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public override operator fun ListPolynomial.plus(other: C): ListPolynomial = + with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) + other + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public override operator fun ListPolynomial.minus(other: C): ListPolynomial = + with(coefficients) { + if (isEmpty()) ListPolynomial(listOf(-other)) + else ListPolynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) - other + + if(size == 0) add(result) + else this[0] = result + } + ) + } + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public override operator fun ListPolynomial.times(other: C): ListPolynomial = + ListPolynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + + /** + * Converts the constant [value] to polynomial. + */ + public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) + + /** + * Returns negation of the polynomial. + */ + public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = + ListPolynomial(coefficients.map { -it }) + /** + * Returns sum of the polynomials. + */ + public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + ) + } + /** + * Returns difference of the polynomials. + */ + public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + ) + } + /** + * Returns product of the polynomials. + */ + public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { + val thisDegree = degree + val otherDegree = other.degree + return ListPolynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) + } + /** + * Raises [arg] to the integer power [exponent]. + */ // TODO: To optimize boxing + override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + override val zero: ListPolynomial = ListPolynomial(emptyList()) + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public override val ListPolynomial.degree: Int get() = coefficients.lastIndex + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) + /** + * Substitutes provided polynomial [argument] into [this] polynomial. + */ + public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) +} + +/** + * Space of polynomials constructed over ring. + * + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: ListPolynomial, value: Double): ListPolynomial = + ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } +} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt similarity index 100% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt new file mode 100644 index 000000000..61ea5a342 --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt @@ -0,0 +1,502 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke +import kotlin.js.JsName +import kotlin.jvm.JvmName + + +/** + * Abstraction of polynomials. + */ +public interface Polynomial + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 +public interface PolynomialSpace> : Ring

{ + /** + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public operator fun C.plus(other: Int): C + /** + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public operator fun C.minus(other: Int): C + /** + * Returns product of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun C.times(other: Int): C + + /** + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public operator fun Int.plus(other: C): C + /** + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public operator fun Int.minus(other: C): C + /** + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: C): C + + /** + * Converts the integer [value] to constant. + */ + public fun constantNumber(value: Int): C = constantOne * value + /** + * Converts the integer to constant. + */ + public fun Int.asConstant(): C = constantNumber(this) + + /** + * Returns sum of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to adding [other] copies of unit polynomial to [this]. + */ + public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) + /** + * Returns difference between the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. + */ + public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) + /** + * Returns product of the polynomial and the integer represented as a polynomial. + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) + + /** + * Returns sum of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to adding [this] copies of unit polynomial to [other]. + */ + public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) + /** + * Returns difference between the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. + */ + public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) + /** + * Returns product of the integer represented as a polynomial and the polynomial. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) + + /** + * Converts the integer [value] to polynomial. + */ + public fun number(value: Int): P = number(constantNumber(value)) + /** + * Converts the integer to polynomial. + */ + public fun Int.asPolynomial(): P = number(this) + + /** + * Returns the same constant. + */ + @JvmName("unaryPlusConstant") + @JsName("unaryPlusConstant") + public operator fun C.unaryPlus(): C = this + /** + * Returns negation of the constant. + */ + @JvmName("unaryMinusConstant") + @JsName("unaryMinusConstant") + public operator fun C.unaryMinus(): C + /** + * Returns sum of the constants. + */ + @JvmName("plusConstantConstant") + @JsName("plusConstantConstant") + public operator fun C.plus(other: C): C + /** + * Returns difference of the constants. + */ + @JvmName("minusConstantConstant") + @JsName("minusConstantConstant") + public operator fun C.minus(other: C): C + /** + * Returns product of the constants. + */ + @JvmName("timesConstantConstant") + @JsName("timesConstantConstant") + public operator fun C.times(other: C): C + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("powerConstant") + @JsName("powerConstant") + public fun power(arg: C, exponent: UInt) : C + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public val constantZero: C + /** + * Instance of unit constant (unit of the underlying ring). + */ + public val constantOne: C + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public operator fun C.plus(other: P): P + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public operator fun C.minus(other: P): P + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public operator fun C.times(other: P): P + + /** + * Returns sum of the constant represented as a polynomial and the polynomial. + */ + public operator fun P.plus(other: C): P + /** + * Returns difference between the constant represented as a polynomial and the polynomial. + */ + public operator fun P.minus(other: C): P + /** + * Returns product of the constant represented as a polynomial and the polynomial. + */ + public operator fun P.times(other: C): P + + /** + * Converts the constant [value] to polynomial. + */ + public fun number(value: C): P = one * value + /** + * Converts the constant to polynomial. + */ + public fun C.asPolynomial(): P = number(this) + + /** + * Returns the same polynomial. + */ + public override operator fun P.unaryPlus(): P = this + /** + * Returns negation of the polynomial. + */ + public override operator fun P.unaryMinus(): P + /** + * Returns sum of the polynomials. + */ + public override operator fun P.plus(other: P): P + /** + * Returns difference of the polynomials. + */ + public override operator fun P.minus(other: P): P + /** + * 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 = exponentiateBySquaring(arg, exponent) + + /** + * Instance of zero polynomial (zero of the polynomial ring). + */ + public override val zero: P + /** + * Instance of unit polynomial (unit of the polynomial ring). + */ + public override val one: P + + /** + * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is + * zero, degree is -1. + */ + public val P.degree: Int + + override fun add(left: P, right: P): P = left + right + override fun multiply(left: P, right: P): P = left * right +} + +/** + * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is + * provided [ring] (of type [A]), that provides constant-wise operations. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param P the type of polynomials. + * @param A the type of algebraic structure (precisely, of ring) provided for constants. + */ +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 +public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { + + /** + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + */ + public val ring: A + + /** + * Returns sum of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + */ + public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } + /** + * Returns difference between the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. + */ + public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } + /** + * Returns product of the constant and the integer represented as a constant (member of underlying ring). + * + * The operation is equivalent to sum of [other] copies of [this]. + */ + public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } + + /** + * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + */ + public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } + /** + * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. + */ + public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } + /** + * Returns product of the integer represented as a constant (member of underlying ring) and the constant. + * + * The operation is equivalent to sum of [this] copies of [other]. + */ + public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } + + /** + * Returns negation of the constant. + */ + @JvmName("unaryMinusConstant") + public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } + /** + * Returns sum of the constants. + */ + @JvmName("plusConstantConstant") + public override operator fun C.plus(other: C): C = ring { this@plus + other } + /** + * Returns difference of the constants. + */ + @JvmName("minusConstantConstant") + public override operator fun C.minus(other: C): C = ring { this@minus - other } + /** + * Returns product of the constants. + */ + @JvmName("timesConstantConstant") + public override operator fun C.times(other: C): C = ring { this@times * other } + /** + * Raises [arg] to the integer power [exponent]. + */ + @JvmName("powerConstant") + override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } + + /** + * Instance of zero constant (zero of the underlying ring). + */ + public override val constantZero: C get() = ring.zero + /** + * Instance of unit constant (unit of the underlying ring). + */ + public override val constantOne: C get() = ring.one +} + +/** + * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. + * + * @param C the type of constants. Polynomials have them as coefficients in their terms. + * @param V the type of variables. Polynomials have them in representations of terms. + * @param P the type of polynomials. + */ +@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 +public interface MultivariatePolynomialSpace>: PolynomialSpace { + /** + * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + @JvmName("plusVariableInt") + public operator fun V.plus(other: Int): P + /** + * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + @JvmName("minusVariableInt") + public operator fun V.minus(other: Int): P + /** + * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. + */ + @JvmName("timesVariableInt") + public operator fun V.times(other: Int): P + + /** + * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusIntVariable") + public operator fun Int.plus(other: V): P + /** + * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusIntVariable") + public operator fun Int.minus(other: V): P + /** + * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesIntVariable") + public operator fun Int.times(other: V): P + + /** + * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + @JvmName("plusVariableConstant") + public operator fun V.plus(other: C): P + /** + * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + @JvmName("minusVariableConstant") + public operator fun V.minus(other: C): P + /** + * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. + */ + @JvmName("timesVariableConstant") + public operator fun V.times(other: C): P + + /** + * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusConstantVariable") + public operator fun C.plus(other: V): P + /** + * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusConstantVariable") + public operator fun C.minus(other: V): P + /** + * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesConstantVariable") + public operator fun C.times(other: V): P + + /** + * Represents the variable as a monic monomial. + */ + @JvmName("unaryPlusVariable") + public operator fun V.unaryPlus(): P + /** + * Returns negation of representation of the variable as a monic monomial. + */ + @JvmName("unaryMinusVariable") + public operator fun V.unaryMinus(): P + /** + * Returns sum of the variables represented as monic monomials. + */ + @JvmName("plusVariableVariable") + public operator fun V.plus(other: V): P + /** + * Returns difference between the variables represented as monic monomials. + */ + @JvmName("minusVariableVariable") + public operator fun V.minus(other: V): P + /** + * Returns product of the variables represented as monic monomials. + */ + @JvmName("timesVariableVariable") + public operator fun V.times(other: V): P + + /** + * Represents the [variable] as a monic monomial. + */ + @JvmName("numberVariable") + public fun number(variable: V): P = +variable + /** + * Represents the variable as a monic monomial. + */ + @JvmName("asPolynomialVariable") + public fun V.asPolynomial(): P = number(this) + + /** + * Returns sum of the variable represented as a monic monomial and the polynomial. + */ + @JvmName("plusVariablePolynomial") + public operator fun V.plus(other: P): P + /** + * Returns difference between the variable represented as a monic monomial and the polynomial. + */ + @JvmName("minusVariablePolynomial") + public operator fun V.minus(other: P): P + /** + * Returns product of the variable represented as a monic monomial and the polynomial. + */ + @JvmName("timesVariablePolynomial") + public operator fun V.times(other: P): P + + /** + * Returns sum of the polynomial and the variable represented as a monic monomial. + */ + @JvmName("plusPolynomialVariable") + public operator fun P.plus(other: V): P + /** + * Returns difference between the polynomial and the variable represented as a monic monomial. + */ + @JvmName("minusPolynomialVariable") + public operator fun P.minus(other: V): P + /** + * Returns product of the polynomial and the variable represented as a monic monomial. + */ + @JvmName("timesPolynomialVariable") + public operator fun P.times(other: V): P + + /** + * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents + * in which they are appeared in the polynomial. + * + * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. + * And keys of the map is the same as in [variables]. + */ + public val P.degrees: Map + /** + * Counts degree of the polynomial by the specified [variable]. + */ + public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } + /** + * Counts degree of the polynomial by the specified [variables]. + */ + public fun P.degreeBy(variables: Collection): UInt + /** + * Set of all variables that appear in the polynomial in positive exponents. + */ + public val P.variables: Set get() = degrees.keys + /** + * Count of all variables that appear in the polynomial in positive exponents. + */ + public val P.countOfVariables: Int get() = variables.size +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt similarity index 99% rename from kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt index 1782dba74..f664ae9db 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt @@ -5,7 +5,8 @@ package space.kscience.kmath.functions -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import kotlin.js.JsName import kotlin.jvm.JvmName diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt similarity index 99% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt index 4e799cb43..e3b35facc 100644 --- a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt @@ -8,9 +8,9 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmName diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt new file mode 100644 index 000000000..e95361724 --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.operations.Ring + + +/** + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = + ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +/** + * Represents [this] constant as a [ListPolynomial]. + */ +public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) + + +// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available + +/** + * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided + * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if + * [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) + ) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, ListPolynomial(listOf(one))) +/** + * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = + ListRationalFunction(numerator, polynomialOne) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + ListPolynomial(listOf(one)) + ) +/** + * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit + * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = + ListRationalFunction( + ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), + polynomialOne + ) + +/** + * Represents [this] constant as a rational function. + */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two +public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ +//context(A) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) +///** +// * Represents [this] constant as a rational function. +// */ +//context(ListRationalFunctionSpace) +//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt new file mode 100644 index 000000000..4f3f6d88e --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt @@ -0,0 +1,255 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + +/** + * Creates a [ListRationalFunctionSpace] over a received ring. + */ +public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace + get() = ListRationalFunctionSpace(this) + +/** + * Creates a [ListRationalFunctionSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListRationalFunctionSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun ListPolynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Substitutes provided polynomial [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = + ring.listPolynomialSpace { + if (coefficients.isEmpty()) return zero + var result: ListPolynomial = coefficients.last().asPolynomial() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Substitutes provided rational function [arg] into [this] polynomial. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ // TODO: To optimize boxing +public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + if (coefficients.isEmpty()) return zero + var result: ListRationalFunction = coefficients.last().asRationalFunction() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result + } + +/** + * Evaluates value of [this] Double rational function in provided Double argument. + */ +public fun ListRationalFunction.substitute(arg: Double): Double = + numerator.substitute(arg) / denominator.substitute(arg) + +/** + * Evaluates value of [this] polynomial for provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) +} + +/** + * Substitutes provided polynomial [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Substitutes provided rational function [arg] into [this] rational function. + */ // TODO: To optimize boxing +public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = + ring.listRationalFunctionSpace { + numerator.substitute(ring, arg) / denominator.substitute(ring, arg) + } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Represent [this] rational function as a regular context-less function. + */ +public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.derivative( + ring: A, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + ListPolynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthDerivative( + ring: A, + order: Int, +): ListPolynomial where A : Ring, A : NumericAlgebra = ring { + require(order >= 0) { "Order of derivative must be non-negative" } + ListPolynomial( + buildList(max(0, coefficients.size - order)) { + for (deg in order.. coefficients.lastIndex) + add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun ListPolynomial.antiderivative( + ring: A, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + ListPolynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. + */ +@UnstableKMathAPI +public fun ListPolynomial.nthAntiderivative( + ring: A, + order: Int, +): ListPolynomial where A : Field, A : NumericAlgebra = ring { + require(order >= 0) { "Order of antiderivative must be non-negative" } + ListPolynomial( + buildList(coefficients.size + order) { + repeat(order) { add(zero) } + coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > ListPolynomial.integrate( + ring: Field, + range: ClosedRange, +): C = ring { + val antiderivative = antiderivative(ring) + antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) +} \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt new file mode 100644 index 000000000..76f1c294e --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + + +/** + * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to + * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is + * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. + */ +@RequiresOptIn( + message = "This declaration gives access to delicate internal structure of polynomials. " + + "It allows to optimize performance by skipping unnecessary arguments check. " + + "But at the same time makes it easy to make a mistake " + + "that will cause wrong computation result or even runtime error. " + + "Make sure you fully read and understand documentation.", + level = RequiresOptIn.Level.ERROR +) +public annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt diff --git a/kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt similarity index 100% rename from kmath-polynomialX/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt similarity index 99% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt index 081cf06e4..80476050b 100644 --- a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -6,13 +6,13 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.invoke import space.kscience.kmath.functions.testUtils.t import space.kscience.kmath.functions.testUtils.x import space.kscience.kmath.functions.testUtils.y import space.kscience.kmath.functions.testUtils.z +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.algebra +import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt similarity index 99% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index d2d417a02..bde1386da 100644 --- a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -11,15 +11,15 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.functions.testUtils.IntModuloRing import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.functions.testUtils.o +import space.kscience.kmath.functions.testUtils.iota import space.kscience.kmath.functions.testUtils.m -import kotlin.test.* +import space.kscience.kmath.functions.testUtils.o +import space.kscience.kmath.functions.testUtils.s +import space.kscience.kmath.functions.testUtils.t import space.kscience.kmath.functions.testUtils.x import space.kscience.kmath.functions.testUtils.y import space.kscience.kmath.functions.testUtils.z -import space.kscience.kmath.functions.testUtils.t -import space.kscience.kmath.functions.testUtils.s -import space.kscience.kmath.functions.testUtils.iota +import kotlin.test.* // TODO: Тесты на конвертацию. diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt similarity index 99% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index 37329a318..88ee1cbb8 100644 --- a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -6,16 +6,15 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.iota +import space.kscience.kmath.functions.testUtils.x +import space.kscience.kmath.functions.testUtils.y +import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals -import space.kscience.kmath.functions.testUtils.x -import space.kscience.kmath.functions.testUtils.y -import space.kscience.kmath.functions.testUtils.iota -import space.kscience.kmath.functions.testUtils.assertEquals class LabeledPolynomialUtilTest { @Test diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt similarity index 100% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt similarity index 100% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt diff --git a/kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt similarity index 100% rename from kmath-polynomialX/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 543d08001..bdd83d04e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,8 +27,8 @@ include( ":kmath-coroutines", ":kmath-functions", ":test-utils-functions", - ":kmath-polynomialX", - ":test-utils-polynomialX", + ":kmath-polynomial", + ":test-utils-polynomial", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", diff --git a/test-utils-polynomialX/build.gradle.kts b/test-utils-polynomial/build.gradle.kts similarity index 63% rename from test-utils-polynomialX/build.gradle.kts rename to test-utils-polynomial/build.gradle.kts index f20e1b8bb..e10e1f2b1 100644 --- a/test-utils-polynomialX/build.gradle.kts +++ b/test-utils-polynomial/build.gradle.kts @@ -7,9 +7,7 @@ kotlin.sourceSets { commonMain { dependencies { api(projects.kmathCore) - api(projects.kmathFunctions) - api(projects.testUtilsFunctions) - api(projects.kmathPolynomialX) + api(projects.kmathPolynomial) api(kotlin("test")) } } diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt similarity index 100% rename from test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt rename to test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt similarity index 100% rename from test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt rename to test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt diff --git a/test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 100% rename from test-utils-polynomialX/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt rename to test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt From f726e6d0f17698dd47d6060212c8a6a04257f726 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Mon, 11 Jul 2022 23:32:15 +0300 Subject: [PATCH 116/174] Minimise appearance of new feature, leave only upgrades. --- .../kmath/functions/ListPolynomial.kt | 387 -------- .../kscience/kmath/functions/Piecewise.kt | 22 +- .../kscience/kmath/functions/Polynomial.kt | 629 +++++-------- .../kscience/kmath/functions/algebraicStub.kt | 95 -- .../kmath/functions/listConstructors.kt | 92 -- .../kscience/kmath/functions/listUtil.kt | 255 ------ .../space/kscience/kmath/functions/misc.kt | 22 - .../kmath/functions/polynomialConstructors.kt | 28 + .../kmath/functions/polynomialUtil.kt | 111 +++ .../kmath/functions/AlgebraicStubTest.kt | 460 ---------- .../kmath/functions/ListPolynomialTest.kt | 251 +----- .../kmath/functions/ListPolynomialUtilTest.kt | 850 +----------------- .../functions/testUtils/IntModuloUtils.kt | 13 +- 13 files changed, 376 insertions(+), 2839 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt create mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt deleted file mode 100644 index 76e1a6bb6..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import kotlin.math.max -import kotlin.math.min - - -/** - * Represents univariate polynomial that stores its coefficients in a [List]. - * - * @param C the type of constants. - */ -public data class ListPolynomial( - /** - * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed - * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * ) - * ``` - * and also as - * ``` - * listOf( - * -6, // -6 + - * 0, // 0 x + - * 5, // 5 x^2 - * 0, // 0 x^3 - * 0, // 0 x^4 - * ) - * ``` - * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the - * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is - * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. - */ - public val coefficients: List -) : Polynomial { - override fun toString(): String = "ListPolynomial$coefficients" -} - -/** - * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided - * [ring] of constants. - * - * @param C the type of constants. Polynomials have them a coefficients in their terms. - * @param A type of provided underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public open class ListPolynomialSpace>( - public override val ring: A, -) : PolynomialSpaceOverRing, A> { - /** - * Returns sum of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public override operator fun ListPolynomial.plus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } + other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public override operator fun ListPolynomial.minus(other: Int): ListPolynomial = - if (other == 0) this - else - ListPolynomial( - coefficients - .toMutableList() - .apply { - val result = getOrElse(0) { constantZero } - other - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns product of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun ListPolynomial.times(other: Int): ListPolynomial = - when (other) { - 0 -> zero - 1 -> this - else -> ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - } - - /** - * Returns sum of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public override operator fun Int.plus(other: ListPolynomial): ListPolynomial = - if (this == 0) other - else - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - val result = this@plus + getOrElse(0) { constantZero } - - if(size == 0) add(result) - else this[0] = result - } - ) - /** - * Returns difference between the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public override operator fun Int.minus(other: ListPolynomial): ListPolynomial = - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - if (this@minus == 0) { - indices.forEach { this[it] = -this[it] } - } else { - (1..lastIndex).forEach { this[it] = -this[it] } - - val result = this@minus - getOrElse(0) { constantZero } - - if (size == 0) add(result) - else this[0] = result - } - } - ) - /** - * Returns product of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: ListPolynomial): ListPolynomial = - when (this) { - 0 -> zero - 1 -> other - else -> ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - } - - /** - * Returns sum of the constant represented as a polynomial and the polynomial. - */ - public override operator fun C.plus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@plus)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) this@plus else this@plus + get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as a polynomial and the polynomial. - */ - public override operator fun C.minus(other: ListPolynomial): ListPolynomial = - with(other.coefficients) { - if (isEmpty()) ListPolynomial(listOf(this@minus)) - else ListPolynomial( - toMutableList() - .apply { - (1 .. lastIndex).forEach { this[it] = -this[it] } - - val result = if (size == 0) this@minus else this@minus - get(0) - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as a polynomial and the polynomial. - */ - public override operator fun C.times(other: ListPolynomial): ListPolynomial = - ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } - ) - - /** - * Returns sum of the constant represented as a polynomial and the polynomial. - */ - public override operator fun ListPolynomial.plus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) + other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns difference between the constant represented as a polynomial and the polynomial. - */ - public override operator fun ListPolynomial.minus(other: C): ListPolynomial = - with(coefficients) { - if (isEmpty()) ListPolynomial(listOf(-other)) - else ListPolynomial( - toMutableList() - .apply { - val result = if (size == 0) other else get(0) - other - - if(size == 0) add(result) - else this[0] = result - } - ) - } - /** - * Returns product of the constant represented as a polynomial and the polynomial. - */ - public override operator fun ListPolynomial.times(other: C): ListPolynomial = - ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } - ) - - /** - * Converts the constant [value] to polynomial. - */ - public override fun number(value: C): ListPolynomial = ListPolynomial(listOf(value)) - - /** - * Returns negation of the polynomial. - */ - public override operator fun ListPolynomial.unaryMinus(): ListPolynomial = - ListPolynomial(coefficients.map { -it }) - /** - * Returns sum of the polynomials. - */ - public override operator fun ListPolynomial.plus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } - } - ) - } - /** - * Returns difference of the polynomials. - */ - public override operator fun ListPolynomial.minus(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } - } - ) - } - /** - * Returns product of the polynomials. - */ - public override operator fun ListPolynomial.times(other: ListPolynomial): ListPolynomial { - val thisDegree = degree - val otherDegree = other.degree - return ListPolynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } - /** - * Raises [arg] to the integer power [exponent]. - */ // TODO: To optimize boxing - override fun power(arg: ListPolynomial, exponent: UInt): ListPolynomial = super.power(arg, exponent) - - /** - * Instance of zero polynomial (zero of the polynomial ring). - */ - override val zero: ListPolynomial = ListPolynomial(emptyList()) - /** - * Instance of unit polynomial (unit of the polynomial ring). - */ - override val one: ListPolynomial by lazy { ListPolynomial(listOf(constantOne)) } - - /** - * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is - * zero, degree is -1. - */ - public override val ListPolynomial.degree: Int get() = coefficients.lastIndex - - // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with - // [ListPolynomialSpace] as a context receiver - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline fun ListPolynomial.substitute(argument: C): C = substitute(ring, argument) - /** - * Substitutes provided polynomial [argument] into [this] polynomial. - */ - public inline fun ListPolynomial.substitute(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) - - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunction(): (C) -> C = asFunctionOver(ring) - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunctionOfConstant(): (C) -> C = asFunctionOfConstantOver(ring) - /** - * Represent [this] polynomial as a regular context-less function. - */ - public inline fun ListPolynomial.asFunctionOfPolynomial(): (ListPolynomial) -> ListPolynomial = asFunctionOfPolynomialOver(ring) - - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun ListPolynomial.invoke(argument: C): C = substitute(ring, argument) - /** - * Evaluates value of [this] polynomial on provided [argument]. - */ - public inline operator fun ListPolynomial.invoke(argument: ListPolynomial): ListPolynomial = substitute(ring, argument) -} - -/** - * Space of polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public class ScalableListPolynomialSpace( - ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: ListPolynomial, value: Double): ListPolynomial = - ring { ListPolynomial(a.coefficients.map { scale(it, value) }) } -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 612b00535..cfd21d552 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -27,10 +27,10 @@ public fun interface Piecewise { * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no * "holes" in it. */ -public interface PiecewisePolynomial> : Piecewise> { - public val pieces: Collection, ListPolynomial>> +public interface PiecewisePolynomial> : Piecewise> { + public val pieces: Collection, Polynomial>> - override fun findPiece(arg: T): ListPolynomial? + override fun findPiece(arg: T): Polynomial? } /** @@ -38,11 +38,11 @@ public interface PiecewisePolynomial> : Piecewise> PiecewisePolynomial( - pieces: Collection, ListPolynomial>>, + pieces: Collection, Polynomial>>, ): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, ListPolynomial>> = pieces + override val pieces: Collection, Polynomial>> = pieces - override fun findPiece(arg: T): ListPolynomial? = pieces.firstOrNull { arg in it.first }?.second + override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second } /** @@ -50,10 +50,10 @@ public fun > PiecewisePolynomial( * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( - override val pieces: List, ListPolynomial>>, + override val pieces: List, Polynomial>>, ) : PiecewisePolynomial { - override fun findPiece(arg: T): ListPolynomial? { + override fun findPiece(arg: T): Polynomial? { val index = pieces.binarySearch { (range, _) -> when { arg >= range.endInclusive -> -1 @@ -74,7 +74,7 @@ private class OrderedPiecewisePolynomial>( */ public class PiecewiseBuilder>(delimiter: T) { private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() + private val pieces: MutableList> = arrayListOf() /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) @@ -82,7 +82,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putRight(right: T, piece: ListPolynomial) { + public fun putRight(right: T, piece: Polynomial) { require(right > delimiters.last()) { "New delimiter should be to the right of old one" } delimiters += right pieces += piece @@ -94,7 +94,7 @@ public class PiecewiseBuilder>(delimiter: T) { * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ - public fun putLeft(left: T, piece: ListPolynomial) { + public fun putLeft(left: T, piece: Polynomial) { require(left < delimiters.first()) { "New delimiter should be to the left of old one" } delimiters.add(0, left) pieces.add(0, piece) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index 61ea5a342..fec4776d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -3,500 +3,299 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") + package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.js.JsName -import kotlin.jvm.JvmName +import kotlin.jvm.JvmInline +import kotlin.math.max +import kotlin.math.min /** - * Abstraction of polynomials. - */ -public interface Polynomial - -/** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. + * Represents univariate polynomial that stores its coefficients in a [List]. * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. + * @param C the type of constants. */ -@Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface PolynomialSpace> : Ring

{ +@JvmInline +public value class Polynomial( /** - * Returns sum of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. + * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed + * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * ) + * ``` + * and also as + * ``` + * listOf( + * -6, // -6 + + * 0, // 0 x + + * 5, // 5 x^2 + * 0, // 0 x^3 + * 0, // 0 x^4 + * ) + * ``` + * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. */ - public operator fun C.plus(other: Int): C - /** - * Returns difference between the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public operator fun C.minus(other: Int): C - /** - * Returns product of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun C.times(other: Int): C + public val coefficients: List +) { + override fun toString(): String = "ListPolynomial$coefficients" +} +/** + * Arithmetic context for univariate polynomials with coefficients stored as a [List] constructed with the provided + * [ring] of constants. + * + * @param C the type of constants. Polynomials have them a coefficients in their terms. + * @param A type of provided underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. + */ +public open class ListPolynomialSpace>( /** - * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. + * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ - public operator fun Int.plus(other: C): C - /** - * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public operator fun Int.minus(other: C): C - /** - * Returns product of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: C): C - - /** - * Converts the integer [value] to constant. - */ - public fun constantNumber(value: Int): C = constantOne * value - /** - * Converts the integer to constant. - */ - public fun Int.asConstant(): C = constantNumber(this) - - /** - * Returns sum of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to adding [other] copies of unit polynomial to [this]. - */ - public operator fun P.plus(other: Int): P = addMultipliedByDoubling(this, one, other) - /** - * Returns difference between the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. - */ - public operator fun P.minus(other: Int): P = addMultipliedByDoubling(this, one, -other) - /** - * Returns product of the polynomial and the integer represented as a polynomial. - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public operator fun P.times(other: Int): P = multiplyByDoubling(this, other) - - /** - * Returns sum of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to adding [this] copies of unit polynomial to [other]. - */ - public operator fun Int.plus(other: P): P = addMultipliedByDoubling(other, one, this) - /** - * Returns difference between the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. - */ - public operator fun Int.minus(other: P): P = addMultipliedByDoubling(-other, one, this) - /** - * Returns product of the integer represented as a polynomial and the polynomial. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public operator fun Int.times(other: P): P = multiplyByDoubling(other, this) - - /** - * Converts the integer [value] to polynomial. - */ - public fun number(value: Int): P = number(constantNumber(value)) - /** - * Converts the integer to polynomial. - */ - public fun Int.asPolynomial(): P = number(this) - - /** - * Returns the same constant. - */ - @JvmName("unaryPlusConstant") - @JsName("unaryPlusConstant") - public operator fun C.unaryPlus(): C = this - /** - * Returns negation of the constant. - */ - @JvmName("unaryMinusConstant") - @JsName("unaryMinusConstant") - public operator fun C.unaryMinus(): C - /** - * Returns sum of the constants. - */ - @JvmName("plusConstantConstant") - @JsName("plusConstantConstant") - public operator fun C.plus(other: C): C - /** - * Returns difference of the constants. - */ - @JvmName("minusConstantConstant") - @JsName("minusConstantConstant") - public operator fun C.minus(other: C): C - /** - * Returns product of the constants. - */ - @JvmName("timesConstantConstant") - @JsName("timesConstantConstant") - public operator fun C.times(other: C): C - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("powerConstant") - @JsName("powerConstant") - public fun power(arg: C, exponent: UInt) : C + public val ring: A, +) : Ring> { /** * Instance of zero constant (zero of the underlying ring). */ - public val constantZero: C + public val constantZero: C get() = ring.zero /** * Instance of unit constant (unit of the underlying ring). */ - public val constantOne: C + public val constantOne: C get() = ring.one /** * Returns sum of the constant represented as a polynomial and the polynomial. */ - public operator fun C.plus(other: P): P + public operator fun C.plus(other: Polynomial): Polynomial = + with(ring) { + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@plus)) + else Polynomial( + toMutableList() + .apply { + val result = if (size == 0) this@plus else this@plus + get(0) + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ - public operator fun C.minus(other: P): P + public operator fun C.minus(other: Polynomial): Polynomial = + with(ring) { + with(other.coefficients) { + if (isEmpty()) Polynomial(listOf(this@minus)) + else Polynomial( + toMutableList() + .apply { + (1..lastIndex).forEach { this[it] = -this[it] } + + val result = if (size == 0) this@minus else this@minus - get(0) + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns product of the constant represented as a polynomial and the polynomial. */ - public operator fun C.times(other: P): P + public operator fun C.times(other: Polynomial): Polynomial = + with(ring) { + Polynomial( + other.coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this@times * this[deg] + } + ) + } /** * Returns sum of the constant represented as a polynomial and the polynomial. */ - public operator fun P.plus(other: C): P + public operator fun Polynomial.plus(other: C): Polynomial = + with(ring) { + with(coefficients) { + if (isEmpty()) Polynomial(listOf(other)) + else Polynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) + other + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ - public operator fun P.minus(other: C): P + public operator fun Polynomial.minus(other: C): Polynomial = + with(ring) { + with(coefficients) { + if (isEmpty()) Polynomial(listOf(-other)) + else Polynomial( + toMutableList() + .apply { + val result = if (size == 0) other else get(0) - other + + if (size == 0) add(result) + else this[0] = result + } + ) + } + } /** * Returns product of the constant represented as a polynomial and the polynomial. */ - public operator fun P.times(other: C): P + public operator fun Polynomial.times(other: C): Polynomial = + with(ring) { + Polynomial( + coefficients + .toMutableList() + .apply { + for (deg in indices) this[deg] = this[deg] * other + } + ) + } /** * Converts the constant [value] to polynomial. */ - public fun number(value: C): P = one * value + public fun number(value: C): Polynomial = Polynomial(listOf(value)) /** * Converts the constant to polynomial. */ - public fun C.asPolynomial(): P = number(this) + public fun C.asPolynomial(): Polynomial = number(this) - /** - * Returns the same polynomial. - */ - public override operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ - public override operator fun P.unaryMinus(): P + public override operator fun Polynomial.unaryMinus(): Polynomial = + with(ring) { + Polynomial(coefficients.map { -it }) + } /** * Returns sum of the polynomials. */ - public override operator fun P.plus(other: P): P + public override operator fun Polynomial.plus(other: Polynomial): Polynomial { + with(ring) { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] + } + } + ) + } + } /** * Returns difference of the polynomials. */ - public override operator fun P.minus(other: P): P + public override operator fun Polynomial.minus(other: Polynomial): Polynomial { + with(ring) { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] + } + } + ) + } + } /** * Returns product of the polynomials. */ - public override operator fun P.times(other: P): P + public override operator fun Polynomial.times(other: Polynomial): Polynomial { + with(ring) { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) + } + } /** * Raises [arg] to the integer power [exponent]. - */ - public override fun power(arg: P, exponent: UInt) : P = exponentiateBySquaring(arg, exponent) + */ // TODO: To optimize boxing + override fun power(arg: Polynomial, exponent: UInt): Polynomial = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). */ - public override val zero: P + override val zero: Polynomial = Polynomial(emptyList()) /** * Instance of unit polynomial (unit of the polynomial ring). */ - public override val one: P + override val one: Polynomial by lazy { Polynomial(listOf(constantOne)) } /** * Degree of the polynomial, [see also](https://en.wikipedia.org/wiki/Degree_of_a_polynomial). If the polynomial is * zero, degree is -1. */ - public val P.degree: Int + public val Polynomial.degree: Int get() = coefficients.lastIndex - override fun add(left: P, right: P): P = left + right - override fun multiply(left: P, right: P): P = left * right + override fun add(left: Polynomial, right: Polynomial): Polynomial = left + right + override fun multiply(left: Polynomial, right: Polynomial): Polynomial = left * right + + // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with + // [ListPolynomialSpace] as a context receiver + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline fun Polynomial.substitute(argument: C): C = substitute(ring, argument) + + /** + * Represent [this] polynomial as a regular context-less function. + */ + public inline fun Polynomial.asFunction(): (C) -> C = asFunctionOver(ring) + + /** + * Evaluates value of [this] polynomial on provided [argument]. + */ + public inline operator fun Polynomial.invoke(argument: C): C = substitute(ring, argument) } /** - * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. It also assumes that there is - * provided [ring] (of type [A]), that provides constant-wise operations. + * Space of polynomials constructed over ring. * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param P the type of polynomials. - * @param A the type of algebraic structure (precisely, of ring) provided for constants. + * @param C the type of constants. Polynomials have them as a coefficients in their terms. + * @param A type of underlying ring of constants. It's [Ring] of [C]. + * @param ring underlying ring of constants of type [A]. */ -@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { - - /** - * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. - */ - public val ring: A - - /** - * Returns sum of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. - */ - public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } - /** - * Returns difference between the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. - */ - public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } - /** - * Returns product of the constant and the integer represented as a constant (member of underlying ring). - * - * The operation is equivalent to sum of [other] copies of [this]. - */ - public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } - - /** - * Returns sum of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. - */ - public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } - /** - * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. - */ - public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } - /** - * Returns product of the integer represented as a constant (member of underlying ring) and the constant. - * - * The operation is equivalent to sum of [this] copies of [other]. - */ - public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } - - /** - * Returns negation of the constant. - */ - @JvmName("unaryMinusConstant") - public override operator fun C.unaryMinus(): C = ring { -this@unaryMinus } - /** - * Returns sum of the constants. - */ - @JvmName("plusConstantConstant") - public override operator fun C.plus(other: C): C = ring { this@plus + other } - /** - * Returns difference of the constants. - */ - @JvmName("minusConstantConstant") - public override operator fun C.minus(other: C): C = ring { this@minus - other } - /** - * Returns product of the constants. - */ - @JvmName("timesConstantConstant") - public override operator fun C.times(other: C): C = ring { this@times * other } - /** - * Raises [arg] to the integer power [exponent]. - */ - @JvmName("powerConstant") - override fun power(arg: C, exponent: UInt): C = ring { power(arg, exponent) } - - /** - * Instance of zero constant (zero of the underlying ring). - */ - public override val constantZero: C get() = ring.zero - /** - * Instance of unit constant (unit of the underlying ring). - */ - public override val constantOne: C get() = ring.one +public class ScalableListPolynomialSpace( + ring: A, +) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(a.coefficients.map { scale(it, value) }) } } - -/** - * Abstraction of ring of polynomials of type [P] of variables of type [V] and over ring of constants of type [C]. - * - * @param C the type of constants. Polynomials have them as coefficients in their terms. - * @param V the type of variables. Polynomials have them in representations of terms. - * @param P the type of polynomials. - */ -@Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariatePolynomialSpace>: PolynomialSpace { - /** - * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. - */ - @JvmName("plusVariableInt") - public operator fun V.plus(other: Int): P - /** - * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. - */ - @JvmName("minusVariableInt") - public operator fun V.minus(other: Int): P - /** - * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. - */ - @JvmName("timesVariableInt") - public operator fun V.times(other: Int): P - - /** - * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("plusIntVariable") - public operator fun Int.plus(other: V): P - /** - * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("minusIntVariable") - public operator fun Int.minus(other: V): P - /** - * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("timesIntVariable") - public operator fun Int.times(other: V): P - - /** - * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. - */ - @JvmName("plusVariableConstant") - public operator fun V.plus(other: C): P - /** - * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. - */ - @JvmName("minusVariableConstant") - public operator fun V.minus(other: C): P - /** - * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. - */ - @JvmName("timesVariableConstant") - public operator fun V.times(other: C): P - - /** - * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("plusConstantVariable") - public operator fun C.plus(other: V): P - /** - * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("minusConstantVariable") - public operator fun C.minus(other: V): P - /** - * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. - */ - @JvmName("timesConstantVariable") - public operator fun C.times(other: V): P - - /** - * Represents the variable as a monic monomial. - */ - @JvmName("unaryPlusVariable") - public operator fun V.unaryPlus(): P - /** - * Returns negation of representation of the variable as a monic monomial. - */ - @JvmName("unaryMinusVariable") - public operator fun V.unaryMinus(): P - /** - * Returns sum of the variables represented as monic monomials. - */ - @JvmName("plusVariableVariable") - public operator fun V.plus(other: V): P - /** - * Returns difference between the variables represented as monic monomials. - */ - @JvmName("minusVariableVariable") - public operator fun V.minus(other: V): P - /** - * Returns product of the variables represented as monic monomials. - */ - @JvmName("timesVariableVariable") - public operator fun V.times(other: V): P - - /** - * Represents the [variable] as a monic monomial. - */ - @JvmName("numberVariable") - public fun number(variable: V): P = +variable - /** - * Represents the variable as a monic monomial. - */ - @JvmName("asPolynomialVariable") - public fun V.asPolynomial(): P = number(this) - - /** - * Returns sum of the variable represented as a monic monomial and the polynomial. - */ - @JvmName("plusVariablePolynomial") - public operator fun V.plus(other: P): P - /** - * Returns difference between the variable represented as a monic monomial and the polynomial. - */ - @JvmName("minusVariablePolynomial") - public operator fun V.minus(other: P): P - /** - * Returns product of the variable represented as a monic monomial and the polynomial. - */ - @JvmName("timesVariablePolynomial") - public operator fun V.times(other: P): P - - /** - * Returns sum of the polynomial and the variable represented as a monic monomial. - */ - @JvmName("plusPolynomialVariable") - public operator fun P.plus(other: V): P - /** - * Returns difference between the polynomial and the variable represented as a monic monomial. - */ - @JvmName("minusPolynomialVariable") - public operator fun P.minus(other: V): P - /** - * Returns product of the polynomial and the variable represented as a monic monomial. - */ - @JvmName("timesPolynomialVariable") - public operator fun P.times(other: V): P - - /** - * Map that associates variables (that appear in the polynomial in positive exponents) with their most exponents - * in which they are appeared in the polynomial. - * - * As consequence all values in the map are positive integers. Also, if the polynomial is constant, the map is empty. - * And keys of the map is the same as in [variables]. - */ - public val P.degrees: Map - /** - * Counts degree of the polynomial by the specified [variable]. - */ - public fun P.degreeBy(variable: V): UInt = degrees.getOrElse(variable) { 0u } - /** - * Counts degree of the polynomial by the specified [variables]. - */ - public fun P.degreeBy(variables: Collection): UInt - /** - * Set of all variables that appear in the polynomial in positive exponents. - */ - public val P.variables: Set get() = degrees.keys - /** - * Count of all variables that appear in the polynomial in positive exponents. - */ - public val P.countOfVariables: Int get() = variables.size -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index b40aa4775..5eb1af4dc 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -9,101 +9,6 @@ import space.kscience.kmath.operations.* // TODO: All of this should be moved to algebraic structures' place for utilities -// FIXME: Move receiver to context receiver -/** - * Returns product of [arg] and integer [multiplier]. - * - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal fun Group.multiplyByDoubling(arg: C, multiplier: Int): C = - if (multiplier >= 0) multiplyByDoubling(arg, multiplier.toUInt()) - else multiplyByDoubling(-arg, (-multiplier).toUInt()) - -// FIXME: Move receiver to context receiver -/** - * Adds product of [arg] and [multiplier] to [base]. - * - * @param base the augend. - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: Int): C = - if (multiplier >= 0) addMultipliedByDoubling(base, arg, multiplier.toUInt()) - else addMultipliedByDoubling(base, -arg, (-multiplier).toUInt()) - -// FIXME: Move receiver to context receiver -/** - * Returns product of [arg] and integer [multiplier]. - * - * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) - * - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal tailrec fun Group.multiplyByDoubling(arg: C, multiplier: UInt): C = - when { - multiplier == 0u -> zero - multiplier == 1u -> arg - multiplier and 1u == 0u -> multiplyByDoubling(arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedByDoubling(arg, arg + arg, multiplier shr 1) - else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") - } - -// FIXME: Move receiver to context receiver -/** - * Adds product of [arg] and [multiplier] to [base]. - * - * This is implementation of variation of [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring) - * - * @param base the augend. - * @param arg the multiplicand. - * @param multiplier the integer multiplier. - * @return sum of the augend [base] and product of the multiplicand [arg] and the multiplier [multiplier]. - * @author Gleb Minaev - */ -internal tailrec fun GroupOps.addMultipliedByDoubling(base: C, arg: C, multiplier: UInt): C = - when { - multiplier == 0u -> base - multiplier == 1u -> base + arg - multiplier and 1u == 0u -> addMultipliedByDoubling(base, arg + arg, multiplier shr 1) - multiplier and 1u == 1u -> addMultipliedByDoubling(base + arg, arg + arg, multiplier shr 1) - else -> error("Error in multiplication group instant by unsigned integer: got reminder by division by 2 different from 0 and 1") - } - -// FIXME: Move receiver to context receiver -/** - * Raises [arg] to the integer power [exponent]. - * - * @param arg the base of the power. - * @param exponent the exponent of the power. - * @return [arg] raised to the power [exponent]. - * @author Gleb Minaev - */ -internal fun Field.exponentiateBySquaring(arg: C, exponent: Int): C = - if (exponent >= 0) exponentiateBySquaring(arg, exponent.toUInt()) - else exponentiateBySquaring(one / arg, (-exponent).toUInt()) - -// FIXME: Move receiver to context receiver -/** - * Multiplies [base] and [arg] raised to the integer power [exponent]. - * - * @param base the multiplicand. - * @param arg the base of the power. - * @param exponent the exponent of the power. - * @return product of [base] and [arg] raised to the power [exponent]. - * @author Gleb Minaev - */ -internal fun Field.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: Int): C = - if (exponent >= 0) multiplyExponentiatedBySquaring(base, arg, exponent.toUInt()) - else multiplyExponentiatedBySquaring(base, one / arg, (-exponent).toUInt()) - // FIXME: Move receiver to context receiver /** * Raises [arg] to the integer power [exponent]. diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt deleted file mode 100644 index e95361724..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.Ring - - -/** - * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed - * if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else this }) - -/** - * Constructs a [ListPolynomial] instance with provided [coefficients]. The collection of coefficients will be reversed - * if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): ListPolynomial = - ListPolynomial(with(coefficients) { if (reverse) reversed() else toList() }) - -/** - * Represents [this] constant as a [ListPolynomial]. - */ -public fun C.asListPolynomial() : ListPolynomial = ListPolynomial(listOf(this)) - - -// Waiting for context receivers :( FIXME: Replace with context receivers when they will be available - -/** - * Constructs [ListRationalFunction] instance with numerator and denominator constructed with provided - * [numeratorCoefficients] and [denominatorCoefficients]. The both collections of coefficients will be reversed if - * [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun ListRationalFunction(numeratorCoefficients: List, denominatorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial( with(denominatorCoefficients) { if (reverse) reversed() else this } ) - ) -/** - * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. - */ -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, ListPolynomial(listOf(one))) -/** - * Constructs [ListRationalFunction] instance with provided [numerator] and unit denominator. - */ -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numerator: ListPolynomial): ListRationalFunction = - ListRationalFunction(numerator, polynomialOne) -/** - * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit - * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun > A.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - ListPolynomial(listOf(one)) - ) -/** - * Constructs [ListRationalFunction] instance with numerator constructed with provided [numeratorCoefficients] and unit - * denominator. The collection of numerator coefficients will be reversed if [reverse] parameter is true. - */ -@Suppress("FunctionName") -public fun > ListRationalFunctionSpace.ListRationalFunction(numeratorCoefficients: List, reverse: Boolean = false): ListRationalFunction = - ListRationalFunction( - ListPolynomial( with(numeratorCoefficients) { if (reverse) reversed() else this } ), - polynomialOne - ) - -/** - * Represents [this] constant as a rational function. - */ // FIXME: When context receivers will be ready, delete this function and uncomment the following two -public fun > C.asListRationalFunction(ring: A) : ListRationalFunction = ring.ListRationalFunction(asListPolynomial()) -///** -// * Represents [this] constant as a rational function. -// */ -//context(A) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) -///** -// * Represents [this] constant as a rational function. -// */ -//context(ListRationalFunctionSpace) -//public fun > C.asListRationalFunction() : ListRationalFunction = ListRationalFunction(asListPolynomial()) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt deleted file mode 100644 index 4f3f6d88e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.pow - - -/** - * Creates a [ListPolynomialSpace] over a received ring. - */ -public inline val > A.listPolynomialSpace: ListPolynomialSpace - get() = ListPolynomialSpace(this) - -/** - * Creates a [ListPolynomialSpace]'s scope over a received ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() -} - -/** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. - */ -public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations - get() = ScalableListPolynomialSpace(this) - -/** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() -} - -/** - * Creates a [ListRationalFunctionSpace] over a received ring. - */ -public inline val > A.listRationalFunctionSpace: ListRationalFunctionSpace - get() = ListRationalFunctionSpace(this) - -/** - * Creates a [ListRationalFunctionSpace]'s scope over a received ring. - */ // TODO: When context will be ready move [ListRationalFunctionSpace] and add [A] to context receivers of [block] -public inline fun , R> A.listRationalFunctionSpace(block: ListRationalFunctionSpace.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListRationalFunctionSpace(this).block() -} - - -/** - * Evaluates value of [this] Double polynomial on provided Double argument. - */ -public fun ListPolynomial.substitute(arg: Double): Double = - coefficients.reduceIndexedOrNull { index, acc, c -> - acc + c * arg.pow(index) - } ?: .0 - -/** - * Evaluates value of [this] polynomial on provided argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListPolynomial.substitute(ring: Ring, arg: C): C = ring { - if (coefficients.isEmpty()) return zero - var result: C = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Substitutes provided polynomial [arg] into [this] polynomial. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ // TODO: To optimize boxing -public fun ListPolynomial.substitute(ring: Ring, arg: ListPolynomial) : ListPolynomial = - ring.listPolynomialSpace { - if (coefficients.isEmpty()) return zero - var result: ListPolynomial = coefficients.last().asPolynomial() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result - } - -/** - * Substitutes provided rational function [arg] into [this] polynomial. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ // TODO: To optimize boxing -public fun ListPolynomial.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = - ring.listRationalFunctionSpace { - if (coefficients.isEmpty()) return zero - var result: ListRationalFunction = coefficients.last().asRationalFunction() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result - } - -/** - * Evaluates value of [this] Double rational function in provided Double argument. - */ -public fun ListRationalFunction.substitute(arg: Double): Double = - numerator.substitute(arg) / denominator.substitute(arg) - -/** - * Evaluates value of [this] polynomial for provided argument. - * - * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). - */ -public fun ListRationalFunction.substitute(ring: Field, arg: C): C = ring { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) -} - -/** - * Substitutes provided polynomial [arg] into [this] rational function. - */ // TODO: To optimize boxing -public fun ListRationalFunction.substitute(ring: Ring, arg: ListPolynomial) : ListRationalFunction = - ring.listRationalFunctionSpace { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) - } - -/** - * Substitutes provided rational function [arg] into [this] rational function. - */ // TODO: To optimize boxing -public fun ListRationalFunction.substitute(ring: Ring, arg: ListRationalFunction) : ListRationalFunction = - ring.listRationalFunctionSpace { - numerator.substitute(ring, arg) / denominator.substitute(ring, arg) - } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListPolynomial = { substitute(ring, it) } - -/** - * Represent [this] polynomial as a regular context-less function. - */ -public fun > ListPolynomial.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfConstantOver(ring: A): (C) -> C = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfPolynomialOver(ring: A): (ListPolynomial) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Represent [this] rational function as a regular context-less function. - */ -public fun > ListRationalFunction.asFunctionOfRationalFunctionOver(ring: A): (ListRationalFunction) -> ListRationalFunction = { substitute(ring, it) } - -/** - * Returns algebraic derivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.derivative( - ring: A, -): ListPolynomial where A : Ring, A : NumericAlgebra = ring { - ListPolynomial( - buildList(max(0, coefficients.size - 1)) { - for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) - } - ) -} - -/** - * Returns algebraic derivative of received polynomial of specified [order]. The [order] should be non-negative integer. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthDerivative( - ring: A, - order: Int, -): ListPolynomial where A : Ring, A : NumericAlgebra = ring { - require(order >= 0) { "Order of derivative must be non-negative" } - ListPolynomial( - buildList(max(0, coefficients.size - order)) { - for (deg in order.. coefficients.lastIndex) - add((deg - order + 1 .. deg).fold(coefficients[deg]) { acc, d -> acc * number(d) }) - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial. - */ -@UnstableKMathAPI -public fun ListPolynomial.antiderivative( - ring: A, -): ListPolynomial where A : Field, A : NumericAlgebra = ring { - ListPolynomial( - buildList(coefficients.size + 1) { - add(zero) - coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } - } - ) -} - -/** - * Returns algebraic antiderivative of received polynomial of specified [order]. The [order] should be non-negative integer. - */ -@UnstableKMathAPI -public fun ListPolynomial.nthAntiderivative( - ring: A, - order: Int, -): ListPolynomial where A : Field, A : NumericAlgebra = ring { - require(order >= 0) { "Order of antiderivative must be non-negative" } - ListPolynomial( - buildList(coefficients.size + order) { - repeat(order) { add(zero) } - coefficients.mapIndexedTo(this) { index, c -> (1..order).fold(c) { acc, i -> acc / number(index + i) } } - } - ) -} - -/** - * Computes a definite integral of [this] polynomial in the specified [range]. - */ -@UnstableKMathAPI -public fun > ListPolynomial.integrate( - ring: Field, - range: ClosedRange, -): C = ring { - val antiderivative = antiderivative(ring) - antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt deleted file mode 100644 index 76f1c294e..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - - -/** - * Marks declarations that give access to internal entities of polynomials delicate structure. Thus, it allows to - * optimize performance a bit by skipping standard steps, but such skips may cause critical errors if something is - * implemented badly. Make sure you fully read and understand documentation and don't break internal contracts. - */ -@RequiresOptIn( - message = "This declaration gives access to delicate internal structure of polynomials. " + - "It allows to optimize performance by skipping unnecessary arguments check. " + - "But at the same time makes it easy to make a mistake " + - "that will cause wrong computation result or even runtime error. " + - "Make sure you fully read and understand documentation.", - level = RequiresOptIn.Level.ERROR -) -public annotation class DelicatePolynomialAPI \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt new file mode 100644 index 000000000..ff04607a7 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + + +/** + * Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(coefficients: List, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else this }) + +/** + * Constructs a [Polynomial] instance with provided [coefficients]. The collection of coefficients will be reversed + * if [reverse] parameter is true. + */ +@Suppress("FunctionName") +public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = + Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) + +/** + * Represents [this] constant as a [Polynomial]. + */ +public fun C.asListPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt new file mode 100644 index 000000000..fc3a728df --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt @@ -0,0 +1,111 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.math.max +import kotlin.math.pow + + +/** + * Creates a [ListPolynomialSpace] over a received ring. + */ +public inline val > A.listPolynomialSpace: ListPolynomialSpace + get() = ListPolynomialSpace(this) + +/** + * Creates a [ListPolynomialSpace]'s scope over a received ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ListPolynomialSpace(this).block() +} + +/** + * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + */ +public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalableListPolynomialSpace(this) + +/** + * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] +public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return ScalableListPolynomialSpace(this).block() +} + + +/** + * Evaluates value of [this] Double polynomial on provided Double argument. + */ +public fun Polynomial.substitute(arg: Double): Double = + coefficients.reduceIndexedOrNull { index, acc, c -> + acc + c * arg.pow(index) + } ?: .0 + +/** + * Evaluates value of [this] polynomial on provided argument. + * + * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). + */ +public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { + if (coefficients.isEmpty()) return zero + var result: C = coefficients.last() + for (j in coefficients.size - 2 downTo 0) { + result = (arg * result) + coefficients[j] + } + return result +} + +/** + * Represent [this] polynomial as a regular context-less function. + */ +public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } + +/** + * Returns algebraic derivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.derivative( + ring: A, +): Polynomial where A : Ring, A : NumericAlgebra = ring { + Polynomial( + buildList(max(0, coefficients.size - 1)) { + for (deg in 1 .. coefficients.lastIndex) add(number(deg) * coefficients[deg]) + } + ) +} + +/** + * Returns algebraic antiderivative of received polynomial. + */ +@UnstableKMathAPI +public fun Polynomial.antiderivative( + ring: A, +): Polynomial where A : Field, A : NumericAlgebra = ring { + Polynomial( + buildList(coefficients.size + 1) { + add(zero) + coefficients.mapIndexedTo(this) { index, t -> t / number(index + 1) } + } + ) +} + +/** + * Computes a definite integral of [this] polynomial in the specified [range]. + */ +@UnstableKMathAPI +public fun > Polynomial.integrate( + ring: Field, + range: ClosedRange, +): C { + val antiderivative = antiderivative(ring) + return ring { antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt index 487cd9ee1..5782292b1 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -26,286 +26,6 @@ object ExprRing : Field { } class AlgebraicStubTest { - @Test - fun test_addMultipliedBySquaring_for_UInt() { - ExprRing { - assertEquals( - "57", - addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, - "tried addMultipliedBySquaring(57, 179, 0u)" - ) - assertEquals( - "(57 + 179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, - "tried addMultipliedBySquaring(57, 179, 1u)" - ) - assertEquals( - "(57 + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, - "tried addMultipliedBySquaring(57, 179, 2u)" - ) - assertEquals( - "((57 + 179) + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, - "tried addMultipliedBySquaring(57, 179, 3u)" - ) - assertEquals( - "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, - "tried addMultipliedBySquaring(57, 179, 4u)" - ) - assertEquals( - "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, - "tried addMultipliedBySquaring(57, 179, 5u)" - ) - assertEquals( - "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, - "tried addMultipliedBySquaring(57, 179, 6u)" - ) - assertEquals( - "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, - "tried addMultipliedBySquaring(57, 179, 7u)" - ) - assertEquals( - "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, - "tried addMultipliedBySquaring(57, 179, 8u)" - ) - } - } - @Test - fun test_multiplyBySquaring_for_UInt() { - ExprRing { - assertEquals( - "0", - multiplyByDoubling(Expr("57"), 0u).expr, - "tried multiplyBySquaring(57, 0u)" - ) - assertEquals( - "57", - multiplyByDoubling(Expr("57"), 1u).expr, - "tried multiplyBySquaring(57, 1u)" - ) - assertEquals( - "(57 + 57)", - multiplyByDoubling(Expr("57"), 2u).expr, - "tried multiplyBySquaring(57, 2u)" - ) - assertEquals( - "(57 + (57 + 57))", - multiplyByDoubling(Expr("57"), 3u).expr, - "tried multiplyBySquaring(57, 3u)" - ) - assertEquals( - "((57 + 57) + (57 + 57))", - multiplyByDoubling(Expr("57"), 4u).expr, - "tried multiplyBySquaring(57, 4u)" - ) - assertEquals( - "(57 + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 5u).expr, - "tried multiplyBySquaring(57, 5u)" - ) - assertEquals( - "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 6u).expr, - "tried multiplyBySquaring(57, 6u)" - ) - assertEquals( - "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 7u).expr, - "tried multiplyBySquaring(57, 7u)" - ) - assertEquals( - "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 8u).expr, - "tried multiplyBySquaring(57, 8u)" - ) - } - } - @Test - fun test_addMultipliedBySquaring_for_Int() { - ExprRing { - assertEquals( - "57", - addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, - "tried addMultipliedBySquaring(57, 179, 0)" - ) - assertEquals( - "(57 + 179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, - "tried addMultipliedBySquaring(57, 179, 1)" - ) - assertEquals( - "(57 + -179)", - addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, - "tried addMultipliedBySquaring(57, 179, -1)" - ) - assertEquals( - "(57 + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, - "tried addMultipliedBySquaring(57, 179, 2)" - ) - assertEquals( - "(57 + (-179 + -179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, - "tried addMultipliedBySquaring(57, 179, -2)" - ) - assertEquals( - "((57 + 179) + (179 + 179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, - "tried addMultipliedBySquaring(57, 179, 3)" - ) - assertEquals( - "((57 + -179) + (-179 + -179))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, - "tried addMultipliedBySquaring(57, 179, -3)" - ) - assertEquals( - "(57 + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, - "tried addMultipliedBySquaring(57, 179, 4)" - ) - assertEquals( - "(57 + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, - "tried addMultipliedBySquaring(57, 179, -4)" - ) - assertEquals( - "((57 + 179) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, - "tried addMultipliedBySquaring(57, 179, 5)" - ) - assertEquals( - "((57 + -179) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, - "tried addMultipliedBySquaring(57, 179, -5)" - ) - assertEquals( - "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, - "tried addMultipliedBySquaring(57, 179, 6)" - ) - assertEquals( - "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, - "tried addMultipliedBySquaring(57, 179, -6)" - ) - assertEquals( - "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, - "tried addMultipliedBySquaring(57, 179, 7)" - ) - assertEquals( - "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, - "tried addMultipliedBySquaring(57, 179, -7)" - ) - assertEquals( - "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, - "tried addMultipliedBySquaring(57, 179, 8)" - ) - assertEquals( - "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", - addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, - "tried addMultipliedBySquaring(57, 179, -8)" - ) - } - } - @Test - fun test_multiplyBySquaring_for_Int() { - ExprRing { - assertEquals( - "0", - multiplyByDoubling(Expr("57"), 0).expr, - "tried multiplyBySquaring(57, 0)" - ) - assertEquals( - "57", - multiplyByDoubling(Expr("57"), 1).expr, - "tried multiplyBySquaring(57, 1)" - ) - assertEquals( - "-57", - multiplyByDoubling(Expr("57"), -1).expr, - "tried multiplyBySquaring(57, -1)" - ) - assertEquals( - "(57 + 57)", - multiplyByDoubling(Expr("57"), 2).expr, - "tried multiplyBySquaring(57, 2)" - ) - assertEquals( - "(-57 + -57)", - multiplyByDoubling(Expr("57"), -2).expr, - "tried multiplyBySquaring(57, -2)" - ) - assertEquals( - "(57 + (57 + 57))", - multiplyByDoubling(Expr("57"), 3).expr, - "tried multiplyBySquaring(57, 3)" - ) - assertEquals( - "(-57 + (-57 + -57))", - multiplyByDoubling(Expr("57"), -3).expr, - "tried multiplyBySquaring(57, -3)" - ) - assertEquals( - "((57 + 57) + (57 + 57))", - multiplyByDoubling(Expr("57"), 4).expr, - "tried multiplyBySquaring(57, 4)" - ) - assertEquals( - "((-57 + -57) + (-57 + -57))", - multiplyByDoubling(Expr("57"), -4).expr, - "tried multiplyBySquaring(57, -4)" - ) - assertEquals( - "(57 + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 5).expr, - "tried multiplyBySquaring(57, 5)" - ) - assertEquals( - "(-57 + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -5).expr, - "tried multiplyBySquaring(57, -5)" - ) - assertEquals( - "((57 + 57) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 6).expr, - "tried multiplyBySquaring(57, 6)" - ) - assertEquals( - "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -6).expr, - "tried multiplyBySquaring(57, -6)" - ) - assertEquals( - "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 7).expr, - "tried multiplyBySquaring(57, 7)" - ) - assertEquals( - "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -7).expr, - "tried multiplyBySquaring(57, -7)" - ) - assertEquals( - "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", - multiplyByDoubling(Expr("57"), 8).expr, - "tried multiplyBySquaring(57, 8)" - ) - assertEquals( - "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", - multiplyByDoubling(Expr("57"), -8).expr, - "tried multiplyBySquaring(57, -8)" - ) - } - } @Test fun test_multiplyExponentiationBySquaring_for_UInt() { ExprRing { @@ -406,184 +126,4 @@ class AlgebraicStubTest { ) } } - @Test - fun test_multiplyExponentiationBySquaring_for_Int() { - ExprRing { - assertEquals( - "57", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr, - "tried multiplyExponentiationBySquaring(57, 179, 0)" - ) - assertEquals( - "(57 * 179)", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr, - "tried multiplyExponentiationBySquaring(57, 179, 1)" - ) - assertEquals( - "(57 * (1 / 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr, - "tried multiplyExponentiationBySquaring(57, 179, -1)" - ) - assertEquals( - "(57 * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr, - "tried multiplyExponentiationBySquaring(57, 179, 2)" - ) - assertEquals( - "(57 * ((1 / 179) * (1 / 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr, - "tried multiplyExponentiationBySquaring(57, 179, -2)" - ) - assertEquals( - "((57 * 179) * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr, - "tried multiplyExponentiationBySquaring(57, 179, 3)" - ) - assertEquals( - "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr, - "tried multiplyExponentiationBySquaring(57, 179, -3)" - ) - assertEquals( - "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr, - "tried multiplyExponentiationBySquaring(57, 179, 4)" - ) - assertEquals( - "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr, - "tried multiplyExponentiationBySquaring(57, 179, -4)" - ) - assertEquals( - "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr, - "tried multiplyExponentiationBySquaring(57, 179, 5)" - ) - assertEquals( - "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr, - "tried multiplyExponentiationBySquaring(57, 179, -5)" - ) - assertEquals( - "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr, - "tried multiplyExponentiationBySquaring(57, 179, 6)" - ) - assertEquals( - "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr, - "tried multiplyExponentiationBySquaring(57, 179, -6)" - ) - assertEquals( - "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr, - "tried multiplyExponentiationBySquaring(57, 179, 7)" - ) - assertEquals( - "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr, - "tried multiplyExponentiationBySquaring(57, 179, -7)" - ) - assertEquals( - "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr, - "tried multiplyExponentiationBySquaring(57, 179, 8)" - ) - assertEquals( - "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr, - "tried multiplyExponentiationBySquaring(57, 179, -8)" - ) - } - } - @Test - fun test_exponentiationBySquaring_for_Int() { - ExprRing { - assertEquals( - "0", - exponentiateBySquaring(Expr("57"), 0).expr, - "tried exponentiationBySquaring(57, 0)" - ) - assertEquals( - "57", - exponentiateBySquaring(Expr("57"), 1).expr, - "tried exponentiationBySquaring(57, 1)" - ) - assertEquals( - "(1 / 57)", - exponentiateBySquaring(Expr("57"), -1).expr, - "tried exponentiationBySquaring(57, -1)" - ) - assertEquals( - "(57 * 57)", - exponentiateBySquaring(Expr("57"), 2).expr, - "tried exponentiationBySquaring(57, 2)" - ) - assertEquals( - "((1 / 57) * (1 / 57))", - exponentiateBySquaring(Expr("57"), -2).expr, - "tried exponentiationBySquaring(57, -2)" - ) - assertEquals( - "(57 * (57 * 57))", - exponentiateBySquaring(Expr("57"), 3).expr, - "tried exponentiationBySquaring(57, 3)" - ) - assertEquals( - "((1 / 57) * ((1 / 57) * (1 / 57)))", - exponentiateBySquaring(Expr("57"), -3).expr, - "tried exponentiationBySquaring(57, -3)" - ) - assertEquals( - "((57 * 57) * (57 * 57))", - exponentiateBySquaring(Expr("57"), 4).expr, - "tried exponentiationBySquaring(57, 4)" - ) - assertEquals( - "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", - exponentiateBySquaring(Expr("57"), -4).expr, - "tried exponentiationBySquaring(57, -4)" - ) - assertEquals( - "(57 * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 5).expr, - "tried exponentiationBySquaring(57, 5)" - ) - assertEquals( - "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -5).expr, - "tried exponentiationBySquaring(57, -5)" - ) - assertEquals( - "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 6).expr, - "tried exponentiationBySquaring(57, 6)" - ) - assertEquals( - "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -6).expr, - "tried exponentiationBySquaring(57, -6)" - ) - assertEquals( - "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 7).expr, - "tried exponentiationBySquaring(57, 7)" - ) - assertEquals( - "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -7).expr, - "tried exponentiationBySquaring(57, -7)" - ) - assertEquals( - "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 8).expr, - "tried exponentiationBySquaring(57, 8)" - ) - assertEquals( - "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", - exponentiateBySquaring(Expr("57"), -8).expr, - "tried exponentiationBySquaring(57, -8)" - ) - } - } } \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index e7d8dfd8c..117ffb579 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -7,252 +7,11 @@ package space.kscience.kmath.functions -import space.kscience.kmath.functions.testUtils.IntModuloRing -import space.kscience.kmath.functions.testUtils.ListPolynomial -import space.kscience.kmath.functions.testUtils.Rational -import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.* import kotlin.test.* class ListPolynomialTest { - @Test - fun test_Polynomial_Int_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + 2, - "test 3" - ) - val polynomial_4 = ListPolynomial() - assertSame( - polynomial_4, - polynomial_4 + 0, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertSame( - polynomial_5, - polynomial_5 + 0, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + 1, - "test 7" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + 2, - "test 8" - ) - } - } - @Test - fun test_Polynomial_Int_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - 2, - "test 3" - ) - val polynomial_4 = ListPolynomial() - assertSame( - polynomial_4, - polynomial_4 - 0, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertEquals( - polynomial_5, - polynomial_5 - 0, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, - "test 6" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - 1, - "test 7" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - 2, - "test 8" - ) - } - } - @Test - fun test_Polynomial_Int_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27, - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15, - "test 2" - ) - val polynomial = ListPolynomial(22, 26, 13, 15, 26) - assertSame( - zero, - polynomial * 0, - "test 3" - ) - assertSame( - polynomial, - polynomial * 1, - "test 4" - ) - } - } - @Test - fun test_Int_Polynomial_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - 2 + ListPolynomial(Rational(-2)), - "test 3" - ) - val polynomial_4 = ListPolynomial() - assertSame( - polynomial_4, - 0 + polynomial_4, - "test 4" - ) - val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) - assertSame( - polynomial_5, - 0 + polynomial_5, - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-1)), - 1 + ListPolynomial(Rational(-2)), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(2)), - 2 + ListPolynomial(), - "test 8" - ) - } - } - @Test - fun test_Int_Polynomial_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - -2 - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), - 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - "test 4" - ) - assertEquals( - ListPolynomial(), - 0 - ListPolynomial(), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(1)), - -1 - ListPolynomial(Rational(-2)), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(-2)), - -2 - ListPolynomial(), - "test 8" - ) - } - } - @Test - fun test_Int_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - val polynomial = ListPolynomial(22, 26, 13, 15, 26) - assertSame( - zero, - 0 * polynomial, - "test 3" - ) - assertSame( - polynomial, - 1 * polynomial, - "test 4" - ) - } - } @Test fun test_Polynomial_Constant_plus() { RationalField.listPolynomialSpace { @@ -338,12 +97,12 @@ class ListPolynomialTest { IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), + ListPolynomial(22, 26, 13, 15, 26) * m(27), "test 1" ) assertEquals( ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), + ListPolynomial(7, 0, 49, 21, 14) * m(15), "test 2" ) } @@ -433,12 +192,12 @@ class ListPolynomialTest { IntModuloRing(35).listPolynomialSpace { assertEquals( ListPolynomial(34, 2, 1, 20, 2), - 27 * ListPolynomial(22, 26, 13, 15, 26), + m(27) * ListPolynomial(22, 26, 13, 15, 26), "test 1" ) assertEquals( ListPolynomial(0, 0, 0, 0, 0), - 15 * ListPolynomial(7, 0, 49, 21, 14), + m(15) * ListPolynomial(7, 0, 49, 21, 14), "test 2" ) } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 339643d02..153b0134b 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -5,11 +5,9 @@ package space.kscience.kmath.functions -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage -import kotlin.test.Ignore +import space.kscience.kmath.misc.UnstableKMathAPI import kotlin.test.Test import kotlin.test.assertEquals @@ -88,754 +86,6 @@ class ListPolynomialUtilTest { ) } @Test - fun test_Polynomial_substitute_Polynomial() { - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), - ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) - .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), - "test 6" - ) - } - @Test - @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), - // not r^(deg(p)(deg(p)+1)/2) as it is now. - fun test_Polynomial_substitute_RationalFunction() { - assertEquals( - ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), - ListPolynomial(Rational(1), Rational(-2), Rational(1)) - .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(66349, 243), - Rational(-17873, 405), - Rational(173533, 3780), - Rational(-91141, 567), - Rational(5773909, 105840), - Rational(-23243, 630), - Rational(1573, 27) - ), - ListPolynomial( - Rational(169, 81), - Rational(-130, 27), - Rational(115, 18), - Rational(-797, 54), - Rational(1985, 144), - Rational(-55, 6), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(-9, 5), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(6, 9), - Rational(-3, 7) - ), - ListPolynomial( - Rational(-13, 9), - Rational(10, 6), - Rational(-10, 8), - Rational(11, 3) - ) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(-14, 9), - Rational(31, 14), - Rational(-5077, 980), - Rational(99, 35) - ), - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(25, 9), - Rational(-25, 6), - Rational(1985, 144), - Rational(-55, 6), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(0), - Rational(-9, 5), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(6, 9), - Rational(-3, 7) - ), - ListPolynomial( - Rational(0), - Rational(10, 6), - Rational(-10, 8), - Rational(11, 3) - ) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-898, 27), - Rational(271, 45), - Rational(-65, 12) , - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ), - ListPolynomial( - Rational(-13, 9), - Rational(5, 3), - Rational(-5, 4), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(-9, 5), - Rational(0) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(6, 9), - Rational(0) - ), - ListPolynomial( - Rational(-13, 9), - Rational(10, 6), - Rational(-10, 8), - Rational(0) - ) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(56872, 243), - Rational(0, 1), - Rational(-90, 7), - Rational(-3718, 81), - Rational(9, 49), - Rational(0, 1), - Rational(1573, 27) - ), - ListPolynomial( - Rational(169, 81), - Rational(0, 1), - Rational(0, 1), - Rational(-286, 27), - Rational(0, 1), - Rational(0, 1), - Rational(121, 9) - ) - ), - ListPolynomial( - Rational(13, 3), - Rational(0), - Rational(5, 5) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(15, 1), - Rational(0), - Rational(-3, 7) - ), - ListPolynomial( - Rational(-13, 9), - Rational(0), - Rational(0), - Rational(11, 3) - ) - ) - ), - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Double() { - assertEquals( - 0.0, - ListRationalFunction( - ListPolynomial(1.0, -2.0, 1.0), - ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) - ).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 2.693702616649797, - ListRationalFunction( - ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), - ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 2" - ) - assertEquals( - 2.692226268901378, - ListRationalFunction( - ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), - ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 3" - ) - assertEquals( - -0.7394904842099175, - ListRationalFunction( - ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), - ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) - ).substitute(-7.53452770353279), - 0.001, - "test 4" - ) - assertEquals( - 3.526835209398159, - ListRationalFunction( - ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), - ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) - ).substitute(-7.53452770353279), - 0.001, - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Constant() { - assertEquals( - Rational(0), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)), - ).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(1149615, 61306), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), - ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 2" - ) - assertEquals( - Rational(3495, 586), - ListRationalFunction( - ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), - ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 3" - ) - assertEquals( - Rational(-88605, 77392), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), - ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), - ).substitute(RationalField, Rational(-7, 8)), - "test 4" - ) - assertEquals( - Rational(116145, 3794), - ListRationalFunction( - ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), - ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), - ).substitute(RationalField, Rational(-7, 8)), - "test 5" - ) - } - @Test - fun test_RationalFunction_substitute_Polynomial() { - assertEquals( - ListRationalFunction( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1)) - ), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)), - ).substitute(RationalField, ListPolynomial(Rational(1))), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-283303, 36), - Rational(-23593, 24), - Rational(368713, 192), - Rational(1455, 8), - Rational(-272171, 1536), - Rational(-2149, 192), - Rational(469, 64), - Rational(11, 48), - Rational(-11, 96) - ), - ListPolynomial( - Rational(5797, 12), - Rational(595, 16), - Rational(-5285, 72), - Rational(-745, 192), - Rational(1105, 288), - Rational(5, 48), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(-11, 6) - ), - ListPolynomial( - Rational(-2, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(-1, 4), - Rational(2, 4) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(-11, 12), - Rational(325, 192), - Rational(21, 32), - Rational(-1739, 1536), - Rational(227, 192), - Rational(-59, 64), - Rational(11, 48), - Rational(-11, 96) - ), - ListPolynomial( - Rational(0, 1), - Rational(15, 16), - Rational(-265, 144), - Rational(-25, 192), - Rational(25, 288), - Rational(5, 48), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(0, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(-11, 6) - ), - ListPolynomial( - Rational(0, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(0, 1), - Rational(-1, 4), - Rational(2, 4) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(149723, 36), - Rational(8483, 24), - Rational(639, 64), - Rational(3, 32), - Rational(0), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ), - ListPolynomial( - Rational(937, 12), - Rational(55, 16), - Rational(5, 144), - Rational(0), - Rational(0), - Rational(0), - Rational(0) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(11, 3), - Rational(-9, 4), - Rational(-6, 1), - Rational(0) - ), - ListPolynomial( - Rational(-2, 3), - Rational(-15, 4), - Rational(5, 9), - Rational(0) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(-1, 4), - Rational(0) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(-216509, 18), - Rational(0, 1), - Rational(2673, 1), - Rational(0, 1), - Rational(-891, 4), - Rational(0, 1), - Rational(33, 4), - Rational(0, 1), - Rational(-11, 96) - ), - ListPolynomial( - Rational(1213, 3), - Rational(0, 1), - Rational(-135, 2), - Rational(0, 1), - Rational(15, 4), - Rational(0, 1), - Rational(-5, 72) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(2, 9), - Rational(0), - Rational(0), - Rational(0), - Rational(-11, 6) - ), - ListPolynomial( - Rational(-2, 3), - Rational(0), - Rational(0), - Rational(-5, 9) - ) - ).substitute(RationalField, - ListPolynomial( - Rational(-9, 1), - Rational(0), - Rational(2, 4) - ) - ), - "test 5" - ) - } - @Test - @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. - // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), - // not r^(deg(p)(deg(p)+1)/2) as it is now. - fun test_RationalFunction_substitute_RationalFunction() { - assertEquals( - ListRationalFunction( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(1)) - ), - ListRationalFunction( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1)) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(1)) - ) - ), - "test 1" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(130087, 3888), - Rational(-2866333, 65610), - Rational(-5076229, 97200), - Rational(222136997, 3280500), - Rational(754719329, 20995200), - Rational(-12010283, 324000), - Rational(-2011967, 172800), - Rational(18607, 2880), - Rational(4705, 4096) - ), - ListPolynomial( - Rational(-143820355, 3779136), - Rational(73886869, 1574640), - Rational(1440175193, 15746400), - Rational(-5308968857, 52488000), - Rational(-186910083731, 2099520000), - Rational(125043463, 1555200), - Rational(5299123, 388800), - Rational(-213757, 15360), - Rational(1380785, 147456) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(-10, 5), - Rational(18, 8), - Rational(-8, 8) - ), - ListPolynomial( - Rational(-14, 8), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(-2, 5), - Rational(-14, 7) - ), - ListPolynomial( - Rational(-6, 4), - Rational(5, 9), - Rational(1, 8) - ) - ) - ), - "test 2" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(5173, 18225), - Rational(904291, 364500), - Rational(283127, 43200), - Rational(37189, 5760), - Rational(147, 128) - ), - ListPolynomial( - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(-163589, 911250), - Rational(-881831, 291600), - Rational(-10722229, 777600), - Rational(-640921, 46080), - Rational(86303, 9216) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(-10, 5), - Rational(18, 8), - Rational(-8, 8) - ), - ListPolynomial( - Rational(0), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(0), - Rational(-2, 5), - Rational(-14, 7) - ), - ListPolynomial( - Rational(0), - Rational(5, 9), - Rational(1, 8) - ) - ) - ), - "test 3" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(445, 16), - Rational(-2011, 54), - Rational(1359199, 72900), - Rational(-135733, 32805), - Rational(2254, 6561), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1) - ), - ListPolynomial( - Rational(-2018387, 46656), - Rational(82316437, 1574640), - Rational(-9335047, 393660), - Rational(15765889, 3280500), - Rational(-242089, 656100), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1), - Rational(0, 1) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(-10, 5), - Rational(18, 8), - Rational(0) - ), - ListPolynomial( - Rational(-14, 8), - Rational(-14, 8), - Rational(-19, 6), - Rational(14, 3), - Rational(0) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(-2, 5), - Rational(0) - ), - ListPolynomial( - Rational(-6, 4), - Rational(5, 9), - Rational(0) - ) - ) - ), - "test 4" - ) - assertEquals( - ListRationalFunction( - ListPolynomial( - Rational(41635, 3888), - Rational(0, 1), - Rational(-279187, 11664), - Rational(0, 1), - Rational(103769, 3456), - Rational(0, 1), - Rational(-11017, 768), - Rational(0, 1), - Rational(4097, 4096) - ), - ListPolynomial( - Rational(-13811791, 3779136), - Rational(0, 1), - Rational(-9999395, 419904), - Rational(0, 1), - Rational(6376601, 124416), - Rational(0, 1), - Rational(-3668315, 82944), - Rational(0, 1), - Rational(2097089, 147456) - ) - ), - ListRationalFunction( - ListPolynomial( - Rational(1, 1), - Rational(0), - Rational(0), - Rational(-8, 8) - ), - ListPolynomial( - Rational(-14, 8), - Rational(0), - Rational(0), - Rational(0), - Rational(8, 9) - ) - ).substitute(RationalField, - ListRationalFunction( - ListPolynomial( - Rational(14, 9), - Rational(0), - Rational(-14, 7) - ), - ListPolynomial( - Rational(-6, 4), - Rational(0), - Rational(1, 8) - ) - ) - ), - "test 5" - ) - } - @Test fun test_Polynomial_derivative() { assertEquals( ListPolynomial(Rational(-2), Rational(2)), @@ -859,55 +109,6 @@ class ListPolynomialUtilTest { ) } @Test - fun test_Polynomial_nthDerivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), - "test 1" - ) - assertFailsWithTypeAndMessage( - "Order of derivative must be non-negative", - "test2" - ) { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), - "test 9" - ) - } - @Test fun test_Polynomial_antiderivative() { assertEquals( ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), @@ -930,53 +131,4 @@ class ListPolynomialUtilTest { "test 4" ) } - @Test - fun test_Polynomial_nthAntiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), - "test 1" - ) - assertFailsWithTypeAndMessage( - "Order of antiderivative must be non-negative", - "test2" - ) { - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) - } - assertEquals( - ListPolynomial(Rational(1), Rational(-2), Rational(1)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 7" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), - "test 8" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), - "test 9" - ) - } } \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 4b65fbea1..997a966a7 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -5,15 +5,14 @@ package space.kscience.kmath.functions.testUtils -import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomialSpace -import space.kscience.kmath.functions.PolynomialSpaceOverRing -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = - ListPolynomial(coefs.map { IntModulo(it, modulus) }) +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial = + Polynomial(coefs.map { IntModulo(it, modulus) }) public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +public fun ListPolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file From 6ff79e28ac0b34e74cbec682866610492425a157 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 00:57:44 +0300 Subject: [PATCH 117/174] Fix names, references, etc. --- .../kscience/kmath/functions/Polynomial.kt | 6 +- .../kmath/functions/polynomialConstructors.kt | 6 +- .../kmath/functions/polynomialUtil.kt | 24 +- .../kmath/interpolation/LinearInterpolator.kt | 4 +- .../kmath/interpolation/SplineInterpolator.kt | 4 +- .../kmath/functions/ListPolynomialTest.kt | 303 ------------------ .../kmath/functions/ListPolynomialUtilTest.kt | 134 -------- .../kmath/functions/PolynomialTest.kt | 303 ++++++++++++++++++ .../kmath/functions/PolynomialUtilTest.kt | 134 ++++++++ .../kmath/integration/SplineIntegralTest.kt | 4 +- .../functions/LabeledPolynomialUtilTest.kt | 1 + .../functions/testUtils/IntModuloUtils.kt | 8 +- .../kmath/functions/testUtils/IntModulo.kt | 133 ++++++++ .../functions/testUtils/IntModuloUtils.kt | 20 ++ .../kmath/functions/testUtils/NTMisc.kt | 29 ++ .../kmath/functions/testUtils/Rational.kt | 177 ++++++++++ .../kmath/functions/testUtils/assertion.kt | 1 - 17 files changed, 825 insertions(+), 466 deletions(-) delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt create mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt create mode 100644 test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt 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 fec4776d9..061f556f6 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 @@ -59,7 +59,7 @@ public value class Polynomial( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public open class ListPolynomialSpace>( +public open class PolynomialSpace>( /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ @@ -293,9 +293,9 @@ public open class ListPolynomialSpace>( * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public class ScalableListPolynomialSpace( +public class ScalablePolynomialSpace( ring: A, -) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { +) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { override fun scale(a: Polynomial, value: Double): Polynomial = ring { Polynomial(a.coefficients.map { scale(it, value) }) } } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt index ff04607a7..2da9ea6f5 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt @@ -11,7 +11,7 @@ package space.kscience.kmath.functions * if [reverse] parameter is true. */ @Suppress("FunctionName") -public fun ListPolynomial(coefficients: List, reverse: Boolean = false): Polynomial = +public fun Polynomial(coefficients: List, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else this }) /** @@ -19,10 +19,10 @@ public fun ListPolynomial(coefficients: List, reverse: Boolean = false): * if [reverse] parameter is true. */ @Suppress("FunctionName") -public fun ListPolynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = +public fun Polynomial(vararg coefficients: C, reverse: Boolean = false): Polynomial = Polynomial(with(coefficients) { if (reverse) reversed() else toList() }) /** * Represents [this] constant as a [Polynomial]. */ -public fun C.asListPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file +public fun C.asPolynomial() : Polynomial = Polynomial(listOf(this)) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialUtil.kt index fc3a728df..0e1259bee 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 @@ -14,31 +14,31 @@ import kotlin.math.pow /** - * Creates a [ListPolynomialSpace] over a received ring. + * Creates a [PolynomialSpace] over a received ring. */ -public inline val > A.listPolynomialSpace: ListPolynomialSpace - get() = ListPolynomialSpace(this) +public inline val > A.polynomialSpace: PolynomialSpace + get() = PolynomialSpace(this) /** - * Creates a [ListPolynomialSpace]'s scope over a received ring. + * Creates a [PolynomialSpace]'s scope over a received ring. */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun , R> A.listPolynomialSpace(block: ListPolynomialSpace.() -> R): R { +public inline fun , R> A.polynomialSpace(block: PolynomialSpace.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ListPolynomialSpace(this).block() + return PolynomialSpace(this).block() } /** - * Creates a [ScalableListPolynomialSpace] over a received scalable ring. + * Creates a [ScalablePolynomialSpace] over a received scalable ring. */ -public inline val A.scalableListPolynomialSpace: ScalableListPolynomialSpace where A : Ring, A : ScaleOperations - get() = ScalableListPolynomialSpace(this) +public inline val A.scalablePolynomialSpace: ScalablePolynomialSpace where A : Ring, A : ScaleOperations + get() = ScalablePolynomialSpace(this) /** - * Creates a [ScalableListPolynomialSpace]'s scope over a received scalable ring. + * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.scalableListPolynomialSpace(block: ScalableListPolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { +public inline fun A.scalablePolynomialSpace(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalableListPolynomialSpace(this).block() + return ScalablePolynomialSpace(this).block() } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index b55f16cf2..34d7bcf41 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.invoke @@ -32,7 +32,7 @@ public class LinearInterpolator>(override val algebra: Field>( val x02 = x0 * x0 val x03 = x02 * x0 //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = ListPolynomial( + val polynomial = Polynomial( a - b * x0 + c * x02 - d * x03, b - 2 * c * x0 + 3 * d * x02, c - 3 * d * x0, diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt deleted file mode 100644 index 117ffb579..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -@file:Suppress("LocalVariableName") - -package space.kscience.kmath.functions - -import space.kscience.kmath.functions.testUtils.* -import kotlin.test.* - - -class ListPolynomialTest { - @Test - fun test_Polynomial_Constant_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(-2)) + Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() + Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - ListPolynomial(Rational(-2)) + Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - ListPolynomial() + Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial(Rational(2)) - Rational(2), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - ListPolynomial() - Rational(0), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - ListPolynomial(Rational(2)) - Rational(1), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - ListPolynomial() - Rational(2), - "test 7" - ) - } - } - @Test - fun test_Polynomial_Constant_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - ListPolynomial(22, 26, 13, 15, 26) * m(27), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(7, 0, 49, 21, 14) * m(15), - "test 2" - ) - } - } - @Test - fun test_Constant_Polynomial_plus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(2) + ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) + ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), - Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(-1)), - Rational(1) + ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(2)), - Rational(2) + ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_minus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), - Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(-2) - ListPolynomial(Rational(-2)), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0)), - Rational(0) - ListPolynomial(), - "test 4" - ) - assertEquals( - ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), - Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), - "test 5" - ) - assertEquals( - ListPolynomial(Rational(1)), - Rational(-1) - ListPolynomial(Rational(-2)), - "test 6" - ) - assertEquals( - ListPolynomial(Rational(-2)), - Rational(-2) - ListPolynomial(), - "test 7" - ) - } - } - @Test - fun test_Constant_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - assertEquals( - ListPolynomial(34, 2, 1, 20, 2), - m(27) * ListPolynomial(22, 26, 13, 15, 26), - "test 1" - ) - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - m(15) * ListPolynomial(7, 0, 49, 21, 14), - "test 2" - ) - } - } - @Test - fun test_Polynomial_unaryMinus() { - RationalField.listPolynomialSpace { - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), - -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), - "test 2" - ) - } - } - @Test - fun test_Polynomial_Polynomial_plus() { - RationalField.listPolynomialSpace { - // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 - assertEquals( - ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + - ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 - assertEquals( - ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + - ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 - assertEquals( - ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + - ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + - ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_minus() { - RationalField.listPolynomialSpace { - // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 - assertEquals( - ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), - ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - - ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), - "test 1" - ) - // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 - assertEquals( - ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), - ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - - ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), - "test 2" - ) - // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 - assertEquals( - ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), - ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - - ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), - "test 3" - ) - // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0)), - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - - ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), - "test 4" - ) - } - } - @Test - fun test_Polynomial_Polynomial_times() { - IntModuloRing(35).listPolynomialSpace { - // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 - assertEquals( - ListPolynomial(1, 0, 1, 0, 1), - ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), - "test 1" - ) - // Spoiler: 5 * 7 = 0 - assertEquals( - ListPolynomial(0, 0, 0, 0, 0), - ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), - "test 2" - ) - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt deleted file mode 100644 index 153b0134b..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ /dev/null @@ -1,134 +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.functions.testUtils.Rational -import space.kscience.kmath.functions.testUtils.RationalField -import space.kscience.kmath.misc.UnstableKMathAPI -import kotlin.test.Test -import kotlin.test.assertEquals - - -@OptIn(UnstableKMathAPI::class) -class ListPolynomialUtilTest { - @Test - fun test_Polynomial_substitute_Double() { - assertEquals( - 0.0, - ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 0.0, - ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), - 0.001, - "test 1" - ) - assertEquals( - 1.1931904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 2" - ) - assertEquals( - 0.5681904761904762, - ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), - 0.001, - "test 3" - ) - assertEquals( - 1.1811904761904761, - ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), - 0.001, - "test 4" - ) - assertEquals( - 1.1703333333333332, - ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), - 0.001, - "test 5" - ) - } - @Test - fun test_Polynomial_substitute_Constant() { - assertEquals( - Rational(0), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), - "test 1" - ) - assertEquals( - Rational(25057, 21000), - ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 2" - ) - assertEquals( - Rational(2983, 5250), - ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 3" - ) - assertEquals( - Rational(4961, 4200), - ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), - "test 4" - ) - assertEquals( - Rational(3511, 3000), - ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), - "test 5" - ) - } - @Test - fun test_Polynomial_derivative() { - assertEquals( - ListPolynomial(Rational(-2), Rational(2)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), - "test 4" - ) - } - @Test - fun test_Polynomial_antiderivative() { - assertEquals( - ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), - "test 1" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 2" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), - "test 3" - ) - assertEquals( - ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), - "test 4" - ) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt new file mode 100644 index 000000000..7e0c6cdf2 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -0,0 +1,303 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.functions.testUtils.* +import kotlin.test.* + + +class PolynomialTest { + @Test + fun test_Polynomial_Constant_plus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial() + Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Polynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Polynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Polynomial() - Rational(0), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Polynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Polynomial() - Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).polynomialSpace { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + Polynomial(22, 26, 13, 15, 26) * m(27), + "test 1" + ) + assertEquals( + Polynomial(0, 0, 0, 0, 0), + Polynomial(7, 0, 49, 21, 14) * m(15), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(2) + Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(0) + Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(-1)), + Rational(1) + Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(2)), + Rational(2) + Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(-2) - Polynomial(Rational(-2)), + "test 3" + ) + assertEquals( + Polynomial(Rational(0)), + Rational(0) - Polynomial(), + "test 4" + ) + assertEquals( + Polynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - Polynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + Polynomial(Rational(1)), + Rational(-1) - Polynomial(Rational(-2)), + "test 6" + ) + assertEquals( + Polynomial(Rational(-2)), + Rational(-2) - Polynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).polynomialSpace { + assertEquals( + Polynomial(34, 2, 1, 20, 2), + m(27) * Polynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + Polynomial(0, 0, 0, 0, 0), + m(15) * Polynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.polynomialSpace { + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + Polynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.polynomialSpace { + // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 + assertEquals( + Polynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + Polynomial(Rational(-2, 9), Rational(-8, 3)) + + Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 + assertEquals( + Polynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), + Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + Polynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.polynomialSpace { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + Polynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), + Polynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - + Polynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 + assertEquals( + Polynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), + Polynomial(Rational(-2, 9), Rational(-8, 3)) - + Polynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + Polynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), + Polynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - + Polynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0)), + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - + Polynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).polynomialSpace { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + Polynomial(1, 0, 1, 0, 1), + Polynomial(1, -1, 1) * Polynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + Polynomial(0, 0, 0, 0, 0), + Polynomial(5, -25, 10) * Polynomial(21, 14, -7), + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt new file mode 100644 index 000000000..820b487b4 --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -0,0 +1,134 @@ +/* + * 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.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.misc.UnstableKMathAPI +import kotlin.test.Test +import kotlin.test.assertEquals + + +@OptIn(UnstableKMathAPI::class) +class PolynomialUtilTest { + @Test + fun test_Polynomial_substitute_Double() { + assertEquals( + 0.0, + Polynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 0.0, + Polynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 1.1931904761904761, + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 2" + ) + assertEquals( + 0.5681904761904762, + Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 3" + ) + assertEquals( + 1.1811904761904761, + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + 0.001, + "test 4" + ) + assertEquals( + 1.1703333333333332, + Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + 0.001, + "test 5" + ) + } + @Test + fun test_Polynomial_substitute_Constant() { + assertEquals( + Rational(0), + Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + Polynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_Polynomial_derivative() { + assertEquals( + Polynomial(Rational(-2), Rational(2)), + Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_Polynomial_antiderivative() { + assertEquals( + Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index aae0ad017..afeba0be4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.integration -import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.integrate import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField @@ -19,7 +19,7 @@ class SplineIntegralTest { @Test fun integratePolynomial(){ - val polynomial = ListPolynomial(1.0, 2.0, 3.0) + val polynomial = Polynomial(1.0, 2.0, 3.0) val integral = polynomial.integrate(DoubleField,1.0..2.0) assertEquals(11.0, integral, 0.001) } diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index 88ee1cbb8..6243818b4 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.functions.testUtils.assertEquals import space.kscience.kmath.functions.testUtils.Rational import space.kscience.kmath.functions.testUtils.RationalField import space.kscience.kmath.functions.testUtils.iota diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 997a966a7..e534c243e 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -6,13 +6,13 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpace -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): Polynomial = +public fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): Polynomial = +public fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, modulus) }) public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun ListPolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +public fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt new file mode 100644 index 000000000..933c4dc4c --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + +package space.kscience.kmath.functions.testUtils + +import space.kscience.kmath.operations.Ring + + +public class IntModulo { + public val residue: Int + public val modulus: Int + + @PublishedApi + internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { + if (toCheckInput) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + this.residue = residue.mod(this.modulus) + } else { + this.residue = residue + this.modulus = modulus + } + } + + public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + + public operator fun unaryPlus(): IntModulo = this + public operator fun unaryMinus(): IntModulo = + IntModulo( + if (residue == 0) 0 else modulus - residue, + modulus, + toCheckInput = false + ) + public operator fun plus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not add two residue different modulo" } + return IntModulo( + (residue + other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun plus(other: Int): IntModulo = + IntModulo( + (residue + other) % modulus, + modulus, + toCheckInput = false + ) + public operator fun minus(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not subtract two residue different modulo" } + return IntModulo( + (residue - other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun minus(other: Int): IntModulo = + IntModulo( + (residue - other) % modulus, + modulus, + toCheckInput = false + ) + public operator fun times(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not multiply two residue different modulo" } + return IntModulo( + (residue * other.residue) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun times(other: Int): IntModulo = + IntModulo( + (residue * other) % modulus, + modulus, + toCheckInput = false + ) + public operator fun div(other: IntModulo): IntModulo { + require(modulus == other.modulus) { "can not divide two residue different modulo" } + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + public operator fun div(other: Int): IntModulo { + val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) + require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } + return IntModulo( + (residue * reciprocalCandidate) % modulus, + modulus, + toCheckInput = false + ) + } + override fun equals(other: Any?): Boolean = + when (other) { + is IntModulo -> residue == other.residue && modulus == other.modulus + else -> false + } + + override fun hashCode(): Int = residue.hashCode() + + override fun toString(): String = "$residue mod $modulus" +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") +public class IntModuloRing : Ring { + + public val modulus: Int + + public constructor(modulus: Int) { + require(modulus != 0) { "modulus can not be zero" } + this.modulus = if (modulus < 0) -modulus else modulus + } + + override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) + override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) + + public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) + + override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right + override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right + + override inline fun IntModulo.unaryMinus(): IntModulo = -this + override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg + override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg + override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg + public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg +} \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt new file mode 100644 index 000000000..32ca1c3aa --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -0,0 +1,20 @@ +/* + * 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.testUtils + +import space.kscience.kmath.functions.ListPolynomial +import space.kscience.kmath.functions.Polynomial +import space.kscience.kmath.functions.ListPolynomialSpace +import space.kscience.kmath.functions.PolynomialSpaceOverRing + + +public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) +public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = + ListPolynomial(coefs.map { IntModulo(it, modulus) }) + +public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt new file mode 100644 index 000000000..ff67f19d8 --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt @@ -0,0 +1,29 @@ +/* + * 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.testUtils + +import kotlin.math.abs + + +internal data class BezoutIdentityWithGCD(val first: T, val second: T, val gcd: T) + +internal tailrec fun gcd(a: Long, b: Long): Long = if (a == 0L) abs(b) else gcd(b % a, a) + +internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD = + when { + a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } + a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) } + b < 0 -> with(bezoutIdentityWithGCDInternalLogic(a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(first, -second, gcd) } + else -> bezoutIdentityWithGCDInternalLogic(a, b, 1, 0, 0, 1) + } + +internal tailrec fun bezoutIdentityWithGCDInternalLogic(a: Int, b: Int, m1: Int, m2: Int, m3: Int, m4: Int): BezoutIdentityWithGCD = + if (b == 0) BezoutIdentityWithGCD(m1, m3, a) + else { + val quotient = a / b + val reminder = a % b + bezoutIdentityWithGCDInternalLogic(b, reminder, m2, m1 - quotient * m2, m4, m3 - quotient * m4) + } \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt new file mode 100644 index 000000000..27b0eb21e --- /dev/null +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -0,0 +1,177 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") + +package space.kscience.kmath.functions.testUtils + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.NumbersAddOps + +@Suppress("NAME_SHADOWING") +public class Rational { + public companion object { + public val ZERO: Rational = Rational(0L) + public val ONE: Rational = Rational(1L) + } + + public val numerator: Long + public 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 + } + } + + public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) + public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) + public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) + public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) + public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) + public constructor(numerator: Long) : this(numerator, 1L, false) + + public operator fun unaryPlus(): Rational = this + public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + public operator fun plus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator + dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false + ) + } + public operator fun plus(other: Int): Rational = + Rational( + numerator + denominator * other.toLong(), + denominator, + toCheckInput = false + ) + public operator fun plus(other: Long): Rational = + Rational( + numerator + denominator * other, + denominator, + toCheckInput = false + ) + public operator fun minus(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val dividedThisDenominator = denominator / denominatorsGcd + val dividedOtherDenominator = other.denominator / denominatorsGcd + val numeratorCandidate = numerator * dividedOtherDenominator - dividedThisDenominator * other.numerator + val secondGcd = gcd(numeratorCandidate, denominatorsGcd) + return Rational( + numeratorCandidate / secondGcd, + dividedThisDenominator * (other.denominator / secondGcd), + toCheckInput = false + ) + } + public operator fun minus(other: Int): Rational = + Rational( + numerator - denominator * other.toLong(), + denominator, + toCheckInput = false + ) + public operator fun minus(other: Long): Rational = + Rational( + numerator - denominator * other, + denominator, + toCheckInput = false + ) + public operator fun times(other: Rational): Rational { + val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) + val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) + return Rational( + (numerator / otherDenominatorAndThisNumeratorGcd) * (other.numerator / thisDenominatorAndOtherNumeratorGcd), + (denominator / thisDenominatorAndOtherNumeratorGcd) * (other.denominator / otherDenominatorAndThisNumeratorGcd), + toCheckInput = false + ) + } + public operator fun times(other: Int): Rational { + val other = other.toLong() + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false + ) + } + public operator fun times(other: Long): Rational { + val denominatorAndOtherGcd = gcd(denominator, other) + return Rational( + numerator * (other / denominatorAndOtherGcd), + denominator / denominatorAndOtherGcd, + toCheckInput = false + ) + } + public operator fun div(other: Rational): Rational { + val denominatorsGcd = gcd(denominator, other.denominator) + val numeratorsGcd = gcd(numerator, other.numerator) + return Rational( + (numerator / numeratorsGcd) * (other.denominator / denominatorsGcd), + (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) + ) + } + public operator fun div(other: Int): Rational { + val other = other.toLong() + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false + ) + } + public operator fun div(other: Long): Rational { + val numeratorAndOtherGcd = gcd(numerator, other) + return Rational( + numerator / numeratorAndOtherGcd, + denominator * (other / numeratorAndOtherGcd), + toCheckInput = false + ) + } + 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") +@OptIn(UnstableKMathAPI::class) +public object RationalField : Field, NumbersAddOps { + 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 +} \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 9ca5f43a3..5d0b77aa8 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ b/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -91,7 +91,6 @@ public fun assertEquals( ) } -// FIXME: Don't understand why but the same function from test-utils-functions module can not be used public inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, From 5bc627f1d414730c2b2383a179edf290f6e5a47f Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 01:56:34 +0300 Subject: [PATCH 118/174] Rollback all breaking changes. The only breaking change now is value class. --- .../kscience/kmath/functions/Piecewise.kt | 8 ++-- .../kscience/kmath/functions/Polynomial.kt | 24 +++------- .../kmath/functions/polynomialUtil.kt | 32 ++++--------- .../kmath/integration/SplineIntegrator.kt | 3 +- .../kmath/interpolation/Interpolator.kt | 4 +- .../kmath/functions/PolynomialUtilTest.kt | 46 +++++++++---------- 6 files changed, 45 insertions(+), 72 deletions(-) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index cfd21d552..16af7f555 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -117,16 +117,16 @@ public fun > PiecewisePolynomial( * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ -public fun , C : Ring> PiecewisePolynomial.substitute(ring: C, arg: T): T? = - findPiece(arg)?.substitute(ring, arg) +public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = + findPiece(arg)?.value(ring, arg) /** * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { substitute(ring, it) } +public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } /** * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. */ public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { substitute(ring, it) ?: defaultValue } + { value(ring, it) ?: defaultValue } 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 061f556f6..bfb378cce 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 @@ -59,12 +59,12 @@ public value class Polynomial( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public open class PolynomialSpace>( +public open class PolynomialSpace( /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. */ public val ring: A, -) : Ring> { +) : Ring>, ScaleOperations> where A : Ring, A : ScaleOperations { /** * Instance of zero constant (zero of the underlying ring). @@ -267,13 +267,15 @@ public open class PolynomialSpace>( override fun add(left: Polynomial, right: Polynomial): Polynomial = left + right override fun multiply(left: Polynomial, right: Polynomial): Polynomial = left * right + override fun scale(a: Polynomial, value: Double): Polynomial = + ring { Polynomial(a.coefficients.map { scale(it, value) }) } // TODO: When context receivers will be ready move all of this substitutions and invocations to utilities with // [ListPolynomialSpace] as a context receiver /** * Evaluates value of [this] polynomial on provided [argument]. */ - public inline fun Polynomial.substitute(argument: C): C = substitute(ring, argument) + public inline fun Polynomial.substitute(argument: C): C = value(ring, argument) /** * Represent [this] polynomial as a regular context-less function. @@ -283,19 +285,5 @@ public open class PolynomialSpace>( /** * Evaluates value of [this] polynomial on provided [argument]. */ - public inline operator fun Polynomial.invoke(argument: C): C = substitute(ring, argument) -} - -/** - * Space of polynomials constructed over ring. - * - * @param C the type of constants. Polynomials have them as a coefficients in their terms. - * @param A type of underlying ring of constants. It's [Ring] of [C]. - * @param ring underlying ring of constants of type [A]. - */ -public class ScalablePolynomialSpace( - ring: A, -) : PolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(a.coefficients.map { scale(it, value) }) } + public inline operator fun Polynomial.invoke(argument: C): C = value(ring, argument) } 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 0e1259bee..f745bf6e4 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 @@ -16,36 +16,22 @@ import kotlin.math.pow /** * Creates a [PolynomialSpace] over a received ring. */ -public inline val > A.polynomialSpace: PolynomialSpace +public inline val A.polynomialSpace: PolynomialSpace where A : Ring, A : ScaleOperations get() = PolynomialSpace(this) /** * Creates a [PolynomialSpace]'s scope over a received ring. */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun , R> A.polynomialSpace(block: PolynomialSpace.() -> R): R { +public inline fun A.polynomialSpace(block: PolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return PolynomialSpace(this).block() } -/** - * Creates a [ScalablePolynomialSpace] over a received scalable ring. - */ -public inline val A.scalablePolynomialSpace: ScalablePolynomialSpace where A : Ring, A : ScaleOperations - get() = ScalablePolynomialSpace(this) - -/** - * Creates a [ScalablePolynomialSpace]'s scope over a received scalable ring. - */ // TODO: When context will be ready move [ListPolynomialSpace] and add [A] to context receivers of [block] -public inline fun A.scalablePolynomialSpace(block: ScalablePolynomialSpace.() -> R): R where A : Ring, A : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ScalablePolynomialSpace(this).block() -} - /** * Evaluates value of [this] Double polynomial on provided Double argument. */ -public fun Polynomial.substitute(arg: Double): Double = +public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexedOrNull { index, acc, c -> acc + c * arg.pow(index) } ?: .0 @@ -55,7 +41,7 @@ public fun Polynomial.substitute(arg: Double): Double = * * It is an implementation of [Horner's method](https://en.wikipedia.org/wiki/Horner%27s_method). */ -public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { +public fun Polynomial.value(ring: Ring, arg: C): C = ring { if (coefficients.isEmpty()) return zero var result: C = coefficients.last() for (j in coefficients.size - 2 downTo 0) { @@ -67,13 +53,13 @@ public fun Polynomial.substitute(ring: Ring, arg: C): C = ring { /** * Represent [this] polynomial as a regular context-less function. */ -public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { substitute(ring, it) } +public fun > Polynomial.asFunctionOver(ring: A): (C) -> C = { value(ring, it) } /** * Returns algebraic derivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.derivative( +public fun Polynomial.differentiate( ring: A, ): Polynomial where A : Ring, A : NumericAlgebra = ring { Polynomial( @@ -87,7 +73,7 @@ public fun Polynomial.derivative( * Returns algebraic antiderivative of received polynomial. */ @UnstableKMathAPI -public fun Polynomial.antiderivative( +public fun Polynomial.integrate( ring: A, ): Polynomial where A : Field, A : NumericAlgebra = ring { Polynomial( @@ -106,6 +92,6 @@ public fun > Polynomial.integrate( ring: Field, range: ClosedRange, ): C { - val antiderivative = antiderivative(ring) - return ring { antiderivative.substitute(ring, range.endInclusive) - antiderivative.substitute(ring, range.start) } + val antiderivative = integrate(ring) + return ring { antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) } } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index 0fcd4c6e5..eb88d9ae0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.integration import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.integrate -import space.kscience.kmath.functions.antiderivative import space.kscience.kmath.interpolation.PolynomialInterpolator import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials @@ -24,7 +23,7 @@ import space.kscience.kmath.structures.MutableBufferFactory @OptIn(PerformancePitfall::class) @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.antiderivative(algebra) }) + PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) /** * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 62819be0c..2266092a3 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -10,7 +10,7 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.functions.substitute +import space.kscience.kmath.functions.value import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.structures.Buffer @@ -34,7 +34,7 @@ public interface PolynomialInterpolator> : Interpolator): PiecewisePolynomial override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).substitute(algebra, x) ?: getDefaultValue() + interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() } } diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index 820b487b4..9d0fe4cc3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -15,119 +15,119 @@ import kotlin.test.assertEquals @OptIn(UnstableKMathAPI::class) class PolynomialUtilTest { @Test - fun test_Polynomial_substitute_Double() { + fun test_Polynomial_value_Double() { assertEquals( 0.0, - Polynomial(1.0, -2.0, 1.0).substitute(1.0), + Polynomial(1.0, -2.0, 1.0).value(1.0), 0.001, "test 1" ) assertEquals( 0.0, - Polynomial(1.0, -2.0, 1.0).substitute(1.0), + Polynomial(1.0, -2.0, 1.0).value(1.0), 0.001, "test 1" ) assertEquals( 1.1931904761904761, - Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).value(0.2), 0.001, "test 2" ) assertEquals( 0.5681904761904762, - Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + Polynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).value(0.2), 0.001, "test 3" ) assertEquals( 1.1811904761904761, - Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + Polynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).value(0.2), 0.001, "test 4" ) assertEquals( 1.1703333333333332, - Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + Polynomial(0.625, 2.6666666666666665, 0.0, 1.5).value(0.2), 0.001, "test 5" ) } @Test - fun test_Polynomial_substitute_Constant() { + fun test_Polynomial_value_Constant() { assertEquals( Rational(0), - Polynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + Polynomial(Rational(1), Rational(-2), Rational(1)).value(RationalField, Rational(1)), "test 1" ) assertEquals( Rational(25057, 21000), Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 2" ) assertEquals( Rational(2983, 5250), Polynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 3" ) assertEquals( Rational(4961, 4200), Polynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 4" ) assertEquals( Rational(3511, 3000), Polynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) - .substitute(RationalField, Rational(1, 5)), + .value(RationalField, Rational(1, 5)), "test 5" ) } @Test - fun test_Polynomial_derivative() { + fun test_Polynomial_differentiate() { assertEquals( Polynomial(Rational(-2), Rational(2)), - Polynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + Polynomial(Rational(1), Rational(-2), Rational(1)).differentiate(RationalField), "test 1" ) assertEquals( Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField), "test 2" ) assertEquals( Polynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).differentiate(RationalField), "test 3" ) assertEquals( Polynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).differentiate(RationalField), "test 4" ) } @Test - fun test_Polynomial_antiderivative() { + fun test_Polynomial_integrate() { assertEquals( Polynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), - Polynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + Polynomial(Rational(1), Rational(-2), Rational(1)).integrate(RationalField), "test 1" ) assertEquals( Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField), "test 2" ) assertEquals( Polynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), - Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + Polynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).integrate(RationalField), "test 3" ) assertEquals( Polynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), - Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + Polynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).integrate(RationalField), "test 4" ) } From f7d159bc036d2fa2496906e612db67fa6ce42e06 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 02:05:29 +0300 Subject: [PATCH 119/174] Made IntModulo implement ScaleOperations. --- .../space/kscience/kmath/functions/testUtils/IntModulo.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 933c4dc4c..21095d858 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations public class IntModulo { @@ -108,7 +109,7 @@ public class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -public class IntModuloRing : Ring { +public class IntModuloRing : Ring, ScaleOperations { public val modulus: Int @@ -130,4 +131,6 @@ public class IntModuloRing : Ring { override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg + + override fun scale(a: IntModulo, value: Double): IntModulo = a * value.toInt() } \ No newline at end of file From 0eb9bd810c26fffff4f4542cf256f643a6279cc2 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 12 Jul 2022 22:56:08 +0300 Subject: [PATCH 120/174] Kotlin 1.7.10 --- .space.kts | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.space.kts b/.space.kts index d70ad6d59..c9500e967 100644 --- a/.space.kts +++ b/.space.kts @@ -1,3 +1,3 @@ job("Build") { gradlew("openjdk:11", "build") -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5202289fa..6b45ee49f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,4 +12,4 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.11.7-kotlin-1.7.0 +toolsVersion=0.11.8-kotlin-1.7.10 From 87aeda84d9fcbbed2a250695010fb7f254acb276 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Tue, 12 Jul 2022 23:10:38 +0300 Subject: [PATCH 121/174] Added MathJax to docs. --- kmath-functions/build.gradle.kts | 4 ++++ .../space/kscience/kmath/functions/Polynomial.kt | 10 +++++++--- kmath-polynomial/build.gradle.kts | 4 ++++ .../LabeledPolynomial.kt | 13 +++++++++---- .../ListPolynomial.kt | 9 ++++++--- .../NumberedPolynomial.kt | 13 +++++++------ .../labeledConstructors.kt | 14 +++++++++----- .../numberedConstructors.kt | 12 ++++++++---- 8 files changed, 54 insertions(+), 25 deletions(-) diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 0a8e8a1be..149a8f277 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -19,6 +19,10 @@ kotlin.sourceSets { } } +dependencies { + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") +} + readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) 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 bfb378cce..1e811d3ba 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 @@ -23,8 +23,10 @@ import kotlin.math.min @JvmInline public value class Polynomial( /** - * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed - * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. + * + * Every monomial \(a x^d\) is stored as a coefficient \(a\) placed + * into the list at index \(d\). For example, coefficients of a polynomial \(5 x^2 - 6\) can be represented as * ``` * listOf( * -6, // -6 + @@ -42,9 +44,11 @@ public value class Polynomial( * 0, // 0 x^4 * ) * ``` - * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * It is not prohibited to put extra zeros at end of the list (as for \(0x^3\) and \(0x^4\) in the example). But the * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. + * + * @usesMathJax */ public val coefficients: List ) { diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index dcfcb1b46..b0f4a095c 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -20,6 +20,10 @@ kotlin.sourceSets { } } +dependencies { + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") +} + readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index 7f107a87f..12bf9f839 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -25,9 +25,9 @@ internal constructor( /** * Map that contains coefficients of the polynomial. * - * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the - * coefficient `a` and the key is a map that associates variables in the monomial with their degree in the monomial. - * For example, coefficients of a polynomial `5 a^2 c^3 - 6 b` can be represented as + * Every monomial \(a x_1^{d_1} ... x_n^{d_n}\) is stored as a pair "key-value" in the map, where the value is the + * coefficient \(a\) and the key is a map that associates variables in the monomial with their degree in the monomial. + * For example, coefficients of a polynomial \(5 a^2 c^3 - 6 b\) can be represented as * ``` * mapOf( * mapOf( @@ -55,7 +55,12 @@ internal constructor( * ) to 0 * ) * ``` - * where `a`, `b` and `c` are corresponding [Symbol] objects. + * where \(a\), \(b\) and \(c\) are corresponding [Symbol] objects. + * + * It is not prohibited to put extra zero monomials into the map (as for \(0 b c\) in the example). But the + * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is + * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + * @usesMathJax */ public val coefficients: Map, C> ) : Polynomial { diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt index 76e1a6bb6..91b9c7658 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -21,8 +21,10 @@ import kotlin.math.min */ public data class ListPolynomial( /** - * List that contains coefficients of the polynomial. Every monomial `a x^d` is stored as a coefficient `a` placed - * into the list at index `d`. For example, coefficients of a polynomial `5 x^2 - 6` can be represented as + * List that contains coefficients of the polynomial. + * + * Every monomial \(a x^d\) is stored as a coefficient \(a\) placed + * into the list at index \(d\). For example, coefficients of a polynomial \(5 x^2 - 6\) can be represented as * ``` * listOf( * -6, // -6 + @@ -40,9 +42,10 @@ public data class ListPolynomial( * 0, // 0 x^4 * ) * ``` - * It is not prohibited to put extra zeros at end of the list (as for `0x^3` and `0x^4` in the example). But the + * It is not prohibited to put extra zeros at end of the list (as for \(0x^3\) and \(0x^4\) in the example). But the * longer the coefficients list the worse performance of arithmetical operations performed on it. Thus, it is * recommended not to put (or even to remove) extra (or useless) coefficients at the end of the coefficients list. + * @usesMathJax */ public val coefficients: List ) : Polynomial { diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index f7dd9d8de..96c96e555 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -24,9 +24,9 @@ internal constructor( /** * Map that contains coefficients of the polynomial. * - * Every monomial `a x_1^{d_1} ... x_n^{d_n}` is stored as a pair "key-value" in the map, where the value is the - * coefficient `a` and the key is a list that associates index of every variable in the monomial with their degree - * in the monomial. For example, coefficients of a polynomial `5 x_1^2 x_3^3 - 6 x_2` can be represented as + * Every monomial \(a x_1^{d_1} ... x_n^{d_n}\) is stored as a pair "key-value" in the map, where the value is the + * coefficient \(a\) and the key is a list that associates index of every variable in the monomial with their degree + * in the monomial. For example, coefficients of a polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be represented as * ``` * mapOf( * listOf(2, 0, 3) to 5, // 5 x_1^2 x_3^3 + @@ -41,9 +41,10 @@ internal constructor( * listOf(0, 1, 1) to 0, // 0 x_2^1 x_3^1 * ) * ``` - * It is not prohibited to put extra zero monomials into the map (as for `0 x_2 x_3` in the example). But the + * It is not prohibited to put extra zero monomials into the map (as for \(0 x_2 x_3\) in the example). But the * bigger the coefficients map the worse performance of arithmetical operations performed on it. Thus, it is * recommended not to put (or even to remove) extra (or useless) monomials in the coefficients map. + * @usesMathJax */ public val coefficients: Map, C> ) : Polynomial { @@ -325,7 +326,7 @@ public class NumberedPolynomialSpace>( /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, - * the result is `-1`. + * the result is -1. */ public val NumberedPolynomial.lastVariable: Int get() = coefficients.keys.maxOfOrNull { degs -> degs.lastIndex } ?: -1 @@ -365,7 +366,7 @@ public class NumberedPolynomialSpace>( } ?: 0u /** * Count of variables occurring in the polynomial with positive power. If there is no such variable, - * the result is `0`. + * the result is 0. */ public val NumberedPolynomial.countOfVariables: Int get() = diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index 819a36449..d23efc5c2 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -262,7 +262,7 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo /** * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. * - * For example, polynomial `5 a^2 c^3 - 6 b` can be described as + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -271,6 +271,7 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo * } * } * ``` + * @usesMathJax */ @DslMarker @UnstableKMathAPI @@ -385,7 +386,7 @@ public class DSL1LabeledPolynomialBuilder( ///** // * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as // * ``` // * Int.algebra { // * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { @@ -394,6 +395,7 @@ public class DSL1LabeledPolynomialBuilder( // * } // * } // * ``` +// * @usesMathJax // */ // FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: // 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. @@ -404,7 +406,7 @@ public class DSL1LabeledPolynomialBuilder( /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { @@ -413,14 +415,15 @@ public class DSL1LabeledPolynomialBuilder( * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as - * ``` + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * `` * Int.algebra { * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + @@ -428,6 +431,7 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt index 8d2c9e617..051019159 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt @@ -243,7 +243,7 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere /** * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -252,6 +252,7 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere * } * } * ``` + * @usesMathJax */ @DslMarker @UnstableKMathAPI @@ -372,7 +373,7 @@ public class DSL1NumberedPolynomialBuilder( ///** // * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as +// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as // * ``` // * Int.algebra { // * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -381,6 +382,7 @@ public class DSL1NumberedPolynomialBuilder( // * } // * } // * ``` +// * @usesMathJax // */ // FIXME: For now this fabric does not let next two fabrics work. (See KT-52803.) Possible feature solutions: // 1. `LowPriorityInOverloadResolution` becomes public. Then it should be applied to this function. @@ -391,7 +393,7 @@ public class DSL1NumberedPolynomialBuilder( /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -400,13 +402,14 @@ public class DSL1NumberedPolynomialBuilder( * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * - * For example, polynomial `5 x_1^2 x_3^3 - 6 x_2` can be described as + * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { @@ -415,6 +418,7 @@ public inline fun > NumberedPolynomialSpace.NumberedPolynomi * } * } * ``` + * @usesMathJax */ @UnstableKMathAPI public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() From 4ea29c82c5abcc079123bd964f77ac4ea0e307a8 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 13 Jul 2022 12:05:53 +0300 Subject: [PATCH 122/174] Small fix of DSL1. --- .../kscience/kmath/functions/polynomials.kt | 4 +- .../labeledConstructors.kt | 40 +++++++++---------- .../numberedConstructors.kt | 36 ++++++++--------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index 4151b0283..c65ca589d 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -107,8 +107,8 @@ fun numberedPolynomialsExample() { // Also there is DSL for constructing NumberedPolynomials: val polynomial5: NumberedPolynomial = NumberedPolynomialDSL1 { 3 {} - 5 { 2 inPowerOf 1u } - -7 with { 1 pow 2u; 3 pow 1u } + 5 { 1 inPowerOf 1u } + -7 with { 0 pow 2u; 2 pow 1u } // `pow` and `inPowerOf` are the same // `with` is omittable } diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index d23efc5c2..aa44660c1 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -265,7 +265,7 @@ public inline fun C.asLabeledPolynomial() : LabeledPolynomial = LabeledPo * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as * ``` * Int.algebra { - * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + * (-6) { b inPowerOf 1u } // (-6) b^1 * } @@ -339,18 +339,18 @@ public class DSL1LabeledPolynomialBuilder( /** * Initial capacity of coefficients map. */ - initialCapacity: Int = 0 + initialCapacity: Int? = null ) { /** * Coefficients storage. Any declaration of any monomial updates the storage. * Afterward the storage will be used as a resulting coefficients map. */ - private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + private val coefficients: MutableMap, C> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap() /** * Builds the resulting coefficients map. * - * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. */ @PublishedApi internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) @@ -386,12 +386,12 @@ public class DSL1LabeledPolynomialBuilder( ///** // * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as +// * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as // * ``` // * Int.algebra { -// * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { -// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + -// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { +// * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + +// * (-6) { b inPowerOf 1u } // (-6) b^1 // * } // * } // * ``` @@ -402,39 +402,39 @@ public class DSL1LabeledPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = LabeledPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] ring of [LabeledPolynomial]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as * ``` * Int.algebra { - * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledPolynomialSpace.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [LabeledPolynomial] with lambda [block] in context of [this] field of [LabeledRationalFunction]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as - * `` + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as + * ``` * Int.algebra { - * val LabeledPolynomial : LabeledPolynomial = LabeledPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * val labeledPolynomial : LabeledPolynomial = LabeledPolynomialDSL1 { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int = 0, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt index 051019159..ce0db3d17 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt @@ -243,12 +243,12 @@ public inline fun C.asNumberedPolynomial() : NumberedPolynomial = Numbere /** * Marks DSL that allows to more simply create [NumberedPolynomial]s with good performance. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + + * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 * } * } * ``` @@ -285,7 +285,7 @@ public class DSL1NumberedPolynomialTermSignatureBuilder { */ public infix fun Int.inPowerOf(deg: UInt) { if (deg == 0u) return - val index = this - 1 + val index = this if (index > signature.lastIndex) { signature.addAll(List(index - signature.lastIndex - 1) { 0u }) signature.add(deg) @@ -326,13 +326,13 @@ public class DSL1NumberedPolynomialBuilder( /** * Initial capacity of coefficients map. */ - initialCapacity: Int = 0 + initialCapacity: Int? = null ) { /** * Coefficients storage. Any declaration of any monomial updates the storage. * Afterward the storage will be used as a resulting coefficients map. */ - private val coefficients: MutableMap, C> = LinkedHashMap(initialCapacity) + private val coefficients: MutableMap, C> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap() /** * Builds the resulting coefficients map. @@ -373,12 +373,12 @@ public class DSL1NumberedPolynomialBuilder( ///** // * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of constants. // * -// * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as +// * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as // * ``` // * Int.algebra { // * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { -// * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + -// * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 +// * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + +// * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 // * } // * } // * ``` @@ -389,39 +389,39 @@ public class DSL1NumberedPolynomialBuilder( // 2. Union types are implemented. Then all three functions should be rewritten // as one with single union type as a (context) receiver. //@UnstableKMathAPI -//public inline fun > A.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() +//public inline fun > A.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = NumberedPolynomialBuilder(::add, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] ring of [NumberedPolynomial]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + + * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedPolynomialSpace.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() /** * Creates [NumberedPolynomial] with lambda [block] in context of [this] field of [NumberedRationalFunction]s. * - * For example, polynomial \(5 x_1^2 x_3^3 - 6 x_2\) can be described as + * For example, polynomial \(5 x_0^2 x_2^3 - 6 x_1\) can be described as * ``` * Int.algebra { * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { - * 5 { 1 inPowerOf 2u; 3 inPowerOf 3u } // 5 x_1^2 x_3^3 + - * (-6) { 2 inPowerOf 1u } // (-6) x_2^1 + * 5 { 0 inPowerOf 2u; 2 inPowerOf 3u } // 5 x_0^2 x_2^3 + + * (-6) { 1 inPowerOf 1u } // (-6) x_1^1 * } * } * ``` * @usesMathJax */ @UnstableKMathAPI -public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int = 0, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +public inline fun > NumberedRationalFunctionSpace.NumberedPolynomialDSL1(initialCapacity: Int? = null, block: DSL1NumberedPolynomialBuilder.() -> Unit) : NumberedPolynomial = DSL1NumberedPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available From 5846f42141a210bef8ba873030f9566ebc14c5e9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 15 Jul 2022 15:21:49 +0300 Subject: [PATCH 123/174] Grand derivative refactoring. Phase 1 --- .../kscience/kmath/expressions/DSCompiler.kt | 90 +- .../kmath/expressions/DerivativeStructure.kt | 191 ++-- .../DerivativeStructureExpression.kt | 327 +++--- .../kscience/kmath/linear/LinearSpace.kt | 2 +- .../space/kscience/kmath/misc/annotations.kt | 2 +- .../space/kscience/kmath/nd/BufferND.kt | 2 +- .../space/kscience/kmath/nd/StructureND.kt | 4 +- .../kmath/operations/DoubleBufferOps.kt | 4 +- .../kmath/operations/bufferOperation.kt | 26 +- .../space/kscience/kmath/structures/Buffer.kt | 8 +- .../space/kscience/kmath/ejml/_generated.kt | 1003 ----------------- .../histogram/UniformHistogramGroupND.kt | 6 +- .../kmath/multik/MultikDoubleAlgebra.kt | 7 + .../space/kscience/kmath/stat/Sampler.kt | 2 +- 14 files changed, 311 insertions(+), 1363 deletions(-) delete mode 100644 kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt index bb88ce52c..e0050cf03 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt @@ -5,11 +5,11 @@ package space.kscience.kmath.expressions + import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableBufferFactory -import kotlin.math.max import kotlin.math.min internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: Int = size) { @@ -54,7 +54,7 @@ internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: * @property order Derivation order. * @see DerivativeStructure */ -internal class DSCompiler> internal constructor( +class DSCompiler> internal constructor( val algebra: A, val bufferFactory: MutableBufferFactory, val freeParameters: Int, @@ -120,8 +120,7 @@ internal class DSCompiler> internal constructor( * This number includes the single 0 order derivative element, which is * guaranteed to be stored in the first element of the array. */ - val size: Int - get() = sizes[freeParameters][order] + val size: Int get() = sizes[freeParameters][order] /** * Get the index of a partial derivative in the array. @@ -178,7 +177,7 @@ internal fun DSCompiler.ln( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : ExponentialOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -211,7 +210,7 @@ internal fun DSCompiler.pow( operandOffset: Int, n: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : PowerOperations = algebra { if (n == 0) { // special case, x^0 = 1 for all x @@ -267,7 +266,7 @@ internal fun DSCompiler.exp( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Ring, A : ScaleOperations, A : ExponentialOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -290,7 +289,7 @@ internal fun DSCompiler.sqrt( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : PowerOperations = algebra { // create the function value and derivatives // [x^(1/n), (1/n)x^((1/n)-1), (1-n)/n^2x^((1/n)-2), ... ] @@ -351,7 +350,7 @@ internal fun DSCompiler.pow( operandOffset: Int, p: Double, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Ring, A : NumericAlgebra, A : PowerOperations, A : ScaleOperations = algebra { // create the function value and derivatives // [x^p, px^(p-1), p(p-1)x^(p-2), ... ] @@ -387,7 +386,7 @@ internal fun DSCompiler.tan( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Ring, A : TrigonometricOperations, A : ScaleOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -469,7 +468,7 @@ internal fun DSCompiler.sin( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Ring, A : ScaleOperations, A : TrigonometricOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -497,7 +496,7 @@ internal fun DSCompiler.acos( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : TrigonometricOperations, A : PowerOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -559,7 +558,7 @@ internal fun DSCompiler.asin( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : TrigonometricOperations, A : PowerOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -618,7 +617,7 @@ internal fun DSCompiler.atan( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : TrigonometricOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -678,7 +677,7 @@ internal fun DSCompiler.cosh( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Ring, A : ScaleOperations, A : ExponentialOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -708,7 +707,7 @@ internal fun DSCompiler.tanh( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : ExponentialOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -765,7 +764,7 @@ internal fun DSCompiler.acosh( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : ExponentialOperations, A : PowerOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -857,7 +856,7 @@ internal fun DSCompiler.sinh( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : ExponentialOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -964,7 +963,7 @@ internal fun DSCompiler.asinh( operand: Buffer, operandOffset: Int, result: MutableBuffer, - resultOffset: Int + resultOffset: Int, ) where A : Field, A : ExponentialOperations, A : PowerOperations = algebra { // create the function value and derivatives val function = bufferFactory(1 + order) { zero } @@ -1109,59 +1108,6 @@ internal fun DSCompiler.atanh( compose(operand, operandOffset, function, result, resultOffset) } -/** - * Get the compiler for number of free parameters and order. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @return cached rules set. - */ -internal fun > getCompiler( - algebra: A, - bufferFactory: MutableBufferFactory, - parameters: Int, - order: Int -): DSCompiler { - // get the cached compilers - val cache: Array?>>? = null - - // we need to create more compilers - val maxParameters: Int = max(parameters, cache?.size ?: 0) - val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) - val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } - - if (cache != null) { - // preserve the already created compilers - for (i in cache.indices) { - cache[i].copyInto(newCache[i], endIndex = cache[i].size) - } - } - - // create the array in increasing diagonal order - - // create the array in increasing diagonal order - for (diag in 0..parameters + order) { - for (o in max(0, diag - parameters)..min(order, diag)) { - val p: Int = diag - o - if (newCache[p][o] == null) { - val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! - val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! - - newCache[p][o] = DSCompiler( - algebra, - bufferFactory, - p, - o, - valueCompiler, - derivativeCompiler, - ) - } - } - } - - return newCache[parameters][order]!! -} - /** * Compile the sizes array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt index a1a6354f0..01c045cdb 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt @@ -6,10 +6,9 @@ package space.kscience.kmath.expressions import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.NumericAlgebra import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer /** * Class representing both the value and the differentials of a function. @@ -28,128 +27,29 @@ import space.kscience.kmath.structures.MutableBuffer * [Commons Math's `DerivativeStructure`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DerivativeStructure.java). */ @UnstableKMathAPI -public open class DerivativeStructure internal constructor( - internal val derivativeAlgebra: DerivativeStructureRing, - internal val compiler: DSCompiler, -) where A : Ring, A : NumericAlgebra, A : ScaleOperations { - /** - * Combined array holding all values. - */ - internal var data: MutableBuffer = - derivativeAlgebra.bufferFactory(compiler.size) { derivativeAlgebra.algebra.zero } +public open class DerivativeStructure> @PublishedApi internal constructor( + private val derivativeAlgebra: DerivativeStructureAlgebra, + @PublishedApi internal val data: Buffer, +) { - /** - * Build an instance with all values and derivatives set to 0. - * - * @param parameters number of free parameters. - * @param order derivation order. - */ - public constructor ( - derivativeAlgebra: DerivativeStructureRing, - parameters: Int, - order: Int, - ) : this( - derivativeAlgebra, - getCompiler(derivativeAlgebra.algebra, derivativeAlgebra.bufferFactory, parameters, order), - ) - - /** - * Build an instance representing a constant value. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param value value of the constant. - * @see DerivativeStructure - */ - public constructor ( - derivativeAlgebra: DerivativeStructureRing, - parameters: Int, - order: Int, - value: T, - ) : this( - derivativeAlgebra, - parameters, - order, - ) { - data[0] = value - } - - /** - * Build an instance representing a variable. - * - * Instances built using this constructor are considered to be the free variables with respect to which - * differentials are computed. As such, their differential with respect to themselves is +1. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param index index of the variable (from 0 to `parameters - 1`). - * @param value value of the variable. - */ - public constructor ( - derivativeAlgebra: DerivativeStructureRing, - parameters: Int, - order: Int, - index: Int, - value: T, - ) : this(derivativeAlgebra, parameters, order, value) { - require(index < parameters) { "number is too large: $index >= $parameters" } - - if (order > 0) { - // the derivative of the variable with respect to itself is 1. - data[getCompiler(derivativeAlgebra.algebra, derivativeAlgebra.bufferFactory, index, order).size] = - derivativeAlgebra.algebra.one - } - } - - /** - * Build an instance from all its derivatives. - * - * @param parameters number of free parameters. - * @param order derivation order. - * @param derivatives derivatives sorted according to [DSCompiler.getPartialDerivativeIndex]. - */ - public constructor ( - derivativeAlgebra: DerivativeStructureRing, - parameters: Int, - order: Int, - vararg derivatives: T, - ) : this( - derivativeAlgebra, - parameters, - order, - ) { - require(derivatives.size == data.size) { "dimension mismatch: ${derivatives.size} and ${data.size}" } - data = derivativeAlgebra.bufferFactory(data.size) { derivatives[it] } - } - - /** - * Copy constructor. - * - * @param ds instance to copy. - */ - internal constructor(ds: DerivativeStructure) : this(ds.derivativeAlgebra, ds.compiler) { - this.data = ds.data.copy() - } + public val compiler: DSCompiler get() = derivativeAlgebra.compiler /** * The number of free parameters. */ - public val freeParameters: Int - get() = compiler.freeParameters + public val freeParameters: Int get() = compiler.freeParameters /** * The derivation order. */ - public val order: Int - get() = compiler.order + public val order: Int get() = compiler.order /** * The value part of the derivative structure. * * @see getPartialDerivative */ - public val value: T - get() = data[0] + public val value: T get() = data[0] /** * Get a partial derivative. @@ -183,4 +83,75 @@ public open class DerivativeStructure internal constructor( public override fun hashCode(): Int = 227 + 229 * freeParameters + 233 * order + 239 * data.hashCode() + + public companion object { + + /** + * Build an instance representing a variable. + * + * Instances built using this constructor are considered to be the free variables with respect to which + * differentials are computed. As such, their differential with respect to themselves is +1. + */ + public fun > variable( + derivativeAlgebra: DerivativeStructureAlgebra, + index: Int, + value: T, + ): DerivativeStructure { + val compiler = derivativeAlgebra.compiler + require(index < compiler.freeParameters) { "number is too large: $index >= ${compiler.freeParameters}" } + return DerivativeStructure(derivativeAlgebra, derivativeAlgebra.bufferForVariable(index, value)) + } + + /** + * Build an instance from all its derivatives. + * + * @param derivatives derivatives sorted according to [DSCompiler.getPartialDerivativeIndex]. + */ + public fun > ofDerivatives( + derivativeAlgebra: DerivativeStructureAlgebra, + vararg derivatives: T, + ): DerivativeStructure { + val compiler = derivativeAlgebra.compiler + require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" } + val data = derivatives.asBuffer() + + return DerivativeStructure( + derivativeAlgebra, + data + ) + } + } +} + +@OptIn(UnstableKMathAPI::class) +private fun > DerivativeStructureAlgebra.bufferForVariable(index: Int, value: T): Buffer { + val buffer = bufferFactory(compiler.size) { algebra.zero } + buffer[0] = value + if (compiler.order > 0) { + // the derivative of the variable with respect to itself is 1. + + val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(numberOfVariables).apply { + set(index, 1) + }) + + buffer[indexOfDerivative] = algebra.one + } + return buffer +} + +/** + * A class implementing both [DerivativeStructure] and [Symbol]. + */ +@UnstableKMathAPI +public class DerivativeStructureSymbol> internal constructor( + derivativeAlgebra: DerivativeStructureAlgebra, + index: Int, + symbol: Symbol, + value: T, +) : Symbol by symbol, DerivativeStructure( + derivativeAlgebra, derivativeAlgebra.bufferForVariable(index, value) +) { + override fun toString(): String = symbol.toString() + override fun equals(other: Any?): Boolean = (other as? Symbol) == symbol + override fun hashCode(): Int = symbol.hashCode() } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt index f91fb55e8..638057921 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt @@ -7,83 +7,89 @@ package space.kscience.kmath.expressions import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableBufferFactory -import space.kscience.kmath.structures.indices +import kotlin.math.max +import kotlin.math.min -/** - * A class implementing both [DerivativeStructure] and [Symbol]. - */ @UnstableKMathAPI -public class DerivativeStructureSymbol( - derivativeAlgebra: DerivativeStructureRing, - size: Int, - order: Int, - index: Int, - symbol: Symbol, - value: T, -) : Symbol by symbol, DerivativeStructure( - derivativeAlgebra, - size, - order, - index, - value -) where A : Ring, A : NumericAlgebra, A : ScaleOperations { - override fun toString(): String = symbol.toString() - override fun equals(other: Any?): Boolean = (other as? Symbol) == symbol - override fun hashCode(): Int = symbol.hashCode() -} - -/** - * A ring over [DerivativeStructure]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters. - */ -@UnstableKMathAPI -public open class DerivativeStructureRing( +public abstract class DerivativeStructureAlgebra>( public val algebra: A, public val bufferFactory: MutableBufferFactory, public val order: Int, bindings: Map, -) : Ring>, ScaleOperations>, - NumericAlgebra>, - ExpressionAlgebra>, - NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { +) : ExpressionAlgebra> { + public val numberOfVariables: Int = bindings.size - override val zero: DerivativeStructure by lazy { - DerivativeStructure( - this, - numberOfVariables, - order, - ) - } - override val one: DerivativeStructure by lazy { - DerivativeStructure( - this, - numberOfVariables, - order, - algebra.one, - ) - } + /** + * Get the compiler for number of free parameters and order. + * + * @return cached rules set. + */ + @PublishedApi + internal val compiler: DSCompiler by lazy { + // get the cached compilers + val cache: Array?>>? = null - override fun number(value: Number): DerivativeStructure = const(algebra.number(value)) + // we need to create more compilers + val maxParameters: Int = max(numberOfVariables, cache?.size ?: 0) + val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) + val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } + + if (cache != null) { + // preserve the already created compilers + for (i in cache.indices) { + cache[i].copyInto(newCache[i], endIndex = cache[i].size) + } + } + + // create the array in increasing diagonal order + for (diag in 0..numberOfVariables + order) { + for (o in max(0, diag - numberOfVariables)..min(order, diag)) { + val p: Int = diag - o + if (newCache[p][o] == null) { + val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! + val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! + + newCache[p][o] = DSCompiler( + algebra, + bufferFactory, + p, + o, + valueCompiler, + derivativeCompiler, + ) + } + } + } + + return@lazy newCache[numberOfVariables][order]!! + } private val variables: Map> = bindings.entries.mapIndexed { index, (key, value) -> key to DerivativeStructureSymbol( this, - numberOfVariables, - order, index, key, value, ) }.toMap() - public override fun const(value: T): DerivativeStructure = - DerivativeStructure(this, numberOfVariables, order, value) + + + public override fun const(value: T): DerivativeStructure { + val buffer = bufferFactory(compiler.size) { algebra.zero } + buffer[0] = value + + return DerivativeStructure( + this, + buffer + ) + } override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[StringSymbol(value)] @@ -103,54 +109,99 @@ public open class DerivativeStructureRing( public fun DerivativeStructure.derivative(vararg symbols: Symbol): T = derivative(symbols.toList()) +} + + +/** + * A ring over [DerivativeStructure]. + * + * @property order The derivation order. + * @param bindings The map of bindings values. All bindings are considered free parameters. + */ +@UnstableKMathAPI +public open class DerivativeStructureRing( + algebra: A, + bufferFactory: MutableBufferFactory, + order: Int, + bindings: Map, +) : DerivativeStructureAlgebra(algebra, bufferFactory, order, bindings), + Ring>, ScaleOperations>, + NumericAlgebra>, + NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { + + override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = + super.bindSymbolOrNull(value) + override fun DerivativeStructure.unaryMinus(): DerivativeStructure { - val ds = DerivativeStructure(this@DerivativeStructureRing, compiler) - for (i in ds.data.indices) { - ds.data[i] = algebra { -data[i] } - } - return ds + val newData = algebra { data.map(bufferFactory) { -it } } + return DerivativeStructure(this@DerivativeStructureRing, newData) } + /** + * Create a copy of given [Buffer] and modify it according to [block] + */ + protected inline fun DerivativeStructure.transformDataBuffer(block: DSCompiler.(MutableBuffer) -> Unit): DerivativeStructure { + val newData = bufferFactory(compiler.size) { data[it] } + compiler.block(newData) + return DerivativeStructure(this@DerivativeStructureRing, newData) + } + + protected fun DerivativeStructure.mapData(block: (T) -> T): DerivativeStructure { + val newData: Buffer = data.map(bufferFactory, block) + return DerivativeStructure(this@DerivativeStructureRing, newData) + } + + protected fun DerivativeStructure.mapDataIndexed(block: (Int, T) -> T): DerivativeStructure { + val newData: Buffer = data.mapIndexed(bufferFactory, block) + return DerivativeStructure(this@DerivativeStructureRing, newData) + } + + override val zero: DerivativeStructure by lazy { + const(algebra.zero) + } + + override val one: DerivativeStructure by lazy { + const(algebra.one) + } + + override fun number(value: Number): DerivativeStructure = const(algebra.number(value)) + override fun add(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure { left.compiler.checkCompatibility(right.compiler) - val ds = DerivativeStructure(left) - left.compiler.add(left.data, 0, right.data, 0, ds.data, 0) - return ds + return left.transformDataBuffer { result -> + add(left.data, 0, right.data, 0, result, 0) + } } - override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure { - val ds = DerivativeStructure(a) - for (i in ds.data.indices) { - ds.data[i] = algebra { ds.data[i].times(value) } - } - return ds + override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = algebra { + a.mapData { it.times(value) } } override fun multiply( left: DerivativeStructure, - right: DerivativeStructure + right: DerivativeStructure, ): DerivativeStructure { left.compiler.checkCompatibility(right.compiler) - val result = DerivativeStructure(this, left.compiler) - left.compiler.multiply(left.data, 0, right.data, 0, result.data, 0) - return result + return left.transformDataBuffer { result -> + multiply(left.data, 0, right.data, 0, result, 0) + } } override fun DerivativeStructure.minus(arg: DerivativeStructure): DerivativeStructure { compiler.checkCompatibility(arg.compiler) - val ds = DerivativeStructure(this) - compiler.subtract(data, 0, arg.data, 0, ds.data, 0) - return ds + return transformDataBuffer { result -> + subtract(data, 0, arg.data, 0, result, 0) + } } - override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure { - val ds = DerivativeStructure(this) - ds.data[0] = algebra { ds.data[0] + number(other) } - return ds + override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure = algebra { + transformDataBuffer { + it[0] += number(other) + } } override operator fun DerivativeStructure.minus(other: Number): DerivativeStructure = - this + -other.toDouble() + this + (-other.toDouble()) override operator fun Number.plus(other: DerivativeStructure): DerivativeStructure = other + this override operator fun Number.minus(other: DerivativeStructure): DerivativeStructure = other - this @@ -194,119 +245,85 @@ public class DerivativeStructureField>( override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure { left.compiler.checkCompatibility(right.compiler) - val result = DerivativeStructure(this, left.compiler) - left.compiler.divide(left.data, 0, right.data, 0, result.data, 0) - return result + return left.transformDataBuffer { result -> + left.compiler.divide(left.data, 0, right.data, 0, result, 0) + } } - override fun sin(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.sin(arg.data, 0, result.data, 0) - return result + override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + sin(arg.data, 0, result, 0) } - override fun cos(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.cos(arg.data, 0, result.data, 0) - return result + override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + cos(arg.data, 0, result, 0) } - override fun tan(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.tan(arg.data, 0, result.data, 0) - return result + override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + tan(arg.data, 0, result, 0) } - override fun asin(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.asin(arg.data, 0, result.data, 0) - return result + override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + asin(arg.data, 0, result, 0) } - override fun acos(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.acos(arg.data, 0, result.data, 0) - return result + override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + acos(arg.data, 0, result, 0) } - override fun atan(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.atan(arg.data, 0, result.data, 0) - return result + override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + atan(arg.data, 0, result, 0) } - override fun sinh(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.sinh(arg.data, 0, result.data, 0) - return result + override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + sinh(arg.data, 0, result, 0) } - override fun cosh(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.cosh(arg.data, 0, result.data, 0) - return result + override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + cosh(arg.data, 0, result, 0) } - override fun tanh(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.tanh(arg.data, 0, result.data, 0) - return result + override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + tanh(arg.data, 0, result, 0) } - override fun asinh(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.asinh(arg.data, 0, result.data, 0) - return result + override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + asinh(arg.data, 0, result, 0) } - override fun acosh(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.acosh(arg.data, 0, result.data, 0) - return result + override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + acosh(arg.data, 0, result, 0) } - override fun atanh(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.atanh(arg.data, 0, result.data, 0) - return result + override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + atanh(arg.data, 0, result, 0) } override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { - is Int -> { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.pow(arg.data, 0, pow, result.data, 0) - result + is Int -> arg.transformDataBuffer { result -> + pow(arg.data, 0, pow, result, 0) } - else -> { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.pow(arg.data, 0, pow.toDouble(), result.data, 0) - result + else -> arg.transformDataBuffer { result -> + pow(arg.data, 0, pow.toDouble(), result, 0) } } - override fun sqrt(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.sqrt(arg.data, 0, result.data, 0) - return result + override fun sqrt(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + sqrt(arg.data, 0, result, 0) } public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure { arg.compiler.checkCompatibility(pow.compiler) - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.pow(arg.data, 0, pow.data, 0, result.data, 0) - return result + return arg.transformDataBuffer { result -> + pow(arg.data, 0, pow.data, 0, result, 0) + } } - override fun exp(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.exp(arg.data, 0, result.data, 0) - return result + override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + exp(arg.data, 0, result, 0) } - override fun ln(arg: DerivativeStructure): DerivativeStructure { - val result = DerivativeStructure(this, arg.compiler) - arg.compiler.ln(arg.data, 0, result.data, 0) - return result + override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> + ln(arg.data, 0, result, 0) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index 715fad07b..10438dd02 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -188,7 +188,7 @@ public interface LinearSpace> { */ public fun > buffered( algebra: A, - bufferFactory: BufferFactory = Buffer.Companion::boxing, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), ): LinearSpace = BufferedLinearSpace(BufferRingOps(algebra, bufferFactory)) @Deprecated("use DoubleField.linearSpace") diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index 7c612b6a9..60fa81cd8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -27,5 +27,5 @@ public annotation class UnstableKMathAPI RequiresOptIn.Level.WARNING, ) public annotation class PerformancePitfall( - val message: String = "Potential performance problem" + val message: String = "Potential performance problem", ) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index 2401f6319..8175bd65e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -69,7 +69,7 @@ public class MutableBufferND( * Transform structure to a new structure using provided [MutableBufferFactory] and optimizing if argument is [MutableBufferND] */ public inline fun MutableStructureND.mapToMutableBuffer( - factory: MutableBufferFactory = MutableBuffer.Companion::auto, + factory: MutableBufferFactory = MutableBufferFactory(MutableBuffer.Companion::auto), crossinline transform: (T) -> R, ): MutableBufferND { return if (this is MutableBufferND) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index e934c6370..6e54e1b9d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -120,7 +120,7 @@ public interface StructureND : Featured, WithShape { */ public fun buffered( strides: Strides, - bufferFactory: BufferFactory = Buffer.Companion::boxing, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), initializer: (IntArray) -> T, ): BufferND = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) @@ -140,7 +140,7 @@ public interface StructureND : Featured, WithShape { public fun buffered( shape: IntArray, - bufferFactory: BufferFactory = Buffer.Companion::boxing, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), initializer: (IntArray) -> T, ): BufferND = buffered(DefaultStrides(shape), bufferFactory, initializer) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt index 0ee591acc..083892105 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt @@ -6,12 +6,10 @@ package space.kscience.kmath.operations import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer - import kotlin.math.* /** @@ -21,7 +19,7 @@ public abstract class DoubleBufferOps : BufferAlgebra, Exte Norm, Double> { override val elementAlgebra: DoubleField get() = DoubleField - override val bufferFactory: BufferFactory get() = ::DoubleBuffer + override val bufferFactory: BufferFactory get() = BufferFactory(::DoubleBuffer) override fun Buffer.map(block: DoubleField.(Double) -> Double): DoubleBuffer = mapInline { DoubleField.block(it) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 31b0c2841..652472fcf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -61,31 +61,39 @@ public inline fun Buffer.toTypedArray(): Array = Array(size, : /** * Create a new buffer from this one with the given mapping function and using [Buffer.Companion.auto] buffer factory. */ -public inline fun Buffer.map(block: (T) -> R): Buffer = +public inline fun Buffer.map(block: (T) -> R): Buffer = Buffer.auto(size) { block(get(it)) } /** * Create a new buffer from this one with the given mapping function. * Provided [bufferFactory] is used to construct the new buffer. */ -public inline fun Buffer.map( +public inline fun Buffer.map( bufferFactory: BufferFactory, crossinline block: (T) -> R, ): Buffer = bufferFactory(size) { block(get(it)) } /** - * Create a new buffer from this one with the given indexed mapping function. - * Provided [BufferFactory] is used to construct the new buffer. + * Create a new buffer from this one with the given mapping (indexed) function. + * Provided [bufferFactory] is used to construct the new buffer. */ -public inline fun Buffer.mapIndexed( - bufferFactory: BufferFactory = Buffer.Companion::auto, +public inline fun Buffer.mapIndexed( + bufferFactory: BufferFactory, crossinline block: (index: Int, value: T) -> R, ): Buffer = bufferFactory(size) { block(it, get(it)) } +/** + * Create a new buffer from this one with the given indexed mapping function. + * Provided [BufferFactory] is used to construct the new buffer. + */ +public inline fun Buffer.mapIndexed( + crossinline block: (index: Int, value: T) -> R, +): Buffer = BufferFactory(Buffer.Companion::auto).invoke(size) { block(it, get(it)) } + /** * Fold given buffer according to [operation] */ -public inline fun Buffer.fold(initial: R, operation: (acc: R, T) -> R): R { +public inline fun Buffer.fold(initial: R, operation: (acc: R, T) -> R): R { var accumulator = initial for (index in this.indices) accumulator = operation(accumulator, get(index)) return accumulator @@ -95,9 +103,9 @@ public inline fun Buffer.fold(initial: R, operation: (acc: R, T) * Zip two buffers using given [transform]. */ @UnstableKMathAPI -public inline fun Buffer.zip( +public inline fun Buffer.zip( other: Buffer, - bufferFactory: BufferFactory = Buffer.Companion::auto, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::auto), crossinline transform: (T1, T2) -> R, ): Buffer { require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index a1b0307c4..1c79c257a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -14,14 +14,18 @@ import kotlin.reflect.KClass * * @param T the type of buffer. */ -public typealias BufferFactory = (Int, (Int) -> T) -> Buffer +public fun interface BufferFactory { + public operator fun invoke(size: Int, builder: (Int) -> T): Buffer +} /** * Function that produces [MutableBuffer] from its size and function that supplies values. * * @param T the type of buffer. */ -public typealias MutableBufferFactory = (Int, (Int) -> T) -> MutableBuffer +public fun interface MutableBufferFactory: BufferFactory{ + override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer +} /** * A generic read-only random-access structure for both primitives and objects. diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt deleted file mode 100644 index aac327a84..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ /dev/null @@ -1,1003 +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 file. - */ - -/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ - -package space.kscience.kmath.ejml - -import org.ejml.data.* -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.CommonOps_FDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_FDRM -import org.ejml.sparse.FillReducing -import org.ejml.sparse.csc.CommonOps_DSCC -import org.ejml.sparse.csc.CommonOps_FSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC -import space.kscience.kmath.linear.* -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.FloatField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.FloatBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast - -/** - * [EjmlVector] specialization for [Double]. - */ -public class EjmlDoubleVector(override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): Double = origin[0, index] -} - -/** - * [EjmlVector] specialization for [Float]. - */ -public class EjmlFloatVector(override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): Float = origin[0, index] -} - -/** - * [EjmlMatrix] specialization for [Double]. - */ -public class EjmlDoubleMatrix(override val origin: M) : EjmlMatrix(origin) { - override operator fun get(i: Int, j: Int): Double = origin[i, j] -} - -/** - * [EjmlMatrix] specialization for [Float]. - */ -public class EjmlFloatMatrix(override val origin: M) : EjmlMatrix(origin) { - override operator fun get(i: Int, j: Int): Float = origin[i, j] -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and - * [DMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceDDRM : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_DDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix().withFeature(LFeature) - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and - * [FMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceFDRM : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_FDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { FloatBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix().withFeature(LFeature) - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and - * [DMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceDSCC : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as DMatrix).wrapMatrix().withFeature(LFeature) - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = DMatrixRMaj(1, 1) - val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_DDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and - * [FMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceFSCC : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as FMatrix).wrapMatrix().withFeature(LFeature) - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = FMatrixRMaj(1, 1) - val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_FDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let{ - type.cast(it) - } - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt index 90ec29ce3..eafd55513 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt @@ -28,7 +28,7 @@ public class UniformHistogramGroupND>( private val lower: Buffer, private val upper: Buffer, private val binNums: IntArray = IntArray(lower.size) { 20 }, - private val bufferFactory: BufferFactory = Buffer.Companion::boxing, + private val bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), ) : HistogramGroupND { init { @@ -114,7 +114,7 @@ public class UniformHistogramGroupND>( public fun > Histogram.Companion.uniformNDFromRanges( valueAlgebraND: FieldOpsND, vararg ranges: ClosedFloatingPointRange, - bufferFactory: BufferFactory = Buffer.Companion::boxing, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), ): UniformHistogramGroupND = UniformHistogramGroupND( valueAlgebraND, ranges.map(ClosedFloatingPointRange::start).asBuffer(), @@ -140,7 +140,7 @@ public fun Histogram.Companion.uniformDoubleNDFromRanges( public fun > Histogram.Companion.uniformNDFromRanges( valueAlgebraND: FieldOpsND, vararg ranges: Pair, Int>, - bufferFactory: BufferFactory = Buffer.Companion::boxing, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), ): UniformHistogramGroupND = UniformHistogramGroupND( valueAlgebraND, ListBuffer( diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index 1dc318517..0de2d8349 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.multik import org.jetbrains.kotlinx.multik.ndarray.data.DataType +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExponentialOperations @@ -22,10 +23,13 @@ public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra): MultikTensor = sin(arg) / cos(arg) + @PerformancePitfall override fun asin(arg: StructureND): MultikTensor = arg.map { asin(it) } + @PerformancePitfall override fun acos(arg: StructureND): MultikTensor = arg.map { acos(it) } + @PerformancePitfall override fun atan(arg: StructureND): MultikTensor = arg.map { atan(it) } override fun exp(arg: StructureND): MultikTensor = multikMath.mathEx.exp(arg.asMultik().array).wrap() @@ -42,10 +46,13 @@ public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra): MultikTensor = arg.map { asinh(it) } + @PerformancePitfall override fun acosh(arg: StructureND): MultikTensor = arg.map { acosh(it) } + @PerformancePitfall override fun atanh(arg: StructureND): MultikTensor = arg.map { atanh(it) } } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index a88f3e437..890318e31 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -35,7 +35,7 @@ public fun interface Sampler { public fun Sampler.sampleBuffer( generator: RandomGenerator, size: Int, - bufferFactory: BufferFactory = Buffer.Companion::boxing, + bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), ): Chain> { require(size > 1) //creating temporary storage once From f5fe53a9f234edd47ecb2e7d73e7700e12f4a01c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 15 Jul 2022 16:20:28 +0300 Subject: [PATCH 124/174] Grand derivative refactoring. Phase 2 --- .../kscience/kmath/expressions/DSAlgebra.kt | 437 ++++++++++++++++++ .../kmath/expressions/DerivativeStructure.kt | 157 ------- .../DerivativeStructureExpression.kt | 349 -------------- .../DerivativeStructureExpressionTest.kt | 4 +- 4 files changed, 439 insertions(+), 508 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt new file mode 100644 index 000000000..d9fc46b47 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -0,0 +1,437 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.expressions + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.MutableBufferFactory +import space.kscience.kmath.structures.asBuffer +import kotlin.math.max +import kotlin.math.min + +/** + * Class representing both the value and the differentials of a function. + * + * This class is the workhorse of the differentiation package. + * + * This class is an implementation of the extension to Rall's numbers described in Dan Kalman's paper + * [Doubly Recursive Multivariate Automatic Differentiation](http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf), + * Mathematics Magazine, vol. 75, no. 3, June 2002. Rall's numbers are an extension to the real numbers used + * throughout mathematical expressions; they hold the derivative together with the value of a function. Dan Kalman's + * derivative structures hold all partial derivatives up to any specified order, with respect to any number of free + * parameters. Rall's numbers therefore can be seen as derivative structures for order one derivative and one free + * parameter, and real numbers can be seen as derivative structures with zero order derivative and no free parameters. + * + * Derived from + * [Commons Math's `DerivativeStructure`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DerivativeStructure.java). + */ +@UnstableKMathAPI +public interface DS> { + public val derivativeAlgebra: DSAlgebra + public val data: Buffer +} + +/** + * Get a partial derivative. + * + * @param orders derivation orders with respect to each variable (if all orders are 0, the value is returned). + * @return partial derivative. + * @see value + */ +@UnstableKMathAPI +public fun > DS.getPartialDerivative(vararg orders: Int): T = + data[derivativeAlgebra.compiler.getPartialDerivativeIndex(*orders)] + +/** + * The value part of the derivative structure. + * + * @see getPartialDerivative + */ +@UnstableKMathAPI +public val > DS.value: T get() = data[0] + +@UnstableKMathAPI +public abstract class DSAlgebra>( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val order: Int, + bindings: Map, +) : ExpressionAlgebra> { + + @OptIn(UnstableKMathAPI::class) + private fun bufferForVariable(index: Int, value: T): Buffer { + val buffer = bufferFactory(compiler.size) { algebra.zero } + buffer[0] = value + if (compiler.order > 0) { + // the derivative of the variable with respect to itself is 1. + + val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(numberOfVariables).apply { + set(index, 1) + }) + + buffer[indexOfDerivative] = algebra.one + } + return buffer + } + + @UnstableKMathAPI + protected inner class DSImpl internal constructor( + override val data: Buffer, + ) : DS { + override val derivativeAlgebra: DSAlgebra get() = this@DSAlgebra + } + + protected fun DS(data: Buffer): DS = DSImpl(data) + + + /** + * Build an instance representing a variable. + * + * Instances built using this constructor are considered to be the free variables with respect to which + * differentials are computed. As such, their differential with respect to themselves is +1. + */ + public fun variable( + index: Int, + value: T, + ): DS { + require(index < compiler.freeParameters) { "number is too large: $index >= ${compiler.freeParameters}" } + return DS(bufferForVariable(index, value)) + } + + /** + * Build an instance from all its derivatives. + * + * @param derivatives derivatives sorted according to [DSCompiler.getPartialDerivativeIndex]. + */ + public fun ofDerivatives( + vararg derivatives: T, + ): DS { + require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" } + val data = derivatives.asBuffer() + + return DS(data) + } + + /** + * A class implementing both [DS] and [Symbol]. + */ + @UnstableKMathAPI + public inner class DSSymbol internal constructor( + index: Int, + symbol: Symbol, + value: T, + ) : Symbol by symbol, DS { + override val derivativeAlgebra: DSAlgebra get() = this@DSAlgebra + override val data: Buffer = bufferForVariable(index, value) + } + + + public val numberOfVariables: Int = bindings.size + + /** + * Get the compiler for number of free parameters and order. + * + * @return cached rules set. + */ + @PublishedApi + internal val compiler: DSCompiler by lazy { + // get the cached compilers + val cache: Array?>>? = null + + // we need to create more compilers + val maxParameters: Int = max(numberOfVariables, cache?.size ?: 0) + val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) + val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } + + if (cache != null) { + // preserve the already created compilers + for (i in cache.indices) { + cache[i].copyInto(newCache[i], endIndex = cache[i].size) + } + } + + // create the array in increasing diagonal order + for (diag in 0..numberOfVariables + order) { + for (o in max(0, diag - numberOfVariables)..min(order, diag)) { + val p: Int = diag - o + if (newCache[p][o] == null) { + val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! + val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! + + newCache[p][o] = DSCompiler( + algebra, + bufferFactory, + p, + o, + valueCompiler, + derivativeCompiler, + ) + } + } + } + + return@lazy newCache[numberOfVariables][order]!! + } + + private val variables: Map = bindings.entries.mapIndexed { index, (key, value) -> + key to DSSymbol( + index, + key, + value, + ) + }.toMap() + + + public override fun const(value: T): DS { + val buffer = bufferFactory(compiler.size) { algebra.zero } + buffer[0] = value + + return DS(buffer) + } + + override fun bindSymbolOrNull(value: String): DSSymbol? = variables[StringSymbol(value)] + + override fun bindSymbol(value: String): DSSymbol = + bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") + + public fun bindSymbolOrNull(symbol: Symbol): DSSymbol? = variables[symbol.identity] + + public fun bindSymbol(symbol: Symbol): DSSymbol = + bindSymbolOrNull(symbol.identity) ?: error("Symbol '${symbol}' is not supported in $this") + + public fun DS.derivative(symbols: List): T { + require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } + val ordersCount = symbols.groupBy { it }.mapValues { it.value.size } + return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) + } + + public fun DS.derivative(vararg symbols: Symbol): T = derivative(symbols.toList()) + +} + + +/** + * A ring over [DS]. + * + * @property order The derivation order. + * @param bindings The map of bindings values. All bindings are considered free parameters. + */ +@UnstableKMathAPI +public open class DSRing( + algebra: A, + bufferFactory: MutableBufferFactory, + order: Int, + bindings: Map, +) : DSAlgebra(algebra, bufferFactory, order, bindings), + Ring>, ScaleOperations>, + NumericAlgebra>, + NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { + + override fun bindSymbolOrNull(value: String): DSSymbol? = + super.bindSymbolOrNull(value) + + override fun DS.unaryMinus(): DS = mapData { -it } + + /** + * Create a copy of given [Buffer] and modify it according to [block] + */ + protected inline fun DS.transformDataBuffer(block: A.(MutableBuffer) -> Unit): DS { + require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } + val newData = bufferFactory(compiler.size) { data[it] } + algebra.block(newData) + return DS(newData) + } + + protected fun DS.mapData(block: A.(T) -> T): DS { + require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } + val newData: Buffer = data.map(bufferFactory) { + algebra.block(it) + } + return DS(newData) + } + + protected fun DS.mapDataIndexed(block: (Int, T) -> T): DS { + require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } + val newData: Buffer = data.mapIndexed(bufferFactory, block) + return DS(newData) + } + + override val zero: DS by lazy { + const(algebra.zero) + } + + override val one: DS by lazy { + const(algebra.one) + } + + override fun number(value: Number): DS = const(algebra.number(value)) + + override fun add(left: DS, right: DS): DS = left.transformDataBuffer { result -> + require(right.derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } + compiler.add(left.data, 0, right.data, 0, result, 0) + } + + override fun scale(a: DS, value: Double): DS = a.mapData { + it.times(value) + } + + override fun multiply( + left: DS, + right: DS, + ): DS = left.transformDataBuffer { result -> + compiler.multiply(left.data, 0, right.data, 0, result, 0) + } +// +// override fun DS.minus(arg: DS): DS = transformDataBuffer { result -> +// subtract(data, 0, arg.data, 0, result, 0) +// } + + override operator fun DS.plus(other: Number): DS = transformDataBuffer { + it[0] += number(other) + } + +// +// override operator fun DS.minus(other: Number): DS = +// this + (-other.toDouble()) + + override operator fun Number.plus(other: DS): DS = other + this + override operator fun Number.minus(other: DS): DS = other - this +} + +@UnstableKMathAPI +public class DerivativeStructureRingExpression( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val function: DSRing.() -> DS, +) : DifferentiableExpression where A : Ring, A : ScaleOperations, A : NumericAlgebra { + override operator fun invoke(arguments: Map): T = + DSRing(algebra, bufferFactory, 0, arguments).function().value + + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + with( + DSRing( + algebra, + bufferFactory, + symbols.size, + arguments + ) + ) { function().derivative(symbols) } + } +} + +/** + * A field over commons-math [DerivativeStructure]. + * + * @property order The derivation order. + * @param bindings The map of bindings values. All bindings are considered free parameters. + */ +@UnstableKMathAPI +public class DSField>( + algebra: A, + bufferFactory: MutableBufferFactory, + order: Int, + bindings: Map, +) : DSRing(algebra, bufferFactory, order, bindings), ExtendedField> { + override fun number(value: Number): DS = const(algebra.number(value)) + + override fun divide(left: DS, right: DS): DS = left.transformDataBuffer { result -> + compiler.divide(left.data, 0, right.data, 0, result, 0) + } + + override fun sin(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.sin(arg.data, 0, result, 0) + } + + override fun cos(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.cos(arg.data, 0, result, 0) + } + + override fun tan(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.tan(arg.data, 0, result, 0) + } + + override fun asin(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.asin(arg.data, 0, result, 0) + } + + override fun acos(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.acos(arg.data, 0, result, 0) + } + + override fun atan(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.atan(arg.data, 0, result, 0) + } + + override fun sinh(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.sinh(arg.data, 0, result, 0) + } + + override fun cosh(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.cosh(arg.data, 0, result, 0) + } + + override fun tanh(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.tanh(arg.data, 0, result, 0) + } + + override fun asinh(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.asinh(arg.data, 0, result, 0) + } + + override fun acosh(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.acosh(arg.data, 0, result, 0) + } + + override fun atanh(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.atanh(arg.data, 0, result, 0) + } + + override fun power(arg: DS, pow: Number): DS = when (pow) { + is Int -> arg.transformDataBuffer { result -> + compiler.pow(arg.data, 0, pow, result, 0) + } + else -> arg.transformDataBuffer { result -> + compiler.pow(arg.data, 0, pow.toDouble(), result, 0) + } + } + + override fun sqrt(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.sqrt(arg.data, 0, result, 0) + } + + public fun power(arg: DS, pow: DS): DS = arg.transformDataBuffer { result -> + compiler.pow(arg.data, 0, pow.data, 0, result, 0) + } + + override fun exp(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.exp(arg.data, 0, result, 0) + } + + override fun ln(arg: DS): DS = arg.transformDataBuffer { result -> + compiler.ln(arg.data, 0, result, 0) + } +} + +@UnstableKMathAPI +public class DerivativeStructureFieldExpression>( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val function: DSField.() -> DS, +) : DifferentiableExpression { + override operator fun invoke(arguments: Map): T = + DSField(algebra, bufferFactory, 0, arguments).function().value + + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + DSField( + algebra, + bufferFactory, + symbols.size, + arguments, + ).run { function().derivative(symbols) } + } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt deleted file mode 100644 index 01c045cdb..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructure.kt +++ /dev/null @@ -1,157 +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 file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * Class representing both the value and the differentials of a function. - * - * This class is the workhorse of the differentiation package. - * - * This class is an implementation of the extension to Rall's numbers described in Dan Kalman's paper [Doubly Recursive - * Multivariate Automatic Differentiation](http://www1.american.edu/cas/mathstat/People/kalman/pdffiles/mmgautodiff.pdf), - * Mathematics Magazine, vol. 75, no. 3, June 2002. Rall's numbers are an extension to the real numbers used - * throughout mathematical expressions; they hold the derivative together with the value of a function. Dan Kalman's - * derivative structures hold all partial derivatives up to any specified order, with respect to any number of free - * parameters. Rall's numbers therefore can be seen as derivative structures for order one derivative and one free - * parameter, and real numbers can be seen as derivative structures with zero order derivative and no free parameters. - * - * Derived from - * [Commons Math's `DerivativeStructure`](https://github.com/apache/commons-math/blob/924f6c357465b39beb50e3c916d5eb6662194175/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/analysis/differentiation/DerivativeStructure.java). - */ -@UnstableKMathAPI -public open class DerivativeStructure> @PublishedApi internal constructor( - private val derivativeAlgebra: DerivativeStructureAlgebra, - @PublishedApi internal val data: Buffer, -) { - - public val compiler: DSCompiler get() = derivativeAlgebra.compiler - - /** - * The number of free parameters. - */ - public val freeParameters: Int get() = compiler.freeParameters - - /** - * The derivation order. - */ - public val order: Int get() = compiler.order - - /** - * The value part of the derivative structure. - * - * @see getPartialDerivative - */ - public val value: T get() = data[0] - - /** - * Get a partial derivative. - * - * @param orders derivation orders with respect to each variable (if all orders are 0, the value is returned). - * @return partial derivative. - * @see value - */ - public fun getPartialDerivative(vararg orders: Int): T = data[compiler.getPartialDerivativeIndex(*orders)] - - - /** - * Test for the equality of two derivative structures. - * - * Derivative structures are considered equal if they have the same number - * of free parameters, the same derivation order, and the same derivatives. - * - * @return `true` if two derivative structures are equal. - */ - public override fun equals(other: Any?): Boolean { - if (this === other) return true - - if (other is DerivativeStructure<*, *>) { - return ((freeParameters == other.freeParameters) && - (order == other.order) && - data == other.data) - } - - return false - } - - public override fun hashCode(): Int = - 227 + 229 * freeParameters + 233 * order + 239 * data.hashCode() - - public companion object { - - /** - * Build an instance representing a variable. - * - * Instances built using this constructor are considered to be the free variables with respect to which - * differentials are computed. As such, their differential with respect to themselves is +1. - */ - public fun > variable( - derivativeAlgebra: DerivativeStructureAlgebra, - index: Int, - value: T, - ): DerivativeStructure { - val compiler = derivativeAlgebra.compiler - require(index < compiler.freeParameters) { "number is too large: $index >= ${compiler.freeParameters}" } - return DerivativeStructure(derivativeAlgebra, derivativeAlgebra.bufferForVariable(index, value)) - } - - /** - * Build an instance from all its derivatives. - * - * @param derivatives derivatives sorted according to [DSCompiler.getPartialDerivativeIndex]. - */ - public fun > ofDerivatives( - derivativeAlgebra: DerivativeStructureAlgebra, - vararg derivatives: T, - ): DerivativeStructure { - val compiler = derivativeAlgebra.compiler - require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" } - val data = derivatives.asBuffer() - - return DerivativeStructure( - derivativeAlgebra, - data - ) - } - } -} - -@OptIn(UnstableKMathAPI::class) -private fun > DerivativeStructureAlgebra.bufferForVariable(index: Int, value: T): Buffer { - val buffer = bufferFactory(compiler.size) { algebra.zero } - buffer[0] = value - if (compiler.order > 0) { - // the derivative of the variable with respect to itself is 1. - - val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(numberOfVariables).apply { - set(index, 1) - }) - - buffer[indexOfDerivative] = algebra.one - } - return buffer -} - -/** - * A class implementing both [DerivativeStructure] and [Symbol]. - */ -@UnstableKMathAPI -public class DerivativeStructureSymbol> internal constructor( - derivativeAlgebra: DerivativeStructureAlgebra, - index: Int, - symbol: Symbol, - value: T, -) : Symbol by symbol, DerivativeStructure( - derivativeAlgebra, derivativeAlgebra.bufferForVariable(index, value) -) { - override fun toString(): String = symbol.toString() - override fun equals(other: Any?): Boolean = (other as? Symbol) == symbol - override fun hashCode(): Int = symbol.hashCode() -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt deleted file mode 100644 index 638057921..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpression.kt +++ /dev/null @@ -1,349 +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 file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableBufferFactory -import kotlin.math.max -import kotlin.math.min - -@UnstableKMathAPI -public abstract class DerivativeStructureAlgebra>( - public val algebra: A, - public val bufferFactory: MutableBufferFactory, - public val order: Int, - bindings: Map, -) : ExpressionAlgebra> { - - public val numberOfVariables: Int = bindings.size - - - /** - * Get the compiler for number of free parameters and order. - * - * @return cached rules set. - */ - @PublishedApi - internal val compiler: DSCompiler by lazy { - // get the cached compilers - val cache: Array?>>? = null - - // we need to create more compilers - val maxParameters: Int = max(numberOfVariables, cache?.size ?: 0) - val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) - val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } - - if (cache != null) { - // preserve the already created compilers - for (i in cache.indices) { - cache[i].copyInto(newCache[i], endIndex = cache[i].size) - } - } - - // create the array in increasing diagonal order - for (diag in 0..numberOfVariables + order) { - for (o in max(0, diag - numberOfVariables)..min(order, diag)) { - val p: Int = diag - o - if (newCache[p][o] == null) { - val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! - val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! - - newCache[p][o] = DSCompiler( - algebra, - bufferFactory, - p, - o, - valueCompiler, - derivativeCompiler, - ) - } - } - } - - return@lazy newCache[numberOfVariables][order]!! - } - - private val variables: Map> = - bindings.entries.mapIndexed { index, (key, value) -> - key to DerivativeStructureSymbol( - this, - index, - key, - value, - ) - }.toMap() - - - - public override fun const(value: T): DerivativeStructure { - val buffer = bufferFactory(compiler.size) { algebra.zero } - buffer[0] = value - - return DerivativeStructure( - this, - buffer - ) - } - - override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[StringSymbol(value)] - - override fun bindSymbol(value: String): DerivativeStructureSymbol = - bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") - - public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] - - public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = - bindSymbolOrNull(symbol.identity) ?: error("Symbol '${symbol}' is not supported in $this") - - public fun DerivativeStructure.derivative(symbols: List): T { - require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } - val ordersCount = symbols.groupBy { it }.mapValues { it.value.size } - return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) - } - - public fun DerivativeStructure.derivative(vararg symbols: Symbol): T = derivative(symbols.toList()) - -} - - -/** - * A ring over [DerivativeStructure]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters. - */ -@UnstableKMathAPI -public open class DerivativeStructureRing( - algebra: A, - bufferFactory: MutableBufferFactory, - order: Int, - bindings: Map, -) : DerivativeStructureAlgebra(algebra, bufferFactory, order, bindings), - Ring>, ScaleOperations>, - NumericAlgebra>, - NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { - - override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = - super.bindSymbolOrNull(value) - - override fun DerivativeStructure.unaryMinus(): DerivativeStructure { - val newData = algebra { data.map(bufferFactory) { -it } } - return DerivativeStructure(this@DerivativeStructureRing, newData) - } - - /** - * Create a copy of given [Buffer] and modify it according to [block] - */ - protected inline fun DerivativeStructure.transformDataBuffer(block: DSCompiler.(MutableBuffer) -> Unit): DerivativeStructure { - val newData = bufferFactory(compiler.size) { data[it] } - compiler.block(newData) - return DerivativeStructure(this@DerivativeStructureRing, newData) - } - - protected fun DerivativeStructure.mapData(block: (T) -> T): DerivativeStructure { - val newData: Buffer = data.map(bufferFactory, block) - return DerivativeStructure(this@DerivativeStructureRing, newData) - } - - protected fun DerivativeStructure.mapDataIndexed(block: (Int, T) -> T): DerivativeStructure { - val newData: Buffer = data.mapIndexed(bufferFactory, block) - return DerivativeStructure(this@DerivativeStructureRing, newData) - } - - override val zero: DerivativeStructure by lazy { - const(algebra.zero) - } - - override val one: DerivativeStructure by lazy { - const(algebra.one) - } - - override fun number(value: Number): DerivativeStructure = const(algebra.number(value)) - - override fun add(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure { - left.compiler.checkCompatibility(right.compiler) - return left.transformDataBuffer { result -> - add(left.data, 0, right.data, 0, result, 0) - } - } - - override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = algebra { - a.mapData { it.times(value) } - } - - override fun multiply( - left: DerivativeStructure, - right: DerivativeStructure, - ): DerivativeStructure { - left.compiler.checkCompatibility(right.compiler) - return left.transformDataBuffer { result -> - multiply(left.data, 0, right.data, 0, result, 0) - } - } - - override fun DerivativeStructure.minus(arg: DerivativeStructure): DerivativeStructure { - compiler.checkCompatibility(arg.compiler) - return transformDataBuffer { result -> - subtract(data, 0, arg.data, 0, result, 0) - } - } - - override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure = algebra { - transformDataBuffer { - it[0] += number(other) - } - } - - override operator fun DerivativeStructure.minus(other: Number): DerivativeStructure = - this + (-other.toDouble()) - - override operator fun Number.plus(other: DerivativeStructure): DerivativeStructure = other + this - override operator fun Number.minus(other: DerivativeStructure): DerivativeStructure = other - this -} - -@UnstableKMathAPI -public class DerivativeStructureRingExpression( - public val algebra: A, - public val bufferFactory: MutableBufferFactory, - public val function: DerivativeStructureRing.() -> DerivativeStructure, -) : DifferentiableExpression where A : Ring, A : ScaleOperations, A : NumericAlgebra { - override operator fun invoke(arguments: Map): T = - DerivativeStructureRing(algebra, bufferFactory, 0, arguments).function().value - - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - with( - DerivativeStructureRing( - algebra, - bufferFactory, - symbols.size, - arguments - ) - ) { function().derivative(symbols) } - } -} - -/** - * A field over commons-math [DerivativeStructure]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters. - */ -@UnstableKMathAPI -public class DerivativeStructureField>( - algebra: A, - bufferFactory: MutableBufferFactory, - order: Int, - bindings: Map, -) : DerivativeStructureRing(algebra, bufferFactory, order, bindings), ExtendedField> { - override fun number(value: Number): DerivativeStructure = const(algebra.number(value)) - - override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure { - left.compiler.checkCompatibility(right.compiler) - return left.transformDataBuffer { result -> - left.compiler.divide(left.data, 0, right.data, 0, result, 0) - } - } - - override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - sin(arg.data, 0, result, 0) - } - - override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - cos(arg.data, 0, result, 0) - } - - override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - tan(arg.data, 0, result, 0) - } - - override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - asin(arg.data, 0, result, 0) - } - - override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - acos(arg.data, 0, result, 0) - } - - override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - atan(arg.data, 0, result, 0) - } - - override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - sinh(arg.data, 0, result, 0) - } - - override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - cosh(arg.data, 0, result, 0) - } - - override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - tanh(arg.data, 0, result, 0) - } - - override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - asinh(arg.data, 0, result, 0) - } - - override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - acosh(arg.data, 0, result, 0) - } - - override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - atanh(arg.data, 0, result, 0) - } - - override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { - is Int -> arg.transformDataBuffer { result -> - pow(arg.data, 0, pow, result, 0) - } - else -> arg.transformDataBuffer { result -> - pow(arg.data, 0, pow.toDouble(), result, 0) - } - } - - override fun sqrt(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - sqrt(arg.data, 0, result, 0) - } - - public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure { - arg.compiler.checkCompatibility(pow.compiler) - return arg.transformDataBuffer { result -> - pow(arg.data, 0, pow.data, 0, result, 0) - } - } - - override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - exp(arg.data, 0, result, 0) - } - - override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.transformDataBuffer { result -> - ln(arg.data, 0, result, 0) - } -} - -@UnstableKMathAPI -public class DerivativeStructureFieldExpression>( - public val algebra: A, - public val bufferFactory: MutableBufferFactory, - public val function: DerivativeStructureField.() -> DerivativeStructure, -) : DifferentiableExpression { - override operator fun invoke(arguments: Map): T = - DerivativeStructureField(algebra, bufferFactory, 0, arguments).function().value - - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - with( - DerivativeStructureField( - algebra, - bufferFactory, - symbols.size, - arguments, - ) - ) { function().derivative(symbols) } - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt index 429fe310b..fdeda4512 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt @@ -19,10 +19,10 @@ import kotlin.test.assertFails internal inline fun diff( order: Int, vararg parameters: Pair, - block: DerivativeStructureField.() -> Unit, + block: DSField.() -> Unit, ) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - DerivativeStructureField(DoubleField, ::DoubleBuffer, order, mapOf(*parameters)).block() + DSField(DoubleField, ::DoubleBuffer, order, mapOf(*parameters)).block() } internal class AutoDiffTest { From 846a6d2620810dc9e15538befba437f0882a77db Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 15 Jul 2022 17:20:00 +0300 Subject: [PATCH 125/174] Grand derivative refactoring. Phase 3 --- .../kscience/kmath/expressions/DSAlgebra.kt | 143 ++++++++++-------- .../kscience/kmath/expressions/DSCompiler.kt | 28 ++-- 2 files changed, 96 insertions(+), 75 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index d9fc46b47..506fbd001 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -44,9 +44,29 @@ public interface DS> { * @see value */ @UnstableKMathAPI -public fun > DS.getPartialDerivative(vararg orders: Int): T = +private fun > DS.getPartialDerivative(vararg orders: Int): T = data[derivativeAlgebra.compiler.getPartialDerivativeIndex(*orders)] +/** + * Provide a partial derivative with given symbols. On symbol could me mentioned multiple times + */ +@UnstableKMathAPI +public fun > DS.derivative(symbols: List): T { + require(symbols.size <= derivativeAlgebra.order) { "The order of derivative ${symbols.size} exceeds computed order ${derivativeAlgebra.order}" } + val ordersCount: Map = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } + return getPartialDerivative(*symbols.map { ordersCount[it] ?: 0 }.toIntArray()) +} + +/** + * Provide a partial derivative with given symbols. On symbol could me mentioned multiple times + */ +@UnstableKMathAPI +public fun > DS.derivative(vararg symbols: Symbol): T { + require(symbols.size <= derivativeAlgebra.order) { "The order of derivative ${symbols.size} exceeds computed order ${derivativeAlgebra.order}" } + val ordersCount: Map = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } + return getPartialDerivative(*symbols.map { ordersCount[it] ?: 0 }.toIntArray()) +} + /** * The value part of the derivative structure. * @@ -61,9 +81,67 @@ public abstract class DSAlgebra>( public val bufferFactory: MutableBufferFactory, public val order: Int, bindings: Map, -) : ExpressionAlgebra> { +) : ExpressionAlgebra>, SymbolIndexer { + + /** + * Get the compiler for number of free parameters and order. + * + * @return cached rules set. + */ + @PublishedApi + internal val compiler: DSCompiler by lazy { + // get the cached compilers + val cache: Array?>>? = null + + // we need to create more compilers + val maxParameters: Int = max(numberOfVariables, cache?.size ?: 0) + val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) + val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } + + if (cache != null) { + // preserve the already created compilers + for (i in cache.indices) { + cache[i].copyInto(newCache[i], endIndex = cache[i].size) + } + } + + // create the array in increasing diagonal order + for (diag in 0..numberOfVariables + order) { + for (o in max(0, diag - numberOfVariables)..min(order, diag)) { + val p: Int = diag - o + if (newCache[p][o] == null) { + val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! + val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! + + newCache[p][o] = DSCompiler( + algebra, + bufferFactory, + p, + o, + valueCompiler, + derivativeCompiler, + ) + } + } + } + + return@lazy newCache[numberOfVariables][order]!! + } + + private val variables: Map by lazy { + bindings.entries.mapIndexed { index, (key, value) -> + key to DSSymbol( + index, + key, + value, + ) + }.toMap() + } + override val symbols: List = bindings.map { it.key } + + public val numberOfVariables: Int get() = symbols.size + - @OptIn(UnstableKMathAPI::class) private fun bufferForVariable(index: Int, value: T): Buffer { val buffer = bufferFactory(compiler.size) { algebra.zero } buffer[0] = value @@ -80,7 +158,7 @@ public abstract class DSAlgebra>( } @UnstableKMathAPI - protected inner class DSImpl internal constructor( + private inner class DSImpl( override val data: Buffer, ) : DS { override val derivativeAlgebra: DSAlgebra get() = this@DSAlgebra @@ -130,63 +208,6 @@ public abstract class DSAlgebra>( override val data: Buffer = bufferForVariable(index, value) } - - public val numberOfVariables: Int = bindings.size - - /** - * Get the compiler for number of free parameters and order. - * - * @return cached rules set. - */ - @PublishedApi - internal val compiler: DSCompiler by lazy { - // get the cached compilers - val cache: Array?>>? = null - - // we need to create more compilers - val maxParameters: Int = max(numberOfVariables, cache?.size ?: 0) - val maxOrder: Int = max(order, if (cache == null) 0 else cache[0].size) - val newCache: Array?>> = Array(maxParameters + 1) { arrayOfNulls(maxOrder + 1) } - - if (cache != null) { - // preserve the already created compilers - for (i in cache.indices) { - cache[i].copyInto(newCache[i], endIndex = cache[i].size) - } - } - - // create the array in increasing diagonal order - for (diag in 0..numberOfVariables + order) { - for (o in max(0, diag - numberOfVariables)..min(order, diag)) { - val p: Int = diag - o - if (newCache[p][o] == null) { - val valueCompiler: DSCompiler? = if (p == 0) null else newCache[p - 1][o]!! - val derivativeCompiler: DSCompiler? = if (o == 0) null else newCache[p][o - 1]!! - - newCache[p][o] = DSCompiler( - algebra, - bufferFactory, - p, - o, - valueCompiler, - derivativeCompiler, - ) - } - } - } - - return@lazy newCache[numberOfVariables][order]!! - } - - private val variables: Map = bindings.entries.mapIndexed { index, (key, value) -> - key to DSSymbol( - index, - key, - value, - ) - }.toMap() - - public override fun const(value: T): DS { val buffer = bufferFactory(compiler.size) { algebra.zero } buffer[0] = value diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt index e0050cf03..b5b2988a3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt @@ -52,20 +52,20 @@ internal fun MutableBuffer.fill(element: T, fromIndex: Int = 0, toIndex: * * @property freeParameters Number of free parameters. * @property order Derivation order. - * @see DerivativeStructure + * @see DS */ -class DSCompiler> internal constructor( - val algebra: A, - val bufferFactory: MutableBufferFactory, - val freeParameters: Int, - val order: Int, +public class DSCompiler> internal constructor( + public val algebra: A, + public val bufferFactory: MutableBufferFactory, + public val freeParameters: Int, + public val order: Int, valueCompiler: DSCompiler?, derivativeCompiler: DSCompiler?, ) { /** * Number of partial derivatives (including the single 0 order derivative element). */ - val sizes: Array by lazy { + public val sizes: Array by lazy { compileSizes( freeParameters, order, @@ -76,7 +76,7 @@ class DSCompiler> internal constructor( /** * Indirection array for partial derivatives. */ - val derivativesIndirection: Array by lazy { + internal val derivativesIndirection: Array by lazy { compileDerivativesIndirection( freeParameters, order, valueCompiler, derivativeCompiler, @@ -86,7 +86,7 @@ class DSCompiler> internal constructor( /** * Indirection array of the lower derivative elements. */ - val lowerIndirection: IntArray by lazy { + internal val lowerIndirection: IntArray by lazy { compileLowerIndirection( freeParameters, order, valueCompiler, derivativeCompiler, @@ -96,7 +96,7 @@ class DSCompiler> internal constructor( /** * Indirection arrays for multiplication. */ - val multIndirection: Array> by lazy { + internal val multIndirection: Array> by lazy { compileMultiplicationIndirection( freeParameters, order, valueCompiler, derivativeCompiler, lowerIndirection, @@ -106,7 +106,7 @@ class DSCompiler> internal constructor( /** * Indirection arrays for function composition. */ - val compositionIndirection: Array> by lazy { + internal val compositionIndirection: Array> by lazy { compileCompositionIndirection( freeParameters, order, valueCompiler, derivativeCompiler, @@ -120,7 +120,7 @@ class DSCompiler> internal constructor( * This number includes the single 0 order derivative element, which is * guaranteed to be stored in the first element of the array. */ - val size: Int get() = sizes[freeParameters][order] + public val size: Int get() = sizes[freeParameters][order] /** * Get the index of a partial derivative in the array. @@ -147,7 +147,7 @@ class DSCompiler> internal constructor( * @return index of the partial derivative. * @see getPartialDerivativeOrders */ - fun getPartialDerivativeIndex(vararg orders: Int): Int { + public fun getPartialDerivativeIndex(vararg orders: Int): Int { // safety check require(orders.size == freeParameters) { "dimension mismatch: ${orders.size} and $freeParameters" } return getPartialDerivativeIndex(freeParameters, order, sizes, *orders) @@ -162,7 +162,7 @@ class DSCompiler> internal constructor( * @return orders derivation orders with respect to each parameter * @see getPartialDerivativeIndex */ - fun getPartialDerivativeOrders(index: Int): IntArray = derivativesIndirection[index] + public fun getPartialDerivativeOrders(index: Int): IntArray = derivativesIndirection[index] } /** From bfadf5b33d545ac0e4d40f2253e20e0ad88e4ba0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 15 Jul 2022 17:31:28 +0300 Subject: [PATCH 126/174] Name refactor --- .../kotlin/space/kscience/kmath/expressions/DSAlgebra.kt | 2 +- .../kmath/expressions/DerivativeStructureExpressionTest.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index 506fbd001..59e6f4f6f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -439,7 +439,7 @@ public class DSField>( } @UnstableKMathAPI -public class DerivativeStructureFieldExpression>( +public class DSFieldExpression>( public val algebra: A, public val bufferFactory: MutableBufferFactory, public val function: DSField.() -> DS, diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt index fdeda4512..e5bc9805a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt @@ -30,7 +30,7 @@ internal class AutoDiffTest { private val y by symbol @Test - fun derivativeStructureFieldTest() { + fun dsAlgebraTest() { diff(2, x to 1.0, y to 1.0) { val x = bindSymbol(x)//by binding() val y = bindSymbol("y") @@ -44,8 +44,8 @@ internal class AutoDiffTest { } @Test - fun autoDifTest() { - val f = DerivativeStructureFieldExpression(DoubleField, ::DoubleBuffer) { + fun dsExpressionTest() { + val f = DSFieldExpression(DoubleField, ::DoubleBuffer) { val x by binding val y by binding x.pow(2) + 2 * x * y + y.pow(2) + 1 From 18ae964e57a2d1059aaa4f17909da45c3a4a1972 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 15 Jul 2022 17:35:13 +0300 Subject: [PATCH 127/174] Name refactor --- .../space/kscience/kmath/ejml/_generated.kt | 1003 +++++++++++++++++ 1 file changed, 1003 insertions(+) create mode 100644 kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt new file mode 100644 index 000000000..aac327a84 --- /dev/null +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -0,0 +1,1003 @@ +/* + * 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 file. + */ + +/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ + +package space.kscience.kmath.ejml + +import org.ejml.data.* +import org.ejml.dense.row.CommonOps_DDRM +import org.ejml.dense.row.CommonOps_FDRM +import org.ejml.dense.row.factory.DecompositionFactory_DDRM +import org.ejml.dense.row.factory.DecompositionFactory_FDRM +import org.ejml.sparse.FillReducing +import org.ejml.sparse.csc.CommonOps_DSCC +import org.ejml.sparse.csc.CommonOps_FSCC +import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC +import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC +import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC +import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC +import space.kscience.kmath.linear.* +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.StructureFeature +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.FloatField +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.FloatBuffer +import kotlin.reflect.KClass +import kotlin.reflect.cast + +/** + * [EjmlVector] specialization for [Double]. + */ +public class EjmlDoubleVector(override val origin: M) : EjmlVector(origin) { + init { + require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } + } + + override operator fun get(index: Int): Double = origin[0, index] +} + +/** + * [EjmlVector] specialization for [Float]. + */ +public class EjmlFloatVector(override val origin: M) : EjmlVector(origin) { + init { + require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } + } + + override operator fun get(index: Int): Float = origin[0, index] +} + +/** + * [EjmlMatrix] specialization for [Double]. + */ +public class EjmlDoubleMatrix(override val origin: M) : EjmlMatrix(origin) { + override operator fun get(i: Int, j: Int): Double = origin[i, j] +} + +/** + * [EjmlMatrix] specialization for [Float]. + */ +public class EjmlFloatMatrix(override val origin: M) : EjmlMatrix(origin) { + override operator fun get(i: Int, j: Int): Float = origin[i, j] +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and + * [DMatrixRMaj] matrices. + */ +public object EjmlLinearSpaceDDRM : EjmlLinearSpace() { + /** + * The [DoubleField] reference. + */ + override val elementAlgebra: DoubleField get() = DoubleField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlDoubleMatrix = when { + this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlDoubleVector = when { + this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector + else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: DoubleField.(i: Int, j: Int) -> Double, + ): EjmlDoubleMatrix = DMatrixRMaj(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: DoubleField.(Int) -> Double, + ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlDoubleMatrix(this) + private fun T.wrapVector() = EjmlDoubleVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixRMaj(1, 1) + CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlDoubleVector { + val out = DMatrixRMaj(1, 1) + CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlDoubleVector { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlDoubleVector { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlDoubleVector { + val out = DMatrixRMaj(1, 1) + + CommonOps_DDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this + + override fun Point.times(value: Double): EjmlDoubleVector { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Double.times(v: Point): EjmlDoubleVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + InverseMatrixFeature::class -> object : InverseMatrixFeature { + override val inverse: Matrix by lazy { + val res = origin.copy() + CommonOps_DDRM.invert(res) + res.wrapMatrix() + } + } + + DeterminantFeature::class -> object : DeterminantFeature { + override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } + } + + SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { + private val svd by lazy { + DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false) + .apply { decompose(origin.copy()) } + } + + override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } + override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } + override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } + override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } + } + + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } + + cholesky.getT(null).wrapMatrix().withFeature(LFeature) + } + } + + LupDecompositionFeature::class -> object : LupDecompositionFeature { + private val lup by lazy { + DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lup.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lup.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } + } + + else -> null + }?.let{ + type.cast(it) + } + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlDoubleVector { + val res = DMatrixRMaj(1, 1) + CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) + return EjmlDoubleVector(res) + } +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and + * [FMatrixRMaj] matrices. + */ +public object EjmlLinearSpaceFDRM : EjmlLinearSpace() { + /** + * The [FloatField] reference. + */ + override val elementAlgebra: FloatField get() = FloatField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlFloatMatrix = when { + this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlFloatVector = when { + this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector + else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: FloatField.(i: Int, j: Int) -> Float, + ): EjmlFloatMatrix = FMatrixRMaj(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: FloatField.(Int) -> Float, + ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlFloatMatrix(this) + private fun T.wrapVector() = EjmlFloatVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { + val out = FMatrixRMaj(1, 1) + CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlFloatVector { + val out = FMatrixRMaj(1, 1) + CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Float): EjmlFloatMatrix { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlFloatVector { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlFloatVector { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlFloatVector { + val out = FMatrixRMaj(1, 1) + + CommonOps_FDRM.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + ) + + return out.wrapVector() + } + + override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this + + override fun Point.times(value: Float): EjmlFloatVector { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Float.times(v: Point): EjmlFloatVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + InverseMatrixFeature::class -> object : InverseMatrixFeature { + override val inverse: Matrix by lazy { + val res = origin.copy() + CommonOps_FDRM.invert(res) + res.wrapMatrix() + } + } + + DeterminantFeature::class -> object : DeterminantFeature { + override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } + } + + SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { + private val svd by lazy { + DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false) + .apply { decompose(origin.copy()) } + } + + override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } + override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } + override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } + override val singularValues: Point by lazy { FloatBuffer(svd.singularValues) } + } + + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } + + cholesky.getT(null).wrapMatrix().withFeature(LFeature) + } + } + + LupDecompositionFeature::class -> object : LupDecompositionFeature { + private val lup by lazy { + DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lup.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lup.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } + } + + else -> null + }?.let{ + type.cast(it) + } + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlFloatVector { + val res = FMatrixRMaj(1, 1) + CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) + return EjmlFloatVector(res) + } +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and + * [DMatrixSparseCSC] matrices. + */ +public object EjmlLinearSpaceDSCC : EjmlLinearSpace() { + /** + * The [DoubleField] reference. + */ + override val elementAlgebra: DoubleField get() = DoubleField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlDoubleMatrix = when { + this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlDoubleVector = when { + this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector + else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: DoubleField.(i: Int, j: Int) -> Double, + ): EjmlDoubleMatrix = DMatrixSparseCSC(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: DoubleField.(Int) -> Double, + ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlDoubleMatrix(this) + private fun T.wrapVector() = EjmlDoubleVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlDoubleVector { + val out = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlDoubleVector { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlDoubleVector { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlDoubleVector { + val out = DMatrixSparseCSC(1, 1) + + CommonOps_DSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this + + override fun Point.times(value: Double): EjmlDoubleVector { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Double.times(v: Point): EjmlDoubleVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } + + (cholesky.getT(null) as DMatrix).wrapMatrix().withFeature(LFeature) + } + } + + LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : + LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { + private val lu by lazy { + DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lu.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lu.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val inverse: Matrix by lazy { + var a = origin + val inverse = DMatrixRMaj(1, 1) + val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE) + if (solver.modifiesA()) a = a.copy() + val i = CommonOps_DDRM.identity(a.numRows) + solver.solve(i, inverse) + inverse.wrapMatrix() + } + + override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) } + } + + else -> null + }?.let{ + type.cast(it) + } + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlDoubleVector { + val res = DMatrixSparseCSC(1, 1) + CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) + return EjmlDoubleVector(res) + } +} + +/** + * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and + * [FMatrixSparseCSC] matrices. + */ +public object EjmlLinearSpaceFSCC : EjmlLinearSpace() { + /** + * The [FloatField] reference. + */ + override val elementAlgebra: FloatField get() = FloatField + + @Suppress("UNCHECKED_CAST") + override fun Matrix.toEjml(): EjmlFloatMatrix = when { + this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix + else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } + } + + @Suppress("UNCHECKED_CAST") + override fun Point.toEjml(): EjmlFloatVector = when { + this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector + else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } + }) + } + + override fun buildMatrix( + rows: Int, + columns: Int, + initializer: FloatField.(i: Int, j: Int) -> Float, + ): EjmlFloatMatrix = FMatrixSparseCSC(rows, columns).also { + (0 until rows).forEach { row -> + (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } + } + }.wrapMatrix() + + override fun buildVector( + size: Int, + initializer: FloatField.(Int) -> Float, + ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { + (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } + }) + + private fun T.wrapMatrix() = EjmlFloatMatrix(this) + private fun T.wrapVector() = EjmlFloatVector(this) + + override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } + + override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { + val out = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) + return out.wrapMatrix() + } + + override fun Matrix.dot(vector: Point): EjmlFloatVector { + val out = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) + return out.wrapVector() + } + + override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override operator fun Matrix.times(value: Float): EjmlFloatMatrix { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.scale(value, toEjml().origin, res) + return res.wrapMatrix() + } + + override fun Point.unaryMinus(): EjmlFloatVector { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.changeSign(toEjml().origin, res) + return res.wrapVector() + } + + override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapMatrix() + } + + override fun Point.plus(other: Point): EjmlFloatVector { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra.one, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Point.minus(other: Point): EjmlFloatVector { + val out = FMatrixSparseCSC(1, 1) + + CommonOps_FSCC.add( + elementAlgebra.one, + toEjml().origin, + elementAlgebra { -one }, + other.toEjml().origin, + out, + null, + null, + ) + + return out.wrapVector() + } + + override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this + + override fun Point.times(value: Float): EjmlFloatVector { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.scale(value, toEjml().origin, res) + return res.wrapVector() + } + + override fun Float.times(v: Point): EjmlFloatVector = v * this + + @UnstableKMathAPI + override fun computeFeature(structure: Matrix, type: KClass): F? { + structure.getFeature(type)?.let { return it } + val origin = structure.toEjml().origin + + return when (type) { + QRDecompositionFeature::class -> object : QRDecompositionFeature { + private val qr by lazy { + DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val q: Matrix by lazy { + qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + } + + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + } + + CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { + override val l: Matrix by lazy { + val cholesky = + DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } + + (cholesky.getT(null) as FMatrix).wrapMatrix().withFeature(LFeature) + } + } + + LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : + LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { + private val lu by lazy { + DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } + } + + override val l: Matrix by lazy { + lu.getLower(null).wrapMatrix().withFeature(LFeature) + } + + override val u: Matrix by lazy { + lu.getUpper(null).wrapMatrix().withFeature(UFeature) + } + + override val inverse: Matrix by lazy { + var a = origin + val inverse = FMatrixRMaj(1, 1) + val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE) + if (solver.modifiesA()) a = a.copy() + val i = CommonOps_FDRM.identity(a.numRows) + solver.solve(i, inverse) + inverse.wrapMatrix() + } + + override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) } + } + + else -> null + }?.let{ + type.cast(it) + } + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p matrix. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) + return res.wrapMatrix() + } + + /** + * Solves for *x* in the following equation: *x = [a] -1 · [b]*. + * + * @param a the base matrix. + * @param b n by p vector. + * @return the solution for *x* that is n by p. + */ + public fun solve(a: Matrix, b: Point): EjmlFloatVector { + val res = FMatrixSparseCSC(1, 1) + CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) + return EjmlFloatVector(res) + } +} + From 32769d690683d8b1975f1d3380c2f6f3ffe49972 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Fri, 15 Jul 2022 18:13:50 +0200 Subject: [PATCH 128/174] Dubins path --- kmath-trajectory/README.md | 32 ++++ kmath-trajectory/build.gradle.kts | 15 ++ .../kmath/trajectory/dubins/DubinsPath.kt | 30 +++ .../trajectory/dubins/DubinsPathFactory.kt | 171 ++++++++++++++++++ .../kscience/kmath/trajectory/segments/Arc.kt | 43 +++++ .../kmath/trajectory/segments/Line.kt | 23 +++ .../kmath/trajectory/segments/Segment.kt | 5 + .../trajectory/segments/components/Circle.kt | 11 ++ .../trajectory/segments/components/Pose2D.kt | 18 ++ .../space/kscience/kmath/trajectory/Math.kt | 27 +++ .../kmath/trajectory/dubins/DubinsTests.kt | 68 +++++++ .../kmath/trajectory/segments/ArcTests.kt | 24 +++ .../kmath/trajectory/segments/LineTests.kt | 33 ++++ settings.gradle.kts | 3 +- 14 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 kmath-trajectory/README.md create mode 100644 kmath-trajectory/build.gradle.kts create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt diff --git a/kmath-trajectory/README.md b/kmath-trajectory/README.md new file mode 100644 index 000000000..cb2b6989f --- /dev/null +++ b/kmath-trajectory/README.md @@ -0,0 +1,32 @@ +# Module kmath-trajectory + + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-trajectory:0.3.0`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-trajectory:0.3.0' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-trajectory:0.3.0") +} +``` diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts new file mode 100644 index 000000000..502867ee3 --- /dev/null +++ b/kmath-trajectory/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") +} + +kotlin.sourceSets.commonMain { + dependencies { + api(projects.kmath.kmathGeometry) + } +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt new file mode 100644 index 000000000..005d7fd60 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt @@ -0,0 +1,30 @@ +/* + * 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.trajectory.dubins + +import space.kscience.kmath.trajectory.segments.Arc +import space.kscience.kmath.trajectory.segments.Segment + +public class DubinsPath( + public val a: Arc, + public val b: Segment, + public val c: Arc, +) { + + public val type: TYPE = TYPE.valueOf( + arrayOf( + a.direction.name[0], + if (b is Arc) b.direction.name[0] else 'S', + c.direction.name[0] + ).toCharArray().concatToString() + ) + + public val length: Double = a.length + b.length + c.length + + public enum class TYPE { + RLR, LRL, RSR, LSL, RSL, LSR + } +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt new file mode 100644 index 000000000..98ed8ed32 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt @@ -0,0 +1,171 @@ +/* + * 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.trajectory.dubins + +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Line2D +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.segments.Arc +import space.kscience.kmath.trajectory.segments.LineSegment +import space.kscience.kmath.trajectory.segments.components.Circle +import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.length +import space.kscience.kmath.trajectory.segments.theta +import kotlin.math.acos +import kotlin.math.cos +import kotlin.math.sin + +public class DubinsPathFactory( + private val base: Pose2D, + private val direction: Pose2D, + private val turningRadius: Double +) { + + public val all: List get() = listOfNotNull(rlr, lrl, rsr, lsl, rsl, lsr) + public val shortest: DubinsPath get() = all.minByOrNull { it.length }!! + public operator fun get(type: DubinsPath.TYPE): DubinsPath? = all.find { it.type == type } + + public val rlr: DubinsPath? get () { + val c1 = base.getRightCircle(turningRadius) + val c2 = direction.getRightCircle(turningRadius) + val centers = Line2D(c1.center, c2.center) + return if (centers.length < turningRadius * 4) { + var theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.RIGHT) + val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.LEFT) + val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.RIGHT) + DubinsPath(a1, a2, a3) + } else { + null + } + } + + private val lrl: DubinsPath? get () { + val c1 = base.getLeftCircle(turningRadius) + val c2 = direction.getLeftCircle(turningRadius) + val centers = Line2D(c1.center, c2.center) + return if (centers.length < turningRadius * 4) { + var theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.LEFT) + val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.LEFT) + DubinsPath(a1, a2, a3) + } else { + null + } + } + + public val rsr: DubinsPath? get () { + val c1 = base.getRightCircle(turningRadius) + val c2 = direction.getRightCircle(turningRadius) + val l = leftOuterTangent(c1, c2) + val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.RIGHT) + return DubinsPath(a1, LineSegment(l), a3) + } + + public val lsl: DubinsPath + get () { + val c1 = base.getLeftCircle(turningRadius) + val c2 = direction.getLeftCircle(turningRadius) + val l = rightOuterTangent(c1, c2) + val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.LEFT) + return DubinsPath(a1, LineSegment(l), a3) + } + + public val rsl: DubinsPath? get () { + val c1 = base.getRightCircle(turningRadius) + val c2 = direction.getLeftCircle(turningRadius) + val l = rightInnerTangent(c1, c2) + return if (c1.center.distanceTo(c2.center) > turningRadius * 2 && l != null) { + val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.LEFT) + DubinsPath(a1, LineSegment(l), a3) + } else { + null + } + } + + public val lsr: DubinsPath? get () { + val c1 = base.getLeftCircle(turningRadius) + val c2 = direction.getRightCircle(turningRadius) + val l = leftInnerTangent(c1, c2) + return if (c1.center.distanceTo(c2.center) > turningRadius * 2 && l != null) { + val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.RIGHT) + DubinsPath(a1, LineSegment(l), a3) + } else { + null + } + } +} + +private enum class SIDE { + LEFT, RIGHT +} + +private fun Pose2D.getLeftCircle(radius: Double): Circle = getTangentCircles(radius).first +private fun Pose2D.getRightCircle(radius: Double): Circle = getTangentCircles(radius).second +private fun Pose2D.getTangentCircles(radius: Double): Pair { + val dX = radius * cos(theta) + val dY = radius * sin(theta) + return Circle(Vector2D(x - dX, y + dY), radius) to Circle(Vector2D(x + dX, y - dY), radius) +} + +private fun leftOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.LEFT) +private fun rightOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.RIGHT) +private fun outerTangent(a: Circle, b: Circle, side: SIDE): Line2D { + val centers = Line2D(a.center, b.center) + val p1 = when (side) { + SIDE.LEFT -> Vector2D( + a.center.x - a.radius * cos(centers.theta), + a.center.y + a.radius * sin(centers.theta) + ) + SIDE.RIGHT -> Vector2D( + a.center.x + a.radius * cos(centers.theta), + a.center.y - a.radius * sin(centers.theta) + ) + } + return Line2D(p1, Vector2D(p1.x + (centers.direction.x - centers.base.x), p1.y + (centers.direction.y - centers.base.y))) +} + +private fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) +private fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.RIGHT) +private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Line2D? { + val centers = Line2D(base.center, direction.center) + return if (centers.length > base.radius * 2) { + val angle = when (side) { + SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) + SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) + }.theta + val dX = base.radius * sin(angle) + val dY = base.radius * cos(angle) + val p1 = Vector2D(base.center.x + dX, base.center.y + dY) + val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) + Line2D(p1, p2) + } else { + null + } +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt new file mode 100644 index 000000000..a7b2fe259 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt @@ -0,0 +1,43 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Line2D +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.segments.components.Circle +import space.kscience.kmath.trajectory.segments.components.Pose2D +import kotlin.math.PI + +public class Arc( + center: Vector2D, + radius: Double, + a: Vector2D, + b: Vector2D, + internal val direction: Direction +) : Circle(center, radius), Segment { + + private val l1 = Line2D(center, a) + private val l2 = Line2D(center, b) + + internal val pose1 = calculatePose(a, l1.theta) + internal val pose2 = calculatePose(b, l2.theta) + private val angle = calculateAngle() + override val length: Double = calculateLength() + + public enum class Direction { + LEFT, RIGHT + } + + private fun calculateAngle() = + (if (direction == Direction.LEFT) l1.theta - l2.theta else l2.theta - l1.theta).theta + + private fun calculateLength(): Double { + val proportion = angle / (2 * PI) + return circumference * proportion + } + + private fun calculatePose(vector: Vector2D, theta: Double): Pose2D = + if (direction == Direction.LEFT) { + Pose2D(vector.x, vector.y, (theta - PI / 2).theta) + } else { + Pose2D(vector.x, vector.y, (theta + PI / 2).theta) + } +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt new file mode 100644 index 000000000..f63372016 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt @@ -0,0 +1,23 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Line2D +import space.kscience.kmath.operations.DoubleField.pow +import kotlin.math.PI +import kotlin.math.atan2 +import kotlin.math.sqrt + +public class LineSegment( + internal val line: Line2D +) : Segment { + override val length: Double + get() = line.length +} + +internal val Line2D.theta: Double + get() = atan2(direction.x - base.x, direction.y - base.y).theta + +internal val Line2D.length: Double + get() = sqrt((direction.x - base.x).pow(2) + (direction.y - base.y).pow(2)) + +internal val Double.theta: Double + get() = (this + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt new file mode 100644 index 000000000..8a1d086fc --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt @@ -0,0 +1,5 @@ +package space.kscience.kmath.trajectory.segments + +public interface Segment { + public val length: Double +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt new file mode 100644 index 000000000..946dd8c6e --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt @@ -0,0 +1,11 @@ +package space.kscience.kmath.trajectory.segments.components + +import space.kscience.kmath.geometry.Vector2D +import kotlin.math.PI + +public open class Circle( + internal val center: Vector2D, + internal val radius: Double +) { + internal val circumference = radius * 2 * PI +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt new file mode 100644 index 000000000..6bcc3d308 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt @@ -0,0 +1,18 @@ +package space.kscience.kmath.trajectory.segments.components + +import space.kscience.kmath.geometry.Vector2D +import kotlin.math.cos +import kotlin.math.sin + +public class Pose2D( + override val x: Double, + override val y: Double, + public val theta: Double +) : Vector2D { + + internal constructor(vector: Vector2D, theta: Double) : this(vector.x, vector.y, theta) + + override fun toString(): String { + return "Pose2D(x=$x, y=$y, theta=$theta)" + } +} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt new file mode 100644 index 000000000..9258e6b4a --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -0,0 +1,27 @@ +package space.kscience.kmath.trajectory + +import space.kscience.kmath.geometry.Line2D +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.theta +import kotlin.math.PI +import kotlin.math.abs +import kotlin.math.sin + +private const val maxFloatDelta = 0.000001 + +fun Double.radiansToDegrees() = this * 180 / PI + +fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta +fun Pose2D.equalsFloat(other: Pose2D) = x.equalFloat(other.x) && y.equalFloat(other.y) && theta.equalFloat(other.theta) + +fun Line2D.inverse() = Line2D(direction, base) +fun Line2D.shift(shift: Int, width: Double): Line2D { + val dX = width * sin(inverse().theta) + val dY = width * sin(theta) + + return Line2D( + Vector2D(base.x - dX * shift, base.y - dY * shift), + Vector2D(direction.x - dX * shift, direction.y - dY * shift) + ) +} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt new file mode 100644 index 000000000..583e7a4e0 --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -0,0 +1,68 @@ +/* + * 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.trajectory.dubins + +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Line2D +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.segments.Arc +import space.kscience.kmath.trajectory.segments.LineSegment +import space.kscience.kmath.trajectory.equalFloat +import space.kscience.kmath.trajectory.equalsFloat +import space.kscience.kmath.trajectory.inverse +import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.theta +import space.kscience.kmath.trajectory.shift +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + + +class DubinsTests { + + @Test + fun dubinsTest() { + val line = Line2D(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + val lineP1 = line.shift(1, 10.0).inverse() + + val start = Pose2D(line.direction, line.theta) + val end = Pose2D(lineP1.base, lineP1.theta) + val radius = 2.0 + val dubins = DubinsPathFactory(start, end, radius) + + val absoluteDistance = start.distanceTo(end) + println("Absolute distance: $absoluteDistance") + + val expectedLengths = mapOf( + DubinsPath.TYPE.RLR to 13.067681939031397, + DubinsPath.TYPE.RSR to 12.28318530717957, + DubinsPath.TYPE.LSL to 32.84955592153878, + DubinsPath.TYPE.RSL to 23.37758938854081, + DubinsPath.TYPE.LSR to 23.37758938854081 + ) + + expectedLengths.forEach { + val path = dubins[it.key] + assertNotNull(path, "Path ${it.key} not found") + println("${it.key}: ${path.length}") + assertTrue(it.value.equalFloat(path.length)) + + assertTrue(start.equalsFloat(path.a.pose1)) + assertTrue(end.equalsFloat(path.c.pose2)) + + // Not working, theta double precision inaccuracy + if (path.b is Arc) { + val b = path.b as Arc + assertTrue(path.a.pose2.equalsFloat(b.pose1)) + assertTrue(path.c.pose1.equalsFloat(b.pose2)) + } else if (path.b is LineSegment) { + val b = (path.b as LineSegment).line + assertTrue(path.a.pose2.equalsFloat(Pose2D(b.base, b.theta))) + assertTrue(path.c.pose1.equalsFloat(Pose2D(b.direction, b.theta))) + } + } + } +} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt new file mode 100644 index 000000000..73b3a1d87 --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -0,0 +1,24 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.radiansToDegrees +import space.kscience.kmath.trajectory.segments.components.Circle +import kotlin.test.Test +import kotlin.test.assertEquals + +class ArcTests { + + @Test + fun arcTest() { + val center = Vector2D(0.0, 0.0) + val radius = 2.0 + val expectedCircumference = 12.56637 + val circle = Circle(center, radius) + assertEquals(expectedCircumference, circle.circumference, 1.0) + + val arc = Arc(center, radius, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) + assertEquals(expectedCircumference / 4, arc.length, 1.0) + assertEquals(0.0, arc.pose1.theta.radiansToDegrees()) + assertEquals(90.0, arc.pose2.theta.radiansToDegrees()) + } +} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt new file mode 100644 index 000000000..30f5ef6d8 --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -0,0 +1,33 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Euclidean2DSpace +import space.kscience.kmath.geometry.Line2D +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.radiansToDegrees +import kotlin.math.pow +import kotlin.math.sqrt +import kotlin.test.Test +import kotlin.test.assertEquals + +class LineTests { + + @Test + fun lineTest() { + val line = Line2D(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), line.length) + assertEquals(45.0, line.theta.radiansToDegrees()) + } + + @Test + fun lineAngleTest() { + val zero = Vector2D(0.0, 0.0) + val north = Line2D(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) + assertEquals(0.0, north.theta.radiansToDegrees()) + val east = Line2D(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) + assertEquals(90.0, east.theta.radiansToDegrees()) + val south = Line2D(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) + assertEquals(180.0, south.theta.radiansToDegrees()) + val west = Line2D(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) + assertEquals(270.0, west.theta.radiansToDegrees()) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e3c621e9a..b564972c7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -44,6 +44,7 @@ include( ":kmath-jupyter", ":kmath-symja", ":kmath-jafama", + ":kmath-trajectory", ":examples", ":benchmarks", -) \ No newline at end of file +) From cdb116fa2009c36a2aaad9942032b35f83d4f8de Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Fri, 15 Jul 2022 18:55:37 +0200 Subject: [PATCH 129/174] Cleanup --- .../trajectory/dubins/DubinsPathFactory.kt | 94 +++++++++---------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt index 98ed8ed32..56875ac5b 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt @@ -32,51 +32,47 @@ public class DubinsPathFactory( val c1 = base.getRightCircle(turningRadius) val c2 = direction.getRightCircle(turningRadius) val centers = Line2D(c1.center, c2.center) - return if (centers.length < turningRadius * 4) { - var theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.RIGHT) - val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.LEFT) - val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.RIGHT) - DubinsPath(a1, a2, a3) - } else { - null - } + if (centers.length > turningRadius * 4) return null + + var theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.RIGHT) + val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.LEFT) + val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.RIGHT) + return DubinsPath(a1, a2, a3) } private val lrl: DubinsPath? get () { val c1 = base.getLeftCircle(turningRadius) val c2 = direction.getLeftCircle(turningRadius) val centers = Line2D(c1.center, c2.center) - return if (centers.length < turningRadius * 4) { - var theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.LEFT) - val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.LEFT) - DubinsPath(a1, a2, a3) - } else { - null - } + if (centers.length > turningRadius * 4) return null + + var theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.LEFT) + val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.LEFT) + return DubinsPath(a1, a2, a3) } - public val rsr: DubinsPath? get () { + public val rsr: DubinsPath get () { val c1 = base.getRightCircle(turningRadius) val c2 = direction.getRightCircle(turningRadius) val l = leftOuterTangent(c1, c2) @@ -99,26 +95,22 @@ public class DubinsPathFactory( val c1 = base.getRightCircle(turningRadius) val c2 = direction.getLeftCircle(turningRadius) val l = rightInnerTangent(c1, c2) - return if (c1.center.distanceTo(c2.center) > turningRadius * 2 && l != null) { - val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.LEFT) - DubinsPath(a1, LineSegment(l), a3) - } else { - null - } + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null + + val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.LEFT) + return DubinsPath(a1, LineSegment(l), a3) } public val lsr: DubinsPath? get () { val c1 = base.getLeftCircle(turningRadius) val c2 = direction.getRightCircle(turningRadius) val l = leftInnerTangent(c1, c2) - return if (c1.center.distanceTo(c2.center) > turningRadius * 2 && l != null) { - val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.RIGHT) - DubinsPath(a1, LineSegment(l), a3) - } else { - null - } + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null + + val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.RIGHT) + return DubinsPath(a1, LineSegment(l), a3) } } From ada1141738328101da29f48af4ba71bc8fca2d30 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Fri, 15 Jul 2022 18:57:10 +0200 Subject: [PATCH 130/174] Use Line distancTo function --- .../kotlin/space/kscience/kmath/trajectory/segments/Line.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt index f63372016..b3e93b5ed 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.trajectory.segments +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.operations.DoubleField.pow import kotlin.math.PI @@ -17,7 +18,7 @@ internal val Line2D.theta: Double get() = atan2(direction.x - base.x, direction.y - base.y).theta internal val Line2D.length: Double - get() = sqrt((direction.x - base.x).pow(2) + (direction.y - base.y).pow(2)) + get() = base.distanceTo(direction) internal val Double.theta: Double get() = (this + (2 * PI)) % (2 * PI) From fa6d741869099923c120e709e11c521c85d425fc Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Fri, 15 Jul 2022 22:12:36 +0200 Subject: [PATCH 131/174] Small improvement in test classes, theta function --- .../trajectory/dubins/DubinsPathFactory.kt | 46 ++++++++++--------- .../kscience/kmath/trajectory/segments/Arc.kt | 11 ++--- .../kmath/trajectory/segments/Line.kt | 7 ++- .../trajectory/segments/components/Pose2D.kt | 7 +-- .../space/kscience/kmath/trajectory/Math.kt | 2 +- .../kmath/trajectory/segments/ArcTests.kt | 11 ++--- .../segments/components/CircleTests.kt | 23 ++++++++++ 7 files changed, 60 insertions(+), 47 deletions(-) create mode 100644 kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt index 56875ac5b..818735a96 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt @@ -34,19 +34,19 @@ public class DubinsPathFactory( val centers = Line2D(c1.center, c2.center) if (centers.length > turningRadius * 4) return null - var theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta + var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle(p, turningRadius) val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta + theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.RIGHT) - val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.LEFT) - val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.RIGHT) + val a1 = Arc(c1.center, base, p1, Arc.Direction.RIGHT) + val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) + val a3 = Arc(c2.center, p2, direction, Arc.Direction.RIGHT) return DubinsPath(a1, a2, a3) } @@ -56,19 +56,19 @@ public class DubinsPathFactory( val centers = Line2D(c1.center, c2.center) if (centers.length > turningRadius * 4) return null - var theta = (centers.theta + acos(centers.length / (turningRadius * 4))).theta + var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle(p, turningRadius) val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = (centers.theta - acos(centers.length / (turningRadius * 4))).theta + theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, turningRadius, base, p1, Arc.Direction.LEFT) - val a2 = Arc(e.center, turningRadius, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, turningRadius, p2, direction, Arc.Direction.LEFT) + val a1 = Arc(c1.center, base, p1, Arc.Direction.LEFT) + val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, p2, direction, Arc.Direction.LEFT) return DubinsPath(a1, a2, a3) } @@ -76,8 +76,8 @@ public class DubinsPathFactory( val c1 = base.getRightCircle(turningRadius) val c2 = direction.getRightCircle(turningRadius) val l = leftOuterTangent(c1, c2) - val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.RIGHT) + val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) return DubinsPath(a1, LineSegment(l), a3) } @@ -86,8 +86,8 @@ public class DubinsPathFactory( val c1 = base.getLeftCircle(turningRadius) val c2 = direction.getLeftCircle(turningRadius) val l = rightOuterTangent(c1, c2) - val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.LEFT) + val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) return DubinsPath(a1, LineSegment(l), a3) } @@ -97,8 +97,8 @@ public class DubinsPathFactory( val l = rightInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null - val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.LEFT) + val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) return DubinsPath(a1, LineSegment(l), a3) } @@ -108,8 +108,8 @@ public class DubinsPathFactory( val l = leftInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null - val a1 = Arc(c1.center, turningRadius, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, turningRadius, l.direction, direction, Arc.Direction.RIGHT) + val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) return DubinsPath(a1, LineSegment(l), a3) } } @@ -148,10 +148,12 @@ private fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(ba private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Line2D? { val centers = Line2D(base.center, direction.center) return if (centers.length > base.radius * 2) { - val angle = when (side) { - SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) - SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) - }.theta + val angle = theta( + when (side) { + SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) + SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) + } + ) val dX = base.radius * sin(angle) val dY = base.radius * cos(angle) val p1 = Vector2D(base.center.x + dX, base.center.y + dY) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt index a7b2fe259..b8a81a070 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.trajectory.segments +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.segments.components.Circle @@ -8,11 +9,10 @@ import kotlin.math.PI public class Arc( center: Vector2D, - radius: Double, a: Vector2D, b: Vector2D, internal val direction: Direction -) : Circle(center, radius), Segment { +) : Circle(center, center.distanceTo(a)), Segment { private val l1 = Line2D(center, a) private val l2 = Line2D(center, b) @@ -26,8 +26,7 @@ public class Arc( LEFT, RIGHT } - private fun calculateAngle() = - (if (direction == Direction.LEFT) l1.theta - l2.theta else l2.theta - l1.theta).theta + private fun calculateAngle() = theta(if (direction == Direction.LEFT) l1.theta - l2.theta else l2.theta - l1.theta) private fun calculateLength(): Double { val proportion = angle / (2 * PI) @@ -36,8 +35,8 @@ public class Arc( private fun calculatePose(vector: Vector2D, theta: Double): Pose2D = if (direction == Direction.LEFT) { - Pose2D(vector.x, vector.y, (theta - PI / 2).theta) + Pose2D(vector.x, vector.y, theta(theta - PI / 2)) } else { - Pose2D(vector.x, vector.y, (theta + PI / 2).theta) + Pose2D(vector.x, vector.y, theta(theta + PI / 2)) } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt index b3e93b5ed..0e23b27f1 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt @@ -7,7 +7,7 @@ import kotlin.math.PI import kotlin.math.atan2 import kotlin.math.sqrt -public class LineSegment( +public data class LineSegment( internal val line: Line2D ) : Segment { override val length: Double @@ -15,10 +15,9 @@ public class LineSegment( } internal val Line2D.theta: Double - get() = atan2(direction.x - base.x, direction.y - base.y).theta + get() = theta(atan2(direction.x - base.x, direction.y - base.y)) internal val Line2D.length: Double get() = base.distanceTo(direction) -internal val Double.theta: Double - get() = (this + (2 * PI)) % (2 * PI) +internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt index 6bcc3d308..d00dfbd96 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt @@ -4,15 +4,10 @@ import space.kscience.kmath.geometry.Vector2D import kotlin.math.cos import kotlin.math.sin -public class Pose2D( +public data class Pose2D( override val x: Double, override val y: Double, public val theta: Double ) : Vector2D { - internal constructor(vector: Vector2D, theta: Double) : this(vector.x, vector.y, theta) - - override fun toString(): String { - return "Pose2D(x=$x, y=$y, theta=$theta)" - } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 9258e6b4a..f52bb56f2 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -8,7 +8,7 @@ import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin -private const val maxFloatDelta = 0.000001 +const val maxFloatDelta = 0.000001 fun Double.radiansToDegrees() = this * 180 / PI diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index 73b3a1d87..a59643c0c 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -10,14 +10,9 @@ class ArcTests { @Test fun arcTest() { - val center = Vector2D(0.0, 0.0) - val radius = 2.0 - val expectedCircumference = 12.56637 - val circle = Circle(center, radius) - assertEquals(expectedCircumference, circle.circumference, 1.0) - - val arc = Arc(center, radius, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) - assertEquals(expectedCircumference / 4, arc.length, 1.0) + val circle = Circle(Vector2D(0.0, 0.0), 2.0) + val arc = Arc(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) + assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.pose1.theta.radiansToDegrees()) assertEquals(90.0, arc.pose2.theta.radiansToDegrees()) } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt new file mode 100644 index 000000000..6f28885e0 --- /dev/null +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt @@ -0,0 +1,23 @@ +/* + * 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.trajectory.segments.components + +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.maxFloatDelta +import kotlin.test.Test +import kotlin.test.assertEquals + +class CircleTests { + + @Test + fun arcTest() { + val center = Vector2D(0.0, 0.0) + val radius = 2.0 + val expectedCircumference = 12.56637 + val circle = Circle(center, radius) + assertEquals(expectedCircumference, circle.circumference, maxFloatDelta) + } +} From 4f88982734acfdfa5f771c3c9c3705801ab00781 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Fri, 15 Jul 2022 22:13:50 +0200 Subject: [PATCH 132/174] Formatting --- .../trajectory/dubins/DubinsPathFactory.kt | 158 +++++++++--------- 1 file changed, 83 insertions(+), 75 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt index 818735a96..91287b952 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt @@ -28,90 +28,95 @@ public class DubinsPathFactory( public val shortest: DubinsPath get() = all.minByOrNull { it.length }!! public operator fun get(type: DubinsPath.TYPE): DubinsPath? = all.find { it.type == type } - public val rlr: DubinsPath? get () { - val c1 = base.getRightCircle(turningRadius) - val c2 = direction.getRightCircle(turningRadius) - val centers = Line2D(c1.center, c2.center) - if (centers.length > turningRadius * 4) return null + public val rlr: DubinsPath? + get() { + val c1 = base.getRightCircle(turningRadius) + val c2 = direction.getRightCircle(turningRadius) + val centers = Line2D(c1.center, c2.center) + if (centers.length > turningRadius * 4) return null - var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, base, p1, Arc.Direction.RIGHT) - val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) - val a3 = Arc(c2.center, p2, direction, Arc.Direction.RIGHT) - return DubinsPath(a1, a2, a3) - } + var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, base, p1, Arc.Direction.RIGHT) + val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) + val a3 = Arc(c2.center, p2, direction, Arc.Direction.RIGHT) + return DubinsPath(a1, a2, a3) + } - private val lrl: DubinsPath? get () { - val c1 = base.getLeftCircle(turningRadius) - val c2 = direction.getLeftCircle(turningRadius) - val centers = Line2D(c1.center, c2.center) - if (centers.length > turningRadius * 4) return null + private val lrl: DubinsPath? + get() { + val c1 = base.getLeftCircle(turningRadius) + val c2 = direction.getLeftCircle(turningRadius) + val centers = Line2D(c1.center, c2.center) + if (centers.length > turningRadius * 4) return null - var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, base, p1, Arc.Direction.LEFT) - val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, p2, direction, Arc.Direction.LEFT) - return DubinsPath(a1, a2, a3) - } + var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, base, p1, Arc.Direction.LEFT) + val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, p2, direction, Arc.Direction.LEFT) + return DubinsPath(a1, a2, a3) + } - public val rsr: DubinsPath get () { - val c1 = base.getRightCircle(turningRadius) - val c2 = direction.getRightCircle(turningRadius) - val l = leftOuterTangent(c1, c2) - val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) - return DubinsPath(a1, LineSegment(l), a3) - } + public val rsr: DubinsPath + get() { + val c1 = base.getRightCircle(turningRadius) + val c2 = direction.getRightCircle(turningRadius) + val l = leftOuterTangent(c1, c2) + val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) + return DubinsPath(a1, LineSegment(l), a3) + } public val lsl: DubinsPath - get () { - val c1 = base.getLeftCircle(turningRadius) - val c2 = direction.getLeftCircle(turningRadius) - val l = rightOuterTangent(c1, c2) - val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) - return DubinsPath(a1, LineSegment(l), a3) - } + get() { + val c1 = base.getLeftCircle(turningRadius) + val c2 = direction.getLeftCircle(turningRadius) + val l = rightOuterTangent(c1, c2) + val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) + return DubinsPath(a1, LineSegment(l), a3) + } - public val rsl: DubinsPath? get () { - val c1 = base.getRightCircle(turningRadius) - val c2 = direction.getLeftCircle(turningRadius) - val l = rightInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null + public val rsl: DubinsPath? + get() { + val c1 = base.getRightCircle(turningRadius) + val c2 = direction.getLeftCircle(turningRadius) + val l = rightInnerTangent(c1, c2) + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null - val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) - return DubinsPath(a1, LineSegment(l), a3) - } + val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) + return DubinsPath(a1, LineSegment(l), a3) + } - public val lsr: DubinsPath? get () { - val c1 = base.getLeftCircle(turningRadius) - val c2 = direction.getRightCircle(turningRadius) - val l = leftInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null + public val lsr: DubinsPath? + get() { + val c1 = base.getLeftCircle(turningRadius) + val c2 = direction.getRightCircle(turningRadius) + val l = leftInnerTangent(c1, c2) + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null - val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) - return DubinsPath(a1, LineSegment(l), a3) - } + val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) + val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) + return DubinsPath(a1, LineSegment(l), a3) + } } private enum class SIDE { @@ -140,7 +145,10 @@ private fun outerTangent(a: Circle, b: Circle, side: SIDE): Line2D { a.center.y - a.radius * sin(centers.theta) ) } - return Line2D(p1, Vector2D(p1.x + (centers.direction.x - centers.base.x), p1.y + (centers.direction.y - centers.base.y))) + return Line2D( + p1, + Vector2D(p1.x + (centers.direction.x - centers.base.x), p1.y + (centers.direction.y - centers.base.y)) + ) } private fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) From 68add4cb5f189d30a7ab5156d141beec97746b02 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 16 Jul 2022 11:35:50 +0300 Subject: [PATCH 133/174] Refactor test naming --- CHANGELOG.md | 1 + .../{DerivativeStructureExpressionTest.kt => DSTest.kt} | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/{DerivativeStructureExpressionTest.kt => DSTest.kt} (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4b8c06cf..ec993fb36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] ### Added +- Autodiff for generic algebra elements in core! ### Changed - Kotlin 1.7 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt similarity index 98% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt index e5bc9805a..727a918ec 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt @@ -25,7 +25,7 @@ internal inline fun diff( DSField(DoubleField, ::DoubleBuffer, order, mapOf(*parameters)).block() } -internal class AutoDiffTest { +internal class DSTest { private val x by symbol private val y by symbol From 579511a5ee0b598fd0e72863ad69f33456e84996 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 16:07:03 +0300 Subject: [PATCH 134/174] Add utilities for maps. Fix some tests. --- .../LabeledPolynomial.kt | 171 ++---- .../ListPolynomial.kt | 24 +- .../NumberedPolynomial.kt | 80 +-- .../collectionUtils.kt | 500 ++++++++++++++++++ .../labeledConstructors.kt | 50 +- .../labeledUtil.kt | 24 +- .../numberedConstructors.kt | 47 +- .../numberedUtil.kt | 10 +- .../functions/NumberedConstructorsTest.kt | 12 +- 9 files changed, 606 insertions(+), 312 deletions(-) create mode 100644 kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index 12bf9f839..b07674a1e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -150,12 +150,7 @@ public class LabeledPolynomialSpace>( else with(coefficients) { if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } + withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } ) } /** @@ -168,12 +163,7 @@ public class LabeledPolynomialSpace>( else with(coefficients) { if (isEmpty()) (-other).asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } + withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } ) } /** @@ -186,11 +176,7 @@ public class LabeledPolynomialSpace>( 0 -> zero 1 -> this else -> LabeledPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { (_, value) -> value * other } ) } @@ -204,12 +190,7 @@ public class LabeledPolynomialSpace>( else with(other.coefficients) { if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } ) } /** @@ -218,18 +199,14 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) -other - else with(other.coefficients) { - if (isEmpty()) this@minus.asPolynomial() - else LabeledPolynomialAsIs( - toMutableMap() - .apply { - forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } + when { + this == 0 -> -other + other.coefficients.isEmpty() -> this@minus.asPolynomial() + else -> LabeledPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(emptyMap(), asConstant()) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) + } ) } /** @@ -242,11 +219,7 @@ public class LabeledPolynomialSpace>( 0 -> zero 1 -> other else -> LabeledPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { (_, value) -> this@times * value } ) } @@ -305,41 +278,26 @@ public class LabeledPolynomialSpace>( with(other.coefficients) { if (isEmpty()) this@plus.asLabeledPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } ) } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun C.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@minus.asLabeledPolynomial() - else LabeledPolynomialAsIs( - toMutableMap() - .apply { - forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyMap() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } + if (other.coefficients.isEmpty()) this@minus.asPolynomial() + else LabeledPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(emptyMap(), this@minus) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) + } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ override operator fun C.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { this@times * it.value } ) /** @@ -349,12 +307,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } + other - } + withPutOrChanged(emptyMap(), other) { it -> it + other } ) } /** @@ -364,12 +317,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asLabeledPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyMap() - - this[degs] = getOrElse(degs) { constantZero } - other - } + withPutOrChanged(emptyMap(), -other) { it -> it - other } ) } /** @@ -377,11 +325,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.times(other: C): LabeledPolynomial = LabeledPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { it.value * other } ) /** @@ -441,38 +385,27 @@ public class LabeledPolynomialSpace>( with(other.coefficients) { if (isEmpty()) this@plus.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = mapOf(this@plus to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } + withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } ) } /** * Returns difference between the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.minus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@minus.asPolynomial() - else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val theVariableDegs = mapOf(this@minus to 1U) - - forEach { (degs, c) -> if(degs != theVariableDegs) this[degs] = -c } - - this[theVariableDegs] = constantOne - getOrElse(theVariableDegs) { constantZero } - } - ) - } + if (other.coefficients.isEmpty()) this@minus.asPolynomial() + else LabeledPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(mapOf(this@minus to 1U), constantOne) + other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, newC -> currentC - newC } + } + ) /** * Returns product of the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.times(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( other.coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[this] = if (this in it) it[this]!! + 1U else 1U } } + .mapKeys { (degs, _) -> degs.withPutOrChanged(this, 1u) { it -> it + 1u } } ) /** @@ -482,12 +415,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = constantOne + getOrElse(degs) { constantZero } - } + withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } ) } /** @@ -497,12 +425,7 @@ public class LabeledPolynomialSpace>( with(coefficients) { if (isEmpty()) other.asPolynomial() else LabeledPolynomialAsIs( - toMutableMap() - .apply { - val degs = mapOf(other to 1U) - - this[degs] = getOrElse(degs) { constantZero } - constantOne - } + withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } ) } /** @@ -511,7 +434,7 @@ public class LabeledPolynomialSpace>( public override operator fun LabeledPolynomial.times(other: Symbol): LabeledPolynomial = LabeledPolynomialAsIs( coefficients - .mapKeys { (degs, _) -> degs.toMutableMap().also{ it[other] = if (other in it) it[other]!! + 1U else 1U } } + .mapKeys { (degs, _) -> degs.withPutOrChanged(other, 1u) { it -> it + 1u } } ) /** @@ -526,10 +449,7 @@ public class LabeledPolynomialSpace>( */ override operator fun LabeledPolynomial.plus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( - buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + mergeBy(coefficients, other.coefficients) { c1, c2 -> c1 + c2 } ) /** * Returns difference of the polynomials. @@ -537,8 +457,8 @@ public class LabeledPolynomialSpace>( override operator fun LabeledPolynomial.minus(other: LabeledPolynomial): LabeledPolynomial = LabeledPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + coefficients.copyTo(this) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) } ) /** @@ -548,10 +468,9 @@ public class LabeledPolynomialSpace>( LabeledPolynomialAsIs( buildMap(coefficients.size * other.coefficients.size) { for ((degs1, c1) in coefficients) for ((degs2, c2) in other.coefficients) { - val degs = degs1.toMutableMap() - degs2.mapValuesTo(degs) { (variable, deg) -> degs.getOrElse(variable) { 0u } + deg } + val degs = mergeBy(degs1, degs2) { deg1, deg2 -> deg1 + deg2 } val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c + this.putOrChange(degs, c) { it -> it + c } } } ) @@ -581,10 +500,8 @@ public class LabeledPolynomialSpace>( public override val LabeledPolynomial.degrees: Map get() = buildMap { - coefficients.entries.forEach { (degs, _) -> - degs.mapValuesTo(this) { (variable, deg) -> - max(getOrElse(variable) { 0u }, deg) - } + coefficients.keys.forEach { degs -> + degs.copyToBy(this, ::max) } } /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt index 91b9c7658..17c42ac8c 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -109,11 +109,7 @@ public open class ListPolynomialSpace>( 0 -> zero 1 -> this else -> ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } + coefficients.map { it * other } ) } @@ -167,11 +163,7 @@ public open class ListPolynomialSpace>( 0 -> zero 1 -> other else -> ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } + other.coefficients.map { this@times * it } ) } @@ -214,11 +206,7 @@ public open class ListPolynomialSpace>( */ public override operator fun C.times(other: ListPolynomial): ListPolynomial = ListPolynomial( - other.coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this@times * this[deg] - } + other.coefficients.map { this@times * it } ) /** @@ -258,11 +246,7 @@ public open class ListPolynomialSpace>( */ public override operator fun ListPolynomial.times(other: C): ListPolynomial = ListPolynomial( - coefficients - .toMutableList() - .apply { - for (deg in indices) this[deg] = this[deg] * other - } + coefficients.map { it * other } ) /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index 96c96e555..14c03ff7c 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -71,13 +71,7 @@ public class NumberedPolynomialSpace>( if (other == 0) this else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } + coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } ) /** * Returns difference between the polynomial and the integer represented as a polynomial. @@ -88,13 +82,7 @@ public class NumberedPolynomialSpace>( if (other == 0) this else NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } + coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } ) /** * Returns product of the polynomial and the integer represented as a polynomial. @@ -106,11 +94,7 @@ public class NumberedPolynomialSpace>( 0 -> zero 1 -> this else -> NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { it.value * other } ) } @@ -123,13 +107,7 @@ public class NumberedPolynomialSpace>( if (this == 0) other else NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } ) /** * Returns difference between the integer represented as a polynomial and the polynomial. @@ -162,11 +140,7 @@ public class NumberedPolynomialSpace>( 0 -> zero 1 -> other else -> NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { this@times * it.value } ) } @@ -177,12 +151,7 @@ public class NumberedPolynomialSpace>( with(other.coefficients) { if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) else NumberedPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = this@plus + getOrElse(degs) { constantZero } - } + withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } ) } /** @@ -207,11 +176,7 @@ public class NumberedPolynomialSpace>( */ override operator fun C.times(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this@times * this[degs]!! - } + other.coefficients.mapValues { this@times * it.value } ) /** @@ -221,12 +186,7 @@ public class NumberedPolynomialSpace>( with(coefficients) { if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) else NumberedPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } + other - } + withPutOrChanged(emptyList(), other) { it -> it + other } ) } /** @@ -236,12 +196,7 @@ public class NumberedPolynomialSpace>( with(coefficients) { if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) else NumberedPolynomialAsIs( - toMutableMap() - .apply { - val degs = emptyList() - - this[degs] = getOrElse(degs) { constantZero } - other - } + withPutOrChanged(emptyList(), -other) { it -> it - other } ) } /** @@ -249,11 +204,7 @@ public class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.times(other: C): NumberedPolynomial = NumberedPolynomialAsIs( - coefficients - .toMutableMap() - .apply { - for (degs in keys) this[degs] = this[degs]!! * other - } + coefficients.mapValues { it.value * other } ) /** @@ -274,10 +225,7 @@ public class NumberedPolynomialSpace>( */ override operator fun NumberedPolynomial.plus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( - buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! + value else value } - } + mergeBy(coefficients, other.coefficients) { c1, c2 -> c1 + c2 } ) /** * Returns difference of the polynomials. @@ -285,8 +233,8 @@ public class NumberedPolynomialSpace>( override operator fun NumberedPolynomial.minus(other: NumberedPolynomial): NumberedPolynomial = NumberedPolynomialAsIs( buildMap(coefficients.size + other.coefficients.size) { - coefficients.mapValuesTo(this) { it.value } - other.coefficients.mapValuesTo(this) { (key, value) -> if (key in this) this[key]!! - value else -value } + coefficients.copyTo(this) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, newC -> currentC - newC }) } ) /** @@ -300,7 +248,7 @@ public class NumberedPolynomialSpace>( (0..max(degs1.lastIndex, degs2.lastIndex)) .map { degs1.getOrElse(it) { 0U } + degs2.getOrElse(it) { 0U } } val c = c1 * c2 - this[degs] = if (degs in this) this[degs]!! + c else c + putOrChange(degs, c) { it -> it + c } } } ) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt new file mode 100644 index 000000000..1d3da4c8b --- /dev/null +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt @@ -0,0 +1,500 @@ +/* + * 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 kotlin.contracts.InvocationKind.* +import kotlin.contracts.contract + + +/** + * Applies the [transformation][transform] to the value corresponding to the given [key] or null instead if it's not + * present. + * + * @param key key to check. + * @param transform transformation to apply. + * @return result of the transformation + */ +internal inline fun MutableMap.applyToKey(key: K, transform: (currentValue: V?) -> V): V { + contract { + callsInPlace(transform, EXACTLY_ONCE) + } + return transform(get(key)).also { this[key] = it } +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value calculated by [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut lazily calculated value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: () -> V, transformOnChange: (currentValue: V) -> V): V { + contract { + callsInPlace(valueOnPut, AT_MOST_ONCE) + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + @Suppress("UNCHECKED_CAST") + return (if (key !in this) valueOnPut() else transformOnChange(get(key) as V)).also { this[key] = it } +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: V, transformOnChange: (currentValue: V) -> V): V { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return putOrChange(key, { valueOnPut }, transformOnChange) +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value and new value as parameters. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: V, transformOnChange: (currentValue: V, newValue: V) -> V): V { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return putOrChange(key, { valueOnPut }, { transformOnChange(it, valueOnPut) }) +} + +/** + * Depending on presence of value corresponding to the given [key] either puts new value [valueOnPut] or + * changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * the [key], current value, and new value as parameters. + * @return result value corresponding to the [key]. + */ +internal inline fun MutableMap.putOrChange(key: K, valueOnPut: V, transformOnChange: (key: K, currentValue: V, newValue: V) -> V): V { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return putOrChange(key, { valueOnPut }, { transformOnChange(key, it, valueOnPut) }) +} + +/** + * Creates copy of [the map][this] and applies the [transformation][transform] to the value corresponding to the given + * [key] in the copy or null instead if it's not present. + * + * @param key key to check. + * @param transform transformation to apply. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withAppliedToKey(key: K, transform: (currentValue: V?) -> V): Map { + contract { + callsInPlace(transform, EXACTLY_ONCE) + } + return buildMap(size) { + putAll(this) + applyToKey(key, transform) + } +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value calculated by [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut lazily calculated value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: () -> V, transformOnChange: (currentValue: V) -> V): Map { + contract { + callsInPlace(valueOnPut, AT_MOST_ONCE) + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return buildMap(size + 1) { + putAll(this@withPutOrChanged) + putOrChange(key, valueOnPut, transformOnChange) + } +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value as a parameter. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (currentValue: V) -> V): Map { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return withPutOrChanged(key, { valueOnPut }, transformOnChange) +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * current value and new value as parameters. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (currentValue: V, newValue: V) -> V): Map { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return withPutOrChanged(key, { valueOnPut }, { transformOnChange(it, valueOnPut) }) +} + +/** + * Creates copy of [the map][this] and depending on presence of value corresponding to the given [key] either puts new + * value [valueOnPut] or changes the present value with [transformOnChange]. + * + * @param key key to check. + * @param valueOnPut value to put in case of absence of the [key]. + * @param transformOnChange transform to apply to current value corresponding to the [key] in case of its presence. Uses + * the [key], current value, and new value as parameters. + * @return the copy of [the map][this]. + */ +internal inline fun Map.withPutOrChanged(key: K, valueOnPut: V, transformOnChange: (key: K, currentValue: V, newValue: V) -> V): Map { + contract { + callsInPlace(transformOnChange, AT_MOST_ONCE) + } + return withPutOrChanged(key, { valueOnPut }, { transformOnChange(key, it, valueOnPut) }) +} + +/** + * Copies entries of [this map][this] to the [destination] map overriding present ones if needed. + * + * @receiver map to be copied. + * @param destination map to receive copies. + * @return the [destination]. + */ +internal fun > Map.copyTo(destination: D): D { + for ((key, value) in this) { + destination[key] = value + } + return destination +} + +/** + * Copies entries of [this map][this] to the [destination] map merging present entries with new ones using [resolve] + * lambda. + * + * @receiver map to be copied. + * @param destination map to receive copies. + * @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyToBy(destination: D, resolve: (key: K, currentValue: W, newValue: V) -> W): D { + for ((key, value) in this) { + destination.putOrChange(key, value) { it -> resolve(key, it, value) } + } + return destination +} + +/** + * Copies entries of [this map][this] to the [destination] map merging present entries with new ones using [resolve] + * lambda. + * + * @receiver map to be copied. + * @param destination map to receive copies. + * @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyToBy(destination: D, resolve: (currentValue: W, newValue: V) -> W): D = + copyToBy(destination) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map overriding present ones if needed. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyTo(destination) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @return the [destination]. + */ +internal inline fun > Map.copyMapTo(destination: D, transform: (Map.Entry) -> W): D { + for (entry in this) { + destination[entry.key] = transform(entry) + } + return destination +} + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map overriding present ones if needed. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyTo(destination) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @return the [destination]. + */ +internal inline fun > Map.copyMapTo(destination: D, transform: (key: K, value: V) -> W): D = + copyMapTo(destination) { (key, value) -> transform(key, value) } + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (Map.Entry) -> W, resolve: (key: K, currentValue: W, newValue: V) -> W): D { + for (entry in this) { + val (key, value) = entry + destination.putOrChange(key, transform(entry)) { it -> resolve(key, it, value) } + } + return destination +} + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes a key, current value corresponding to the key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: V) -> W): D = + copyMapToBy(destination, { (key, value) -> transform(key, value) }, resolve) + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (Map.Entry) -> W, resolve: (currentValue: W, newValue: V) -> W): D = + copyMapToBy(destination, transform, { _, currentValue, newValue -> resolve(currentValue, newValue) }) + +/** + * Transforms values of entries of [this map][this] with [the given transformation][transform] and copies resulting + * entries to the [destination] map merging present entries with new ones using [resolve] lambda. Is equivalent to + * ```kotlin + * this.mapValues(transform).copyToBy(destination, resolve) + * ``` + * + * @receiver map to be transformed and copied. + * @param destination map to receive copies. + * @param transform generates value of transformed entry using initial entry as an argument. Key of transformed entry is + * the same as initial entry. + * @param resolve lambda function that resolves overriding. It takes current value corresponding to some key, and + * a new one and returns value to associate to the key. + * @return the [destination]. + */ +internal inline fun > Map.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: V) -> W): D = + copyMapToBy(destination, { (key, value) -> transform(key, value) }, { _, currentValue, newValue -> resolve(currentValue, newValue) }) + +// TODO: Docs +internal fun > mergeTo(map1: Map, map2: Map, destination: D): D { + for ((key, value) in map1) { + destination.put(key, value) + } + for ((key, value) in map2) { + destination.put(key, value) + } + return destination +} + +// TODO: Docs +internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (key: K, value1: V1, value2: V2) -> W): D { + for (key in map2.keys) { + destination.remove(key) + } + for ((key, value) in map1) { + destination.put(key, value) + } + for ((key, value) in map2) { + @Suppress("UNCHECKED_CAST") + destination.putOrChange(key, value) { it -> resolve(key, it as V1, value) } + } + return destination +} + +// TODO: Docs +internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (value1: V1, value2: V2) -> W): D = + mergeToBy(map1, map2, destination) { _, value1, value2 -> resolve(value1, value2) } + +// TODO: Docs +internal fun merge(map1: Map, map2: Map): Map { + val result = LinkedHashMap(map1.size + map2.size) + return mergeTo(map1, map2, result) +} + +// TODO: Docs +internal inline fun mergeBy(map1: Map, map2: Map, transform: (key: K, value1: V1, value2: V2) -> W): Map { + val result = LinkedHashMap(map1.size + map2.size) + return mergeToBy(map1, map2, result, transform) +} + +// TODO: Docs +internal inline fun mergeBy(map1: Map, map2: Map, transform: (value1: V1, value2: V2) -> W): Map = + mergeBy(map1, map2) { _, value1, value2 -> transform(value1, value2) } + +// TODO: Docs +internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): D { + for (element in this) { + val (key, value) = transform(element) + destination.putOrChange(key, value, resolve) + } + return destination +} + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): D { + for (element in this) { + val key = keySelector(element) + val value = valueTransform(element) + destination.putOrChange(key, value, resolve) + } + return destination +} + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): D { + for (element in this) { + val key = keySelector(element) + destination.putOrChange(key, element, resolve) + } + return destination +} + +// TODO: Docs +internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): D = + associateTo(destination, transform) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): D = + associateByTo(destination, keySelector, valueTransform) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +// TODO: Docs +internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): D = + associateByTo(destination, keySelector) { _, currentValue, newValue -> resolve(currentValue, newValue) } + +// TODO: Docs +internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = + associateTo(LinkedHashMap(), transform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = + associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): Map = + associateByTo(LinkedHashMap(), keySelector, resolve) + +// TODO: Docs +internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): Map = + associateTo(LinkedHashMap(), transform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): Map = + associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) + +// TODO: Docs +internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): Map = + associateByTo(LinkedHashMap(), keySelector, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, transform, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, transform, resolve) + +// TODO: Docs +internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: W) -> W): D = + entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, transform, { it.value }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, transform, { it.value }, resolve) + +// TODO: Docs +internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): D = + entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) + +// TODO: Docs +internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = + mapKeysTo(LinkedHashMap(size), transform, resolve) \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index aa44660c1..43048089e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -10,6 +10,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke /** @@ -76,17 +77,10 @@ public inline fun LabeledPolynomialWithoutCheck(vararg pairs: Pair LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return LabeledPolynomial(fixedCoefs) -} +public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) -> C) : LabeledPolynomial = + LabeledPolynomialAsIs( + coefs.mapKeys({ key, _ -> key.cleanUp() }, add) + ) /** * Constructs [LabeledPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -98,17 +92,10 @@ public fun LabeledPolynomial(coefs: Map, C>, add: (C, C) - * * @see LabeledPolynomialWithoutCheck */ -public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return LabeledPolynomial(fixedCoefs) -} +public fun LabeledPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : LabeledPolynomial = + LabeledPolynomialAsIs( + pairs.associateBy({ it.first.cleanUp() }, { it.second }, add) + ) /** * Constructs [LabeledPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -120,17 +107,10 @@ public fun LabeledPolynomial(pairs: Collection, C>>, * * @see LabeledPolynomialWithoutCheck */ -public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return LabeledPolynomial(fixedCoefs) -} +public fun LabeledPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : LabeledPolynomial = + LabeledPolynomialAsIs( + pairs.asIterable().associateBy({ it.first.cleanUp() }, { it.second }, add) + ) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -304,7 +284,7 @@ public class DSL1LabeledPolynomialTermSignatureBuilder { */ public infix fun Symbol.inPowerOf(deg: UInt) { if (deg == 0u) return - signature[this] = signature.getOrElse(this) { 0u } + deg + signature.putOrChange(this, deg) { it -> it + deg } } /** * Declares power of [this] variable of degree [deg]. @@ -362,7 +342,7 @@ public class DSL1LabeledPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: Map) { - coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + coefficients.putOrChange(signature, this@with, add) } /** * Declares monomial with [this] coefficient and signature constructed by [block]. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt index e3b35facc..a37a1fe39 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt @@ -7,10 +7,7 @@ package space.kscience.kmath.functions import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.* import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmName @@ -56,7 +53,7 @@ public fun LabeledPolynomial.substitute(args: Map): Labe val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - this[newDegs] = if (newDegs in this) this[newDegs]!! + newC else newC + putOrChange(newDegs, newC, ::add) } } ) @@ -75,7 +72,7 @@ public fun LabeledPolynomial.substitute(ring: Ring, args: Map> LabeledPolynomial.antiderivativeWithRespectTo( buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, 1u) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } + val newDegs = degs.withPutOrChanged(variable, 1u) { it -> it + 1u } put( newDegs, c / multiplyByDoubling(one, newDegs[variable]!!) @@ -284,10 +278,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } + val newDegs = degs.withPutOrChanged(variable, order) { it -> it + order } put( newDegs, newDegs[variable]!!.let { deg -> @@ -314,10 +305,7 @@ public fun > LabeledPolynomial.nthAntiderivativeWithRespectTo buildMap(coefficients.size) { coefficients .forEach { (degs, c) -> - val newDegs = buildMap(degs.size + 1) { - for ((variable, order) in filteredVariablesAndOrders) put(variable, order) - for ((vari, deg) in degs) put(vari, deg + getOrElse(vari) { 0u }) - } + val newDegs = mergeBy(degs, filteredVariablesAndOrders) { deg, order -> deg + order } put( newDegs, filteredVariablesAndOrders.entries.fold(c) { acc1, (index, order) -> diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt index ce0db3d17..ce49088ae 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt @@ -75,17 +75,10 @@ public inline fun NumberedPolynomialWithoutCheck(vararg pairs: Pair NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in coefs) { - val key = entry.key.cleanUp() - val value = entry.value - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return NumberedPolynomial(fixedCoefs) -} +public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : NumberedPolynomial = + NumberedPolynomialAsIs( + coefs.mapKeys({ key, _ -> key.cleanUp() }, add) + ) /** * Constructs [NumberedPolynomial] with provided collection of [pairs] of pairs "term's signature — term's coefficient". @@ -97,17 +90,10 @@ public fun NumberedPolynomial(coefs: Map, C>, add: (C, C) -> C) : * * @see NumberedPolynomialWithoutCheck */ -public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return NumberedPolynomial(fixedCoefs) -} +public fun NumberedPolynomial(pairs: Collection, C>>, add: (C, C) -> C) : NumberedPolynomial = + NumberedPolynomialAsIs( + pairs.associateBy({ it.first.cleanUp() }, { it.second }, add) + ) /** * Constructs [NumberedPolynomial] with provided array [pairs] of pairs "term's signature — term's coefficient". @@ -119,17 +105,10 @@ public fun NumberedPolynomial(pairs: Collection, C>>, add: ( * * @see NumberedPolynomialWithoutCheck */ -public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial { - val fixedCoefs = mutableMapOf, C>() - - for (entry in pairs) { - val key = entry.first.cleanUp() - val value = entry.second - fixedCoefs[key] = if (key in fixedCoefs) add(fixedCoefs[key]!!, value) else value - } - - return NumberedPolynomial(fixedCoefs) -} +public fun NumberedPolynomial(vararg pairs: Pair, C>, add: (C, C) -> C) : NumberedPolynomial = + NumberedPolynomialAsIs( + pairs.asIterable().associateBy({ it.first.cleanUp() }, { it.second }, add) + ) // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available @@ -349,7 +328,7 @@ public class DSL1NumberedPolynomialBuilder( * coefficients is zero at any moment the monomial won't be removed but will be left as it is. */ public infix fun C.with(signature: List) { - coefficients[signature] = if (signature in coefficients) add(coefficients[signature]!!, this@with) else this@with + coefficients.putOrChange(signature, this@with, add) } /** * Declares monomial with [this] coefficient and signature constructed by [block]. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt index 9d88cd648..9f29cf31a 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt @@ -58,7 +58,7 @@ public fun NumberedPolynomial.substitute(args: Map): Number val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * substitution.pow(deg.toInt()) } - this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) @@ -76,7 +76,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Map val deg = degs.getOrElse(variable) { 0u } if (deg == 0u) product else product * power(substitution, deg) } - this[newDegs] = if (newDegs !in this) newC else this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) @@ -158,8 +158,7 @@ public fun NumberedPolynomial.substitute(args: Buffer): Numbered val deg = degs[variable] if (deg == 0u) product else product * args[variable].pow(deg.toInt()) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) @@ -183,8 +182,7 @@ public fun NumberedPolynomial.substitute(ring: Ring, args: Buffer): val deg = degs[variable] if (deg == 0u) product else product * power(args[variable], deg) } - if (newDegs !in this) this[newDegs] = newC - else this[newDegs] = this[newDegs]!! + newC + putOrChange(newDegs, newC) { it -> it + newC } } } ) diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index f9a5a041b..1815749ce 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -23,8 +23,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomialDSL1 { - 5 { 1 pow 2u; 3 pow 3u } - (-6) { 2 pow 1u } + 5 { 0 pow 2u; 2 pow 3u } + (-6) { 1 pow 1u } } }, "test 1" @@ -47,8 +47,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomialDSL1 { - 5 { 1 pow 1u; 1 pow 1u } - (-6) { 1 pow 2u } + 5 { 0 pow 1u; 0 pow 1u } + (-6) { 0 pow 2u } } }, "test 3" @@ -59,8 +59,8 @@ class NumberedConstructorsTest { ), Int.algebra.numberedPolynomialSpace { NumberedPolynomialDSL1 { - 5 { 1 pow 1u; 1 pow 1u } - (-6) { 1 pow 2u; 3 pow 0u } + 5 { 0 pow 1u; 0 pow 1u } + (-6) { 0 pow 2u; 2 pow 0u } } }, "test 3" From 3eef778f6036baa375d40be4f71f697ca707c5ea Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 16 Jul 2022 16:27:11 +0300 Subject: [PATCH 135/174] Add mandatory MutableBufferFactory to Algebra #477 --- CHANGELOG.md | 1 + .../kscience/kmath/benchmarks/DotBenchmark.kt | 3 +- .../kmath/benchmarks/NDFieldBenchmark.kt | 10 +--- .../kmath/benchmarks/ViktorBenchmark.kt | 21 +++---- .../kmath/benchmarks/ViktorLogBenchmark.kt | 7 +-- .../kscience/kmath/operations/complexDemo.kt | 5 +- .../kscience/kmath/structures/NDField.kt | 21 ++----- .../space/kscience/kmath/complex/Complex.kt | 8 +-- .../kscience/kmath/complex/ComplexFieldND.kt | 5 -- .../kscience/kmath/expressions/DSAlgebra.kt | 42 +++++++------- .../kmath/linear/BufferedLinearSpace.kt | 7 +-- .../kscience/kmath/linear/LinearSpace.kt | 16 +----- .../kscience/kmath/nd/BufferAlgebraND.kt | 10 ++-- .../space/kscience/kmath/nd/StructureND.kt | 4 +- .../kscience/kmath/operations/Algebra.kt | 13 +++-- .../space/kscience/kmath/operations/BigInt.kt | 13 +---- .../kmath/operations/BufferAlgebra.kt | 47 +++++++-------- .../kmath/operations/DoubleBufferOps.kt | 4 +- .../kmath/operations/bufferOperation.kt | 4 +- .../kscience/kmath/operations/numbers.kt | 33 +++++------ .../space/kscience/kmath/structures/Buffer.kt | 18 +++++- .../kscience/kmath/structures/ByteBuffer.kt | 57 +++++++++++++++++++ .../kscience/kmath/expressions/DSTest.kt | 2 +- .../histogram/UniformHistogramGroupND.kt | 14 ++--- .../space/kscience/kmath/stat/Sampler.kt | 2 +- 25 files changed, 187 insertions(+), 180 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index ec993fb36..4852f474a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Added - Autodiff for generic algebra elements in core! +- Algebra now has an obligatory `bufferFactory` (#477). ### Changed - Kotlin 1.7 diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 7d5ae310b..7ceecb5ab 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -16,7 +16,6 @@ import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.tensorflow.produceWithTF import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra @@ -84,7 +83,7 @@ internal class DotBenchmark { } @Benchmark - fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) { + fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { blackhole.consume(matrix1 dot matrix2) } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index e3b3dde05..89673acd4 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -20,7 +20,6 @@ import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.one import space.kscience.kmath.nd4j.nd4j import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.one import space.kscience.kmath.tensors.core.tensorAlgebra @@ -28,12 +27,6 @@ import space.kscience.kmath.viktor.viktorAlgebra @State(Scope.Benchmark) internal class NDFieldBenchmark { - @Benchmark - fun autoFieldAdd(blackhole: Blackhole) = with(autoField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } @Benchmark fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { @@ -95,9 +88,8 @@ internal class NDFieldBenchmark { private const val dim = 1000 private const val n = 100 private val shape = intArrayOf(dim, dim) - private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) private val specializedField = DoubleField.ndAlgebra - private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) + private val genericField = BufferedFieldOpsND(DoubleField) private val nd4jField = DoubleField.nd4j private val multikField = DoubleField.multikAlgebra private val viktorField = DoubleField.viktorAlgebra diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index de301678c..0e92a703e 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -10,25 +10,19 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.ndAlgebra +import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.viktor.ViktorFieldND @State(Scope.Benchmark) internal class ViktorBenchmark { - @Benchmark - fun automaticFieldAddition(blackhole: Blackhole) { - with(autoField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - } @Benchmark - fun realFieldAddition(blackhole: Blackhole) { - with(realField) { + fun doubleFieldAddition(blackhole: Blackhole) { + with(doubleField) { var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) @@ -58,8 +52,7 @@ internal class ViktorBenchmark { private val shape = Shape(dim, dim) // automatically build context most suited for given type. - private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) - private val realField = DoubleField.ndAlgebra + private val doubleField = DoubleField.ndAlgebra private val viktorField = ViktorFieldND(dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index dfdd89d74..7bb0b876e 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -10,19 +10,17 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.viktor.ViktorFieldND @State(Scope.Benchmark) internal class ViktorLogBenchmark { @Benchmark fun realFieldLog(blackhole: Blackhole) { - with(realField) { + with(doubleField) { val fortyTwo = structureND(shape) { 42.0 } var res = one(shape) repeat(n) { res = ln(fortyTwo) } @@ -54,8 +52,7 @@ internal class ViktorLogBenchmark { private val shape = Shape(dim, dim) // automatically build context most suited for given type. - private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) - private val realField = DoubleField.ndAlgebra + private val doubleField = DoubleField.ndAlgebra private val viktorField = ViktorFieldND(dim, dim) } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt index 2e1801cc2..285b8d000 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.operations import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.algebra -import space.kscience.kmath.complex.bufferAlgebra import space.kscience.kmath.complex.ndAlgebra import space.kscience.kmath.nd.BufferND import space.kscience.kmath.nd.StructureND @@ -18,7 +17,7 @@ fun main() = Complex.algebra { println(complex * 8 - 5 * i) //flat buffer - val buffer = with(bufferAlgebra){ + val buffer = with(bufferAlgebra) { buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) } } println(buffer) @@ -30,7 +29,7 @@ fun main() = Complex.algebra { println(element) // 1d element operation - val result: StructureND = ndAlgebra{ + val result: StructureND = ndAlgebra { val a = structureND(8) { (it) -> i * it - it.toDouble() } val b = 3 val c = Complex(1.0, 1.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index b680e267d..d6ff1dceb 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -32,12 +32,10 @@ fun main() { val shape = Shape(dim, dim) - // automatically build context most suited for given type. - val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) // specialized nd-field for Double. It works as generic Double field as well. - val realField = DoubleField.ndAlgebra - //A generic boxing field. It should be used for objects, not primitives. - val boxingField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) + val doubleField = DoubleField.ndAlgebra + //A generic field. It should be used for objects, not primitives. + val genericField = BufferedFieldOpsND(DoubleField) // Nd4j specialized field. val nd4jField = DoubleField.nd4j //viktor field @@ -46,14 +44,14 @@ fun main() { val parallelField = DoubleField.ndStreaming(dim, dim) measureAndPrint("Boxing addition") { - boxingField { + genericField { var res: StructureND = one(shape) repeat(n) { res += 1.0 } } } measureAndPrint("Specialized addition") { - realField { + doubleField { var res: StructureND = one(shape) repeat(n) { res += 1.0 } } @@ -80,15 +78,8 @@ fun main() { } } - measureAndPrint("Automatic field addition") { - autoField { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - } - } - measureAndPrint("Lazy addition") { - val res = realField.one(shape).mapAsync(GlobalScope) { + val res = doubleField.one(shape).mapAsync(GlobalScope) { var c = 0.0 repeat(n) { c += 1.0 diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt index 77fe782a9..f56fb0f6e 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt @@ -10,10 +10,7 @@ import space.kscience.kmath.memory.MemorySpec import space.kscience.kmath.memory.MemoryWriter import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MemoryBuffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableMemoryBuffer +import space.kscience.kmath.structures.* import kotlin.math.* /** @@ -54,6 +51,9 @@ public object ComplexField : Norm, NumbersAddOps, ScaleOperations { + override val bufferFactory: MutableBufferFactory = MutableBufferFactory { size, init -> + MutableMemoryBuffer.create(Complex, size, init) + } override val zero: Complex = 0.0.toComplex() override val one: Complex = 1.0.toComplex() diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt index 46d4b7c5c..65943f421 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt @@ -56,11 +56,6 @@ public sealed class ComplexFieldOpsND : BufferedFieldOpsND - get() = bufferAlgebra(Buffer.Companion::complex) - - @OptIn(UnstableKMathAPI::class) public class ComplexFieldND(override val shape: Shape) : ComplexFieldOpsND(), FieldND, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index 59e6f4f6f..c55e41bb2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -78,9 +78,9 @@ public val > DS.value: T get() = data[0] @UnstableKMathAPI public abstract class DSAlgebra>( public val algebra: A, - public val bufferFactory: MutableBufferFactory, public val order: Int, bindings: Map, + public val valueBufferFactory: MutableBufferFactory = algebra.bufferFactory, ) : ExpressionAlgebra>, SymbolIndexer { /** @@ -90,6 +90,7 @@ public abstract class DSAlgebra>( */ @PublishedApi internal val compiler: DSCompiler by lazy { + val numberOfVariables = bindings.size // get the cached compilers val cache: Array?>>? = null @@ -115,7 +116,7 @@ public abstract class DSAlgebra>( newCache[p][o] = DSCompiler( algebra, - bufferFactory, + valueBufferFactory, p, o, valueCompiler, @@ -139,16 +140,13 @@ public abstract class DSAlgebra>( } override val symbols: List = bindings.map { it.key } - public val numberOfVariables: Int get() = symbols.size - - private fun bufferForVariable(index: Int, value: T): Buffer { - val buffer = bufferFactory(compiler.size) { algebra.zero } + val buffer = valueBufferFactory(compiler.size) { algebra.zero } buffer[0] = value if (compiler.order > 0) { // the derivative of the variable with respect to itself is 1. - val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(numberOfVariables).apply { + val indexOfDerivative = compiler.getPartialDerivativeIndex(*IntArray(symbols.size).apply { set(index, 1) }) @@ -209,7 +207,7 @@ public abstract class DSAlgebra>( } public override fun const(value: T): DS { - val buffer = bufferFactory(compiler.size) { algebra.zero } + val buffer = valueBufferFactory(compiler.size) { algebra.zero } buffer[0] = value return DS(buffer) @@ -245,10 +243,10 @@ public abstract class DSAlgebra>( @UnstableKMathAPI public open class DSRing( algebra: A, - bufferFactory: MutableBufferFactory, order: Int, bindings: Map, -) : DSAlgebra(algebra, bufferFactory, order, bindings), + valueBufferFactory: MutableBufferFactory, +) : DSAlgebra(algebra, order, bindings, valueBufferFactory), Ring>, ScaleOperations>, NumericAlgebra>, NumbersAddOps> where A : Ring, A : NumericAlgebra, A : ScaleOperations { @@ -263,14 +261,14 @@ public open class DSRing( */ protected inline fun DS.transformDataBuffer(block: A.(MutableBuffer) -> Unit): DS { require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData = bufferFactory(compiler.size) { data[it] } + val newData = valueBufferFactory(compiler.size) { data[it] } algebra.block(newData) return DS(newData) } protected fun DS.mapData(block: A.(T) -> T): DS { require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData: Buffer = data.map(bufferFactory) { + val newData: Buffer = data.map(valueBufferFactory) { algebra.block(it) } return DS(newData) @@ -278,7 +276,7 @@ public open class DSRing( protected fun DS.mapDataIndexed(block: (Int, T) -> T): DS { require(derivativeAlgebra == this@DSRing) { "All derivative operations should be done in the same algebra" } - val newData: Buffer = data.mapIndexed(bufferFactory, block) + val newData: Buffer = data.mapIndexed(valueBufferFactory, block) return DS(newData) } @@ -327,19 +325,19 @@ public open class DSRing( @UnstableKMathAPI public class DerivativeStructureRingExpression( public val algebra: A, - public val bufferFactory: MutableBufferFactory, + public val elementBufferFactory: MutableBufferFactory = algebra.bufferFactory, public val function: DSRing.() -> DS, ) : DifferentiableExpression where A : Ring, A : ScaleOperations, A : NumericAlgebra { override operator fun invoke(arguments: Map): T = - DSRing(algebra, bufferFactory, 0, arguments).function().value + DSRing(algebra, 0, arguments, elementBufferFactory).function().value override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> with( DSRing( algebra, - bufferFactory, symbols.size, - arguments + arguments, + elementBufferFactory ) ) { function().derivative(symbols) } } @@ -354,10 +352,10 @@ public class DerivativeStructureRingExpression( @UnstableKMathAPI public class DSField>( algebra: A, - bufferFactory: MutableBufferFactory, order: Int, bindings: Map, -) : DSRing(algebra, bufferFactory, order, bindings), ExtendedField> { + valueBufferFactory: MutableBufferFactory, +) : DSRing(algebra, order, bindings, valueBufferFactory), ExtendedField> { override fun number(value: Number): DS = const(algebra.number(value)) override fun divide(left: DS, right: DS): DS = left.transformDataBuffer { result -> @@ -441,18 +439,18 @@ public class DSField>( @UnstableKMathAPI public class DSFieldExpression>( public val algebra: A, - public val bufferFactory: MutableBufferFactory, + private val valueBufferFactory: MutableBufferFactory = algebra.bufferFactory, public val function: DSField.() -> DS, ) : DifferentiableExpression { override operator fun invoke(arguments: Map): T = - DSField(algebra, bufferFactory, 0, arguments).function().value + DSField(algebra, 0, arguments, valueBufferFactory).function().value override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> DSField( algebra, - bufferFactory, symbols.size, arguments, + valueBufferFactory, ).run { function().derivative(symbols) } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt index 36cbd9064..8f7569699 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt @@ -11,13 +11,12 @@ import space.kscience.kmath.nd.as2D import space.kscience.kmath.nd.asND import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.indices public class BufferedLinearSpace>( - private val bufferAlgebra: BufferAlgebra + private val bufferAlgebra: BufferAlgebra, ) : LinearSpace { override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra @@ -91,5 +90,5 @@ public class BufferedLinearSpace>( } -public fun > A.linearSpace(bufferFactory: BufferFactory): BufferedLinearSpace = - BufferedLinearSpace(BufferRingOps(this, bufferFactory)) +public val > A.linearSpace: BufferedLinearSpace + get() = BufferedLinearSpace(BufferRingOps(this)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index 10438dd02..d437070c9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -11,12 +11,9 @@ import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.nd.as1D import space.kscience.kmath.operations.BufferRingOps -import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer import kotlin.reflect.KClass /** @@ -187,18 +184,9 @@ public interface LinearSpace> { * A structured matrix with custom buffer */ public fun > buffered( - algebra: A, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), - ): LinearSpace = BufferedLinearSpace(BufferRingOps(algebra, bufferFactory)) + algebra: A + ): LinearSpace = BufferedLinearSpace(BufferRingOps(algebra)) - @Deprecated("use DoubleField.linearSpace") - public val double: LinearSpace = buffered(DoubleField, ::DoubleBuffer) - - /** - * Automatic buffered matrix, unboxed if it is possible - */ - public inline fun > auto(ring: A): LinearSpace = - buffered(ring, Buffer.Companion::auto) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt index 68e8ebe90..8c5eef3d0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt @@ -10,7 +10,6 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.BufferFactory public interface BufferAlgebraND> : AlgebraND { public val indexerBuilder: (IntArray) -> ShapeIndexer @@ -60,7 +59,7 @@ public inline fun > BufferAlgebraND.mapInline( return BufferND( indexes, bufferAlgebra.run { - bufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) } + elementBufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) } } ) } @@ -74,7 +73,7 @@ internal inline fun > BufferAlgebraND.mapIndexedInline( return BufferND( indexes, bufferAlgebra.run { - bufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) } + elementBufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) } } ) } @@ -91,7 +90,7 @@ internal inline fun > BufferAlgebraND.zipInline( return BufferND( indexes, bufferAlgebra.run { - bufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) } + elementBufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) } } ) } @@ -116,9 +115,8 @@ public open class BufferedFieldOpsND>( public constructor( elementAlgebra: A, - bufferFactory: BufferFactory, indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, - ) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) + ) : this(BufferFieldOps(elementAlgebra), indexerBuilder) @OptIn(PerformancePitfall::class) override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 6e54e1b9d..e14b8bf9d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -120,7 +120,7 @@ public interface StructureND : Featured, WithShape { */ public fun buffered( strides: Strides, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), + bufferFactory: BufferFactory = BufferFactory.boxing(), initializer: (IntArray) -> T, ): BufferND = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) @@ -140,7 +140,7 @@ public interface StructureND : Featured, WithShape { public fun buffered( shape: IntArray, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), + bufferFactory: BufferFactory = BufferFactory.boxing(), initializer: (IntArray) -> T, ): BufferND = buffered(DefaultStrides(shape), bufferFactory, initializer) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index 45ba32c13..a93b4365e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -8,12 +8,7 @@ package space.kscience.kmath.operations import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring.Companion.optimizedPower - -/** - * Stub for DSL the [Algebra] is. - */ -@DslMarker -public annotation class KMathContext +import space.kscience.kmath.structures.MutableBufferFactory /** * Represents an algebraic structure. @@ -21,6 +16,12 @@ public annotation class KMathContext * @param T the type of element of this structure. */ public interface Algebra { + + /** + * Provide a factory for buffers, associated with this [Algebra] + */ + public val bufferFactory: MutableBufferFactory get() = MutableBufferFactory.boxing() + /** * Wraps a raw string to [T] object. This method is designed for three purposes: * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 99268348b..9b6911f73 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -10,7 +10,6 @@ import space.kscience.kmath.nd.BufferedRingOpsND import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer import kotlin.math.log2 import kotlin.math.max import kotlin.math.min @@ -528,19 +527,11 @@ public fun String.parseBigInteger(): BigInt? { public val BigInt.algebra: BigIntField get() = BigIntField -@Deprecated("Use BigInt::buffer") -public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = - boxing(size, initializer) - public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer = Buffer.boxing(size, initializer) -@Deprecated("Use BigInt::mutableBuffer") -public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = - boxing(size, initializer) - -public inline fun BigInt.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer = +public inline fun BigInt.Companion.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer = Buffer.boxing(size, initializer) public val BigIntField.nd: BufferedRingOpsND - get() = BufferedRingOpsND(BufferRingOps(BigIntField, BigInt::buffer)) + get() = BufferedRingOpsND(BufferRingOps(BigIntField)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index 51fff8b69..a256fe7d1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -7,8 +7,6 @@ package space.kscience.kmath.operations import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.ShortBuffer public interface WithSize { public val size: Int @@ -19,11 +17,11 @@ public interface WithSize { */ public interface BufferAlgebra> : Algebra> { public val elementAlgebra: A - public val bufferFactory: BufferFactory + public val elementBufferFactory: BufferFactory get() = elementAlgebra.bufferFactory public fun buffer(size: Int, vararg elements: T): Buffer { require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return bufferFactory(size) { elements[it] } + return elementBufferFactory(size) { elements[it] } } //TODO move to multi-receiver inline extension @@ -36,13 +34,13 @@ public interface BufferAlgebra> : Algebra> { override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { val operationFunction = elementAlgebra.unaryOperationFunction(operation) - return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } + return { arg -> elementBufferFactory(arg.size) { operationFunction(arg[it]) } } } override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { val operationFunction = elementAlgebra.binaryOperationFunction(operation) return { left, right -> - bufferFactory(left.size) { operationFunction(left[it], right[it]) } + elementBufferFactory(left.size) { operationFunction(left[it], right[it]) } } } } @@ -53,7 +51,7 @@ public interface BufferAlgebra> : Algebra> { private inline fun > BufferAlgebra.mapInline( buffer: Buffer, crossinline block: A.(T) -> T, -): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) } +): Buffer = elementBufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) } /** * Inline map @@ -61,7 +59,7 @@ private inline fun > BufferAlgebra.mapInline( private inline fun > BufferAlgebra.mapIndexedInline( buffer: Buffer, crossinline block: A.(index: Int, arg: T) -> T, -): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) } +): Buffer = elementBufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) } /** * Inline zip @@ -72,15 +70,15 @@ private inline fun > BufferAlgebra.zipInline( crossinline block: A.(l: T, r: T) -> T, ): Buffer { require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" } - return bufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } + return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } } public fun BufferAlgebra.buffer(size: Int, initializer: (Int) -> T): Buffer { - return bufferFactory(size, initializer) + return elementBufferFactory(size, initializer) } public fun A.buffer(initializer: (Int) -> T): Buffer where A : BufferAlgebra, A : WithSize { - return bufferFactory(size, initializer) + return elementBufferFactory(size, initializer) } public fun > BufferAlgebra.sin(arg: Buffer): Buffer = @@ -131,7 +129,6 @@ public fun > BufferAlgebra.pow(arg: Buffer, p public open class BufferRingOps>( override val elementAlgebra: A, - override val bufferFactory: BufferFactory, ) : BufferAlgebra, RingOps> { override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } @@ -146,15 +143,13 @@ public open class BufferRingOps>( } public val ShortRing.bufferAlgebra: BufferRingOps - get() = BufferRingOps(ShortRing, ::ShortBuffer) + get() = BufferRingOps(ShortRing) public open class BufferFieldOps>( elementAlgebra: A, - bufferFactory: BufferFactory, -) : BufferRingOps(elementAlgebra, bufferFactory), BufferAlgebra, FieldOps>, - ScaleOperations> { +) : BufferRingOps(elementAlgebra), BufferAlgebra, FieldOps>, ScaleOperations> { -// override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } + // override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } // override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } override fun divide(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l / r } @@ -167,30 +162,26 @@ public open class BufferFieldOps>( public class BufferField>( elementAlgebra: A, - bufferFactory: BufferFactory, override val size: Int, -) : BufferFieldOps(elementAlgebra, bufferFactory), Field>, WithSize { +) : BufferFieldOps(elementAlgebra), Field>, WithSize { - override val zero: Buffer = bufferFactory(size) { elementAlgebra.zero } - override val one: Buffer = bufferFactory(size) { elementAlgebra.one } + override val zero: Buffer = elementAlgebra.bufferFactory(size) { elementAlgebra.zero } + override val one: Buffer = elementAlgebra.bufferFactory(size) { elementAlgebra.one } } /** * Generate full buffer field from given buffer operations */ public fun > BufferFieldOps.withSize(size: Int): BufferField = - BufferField(elementAlgebra, bufferFactory, size) + BufferField(elementAlgebra, size) //Double buffer specialization public fun BufferField.buffer(vararg elements: Number): Buffer { require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return bufferFactory(size) { elements[it].toDouble() } + return elementBufferFactory(size) { elements[it].toDouble() } } -public fun > A.bufferAlgebra(bufferFactory: BufferFactory): BufferFieldOps = - BufferFieldOps(this, bufferFactory) - -public val DoubleField.bufferAlgebra: BufferFieldOps - get() = BufferFieldOps(DoubleField, ::DoubleBuffer) +public val > A.bufferAlgebra: BufferFieldOps + get() = BufferFieldOps(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt index 083892105..669c0a390 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.operations import space.kscience.kmath.linear.Point import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.MutableBufferFactory import space.kscience.kmath.structures.asBuffer import kotlin.math.* @@ -19,7 +19,7 @@ public abstract class DoubleBufferOps : BufferAlgebra, Exte Norm, Double> { override val elementAlgebra: DoubleField get() = DoubleField - override val bufferFactory: BufferFactory get() = BufferFactory(::DoubleBuffer) + override val elementBufferFactory: MutableBufferFactory get() = elementAlgebra.bufferFactory override fun Buffer.map(block: DoubleField.(Double) -> Double): DoubleBuffer = mapInline { DoubleField.block(it) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 652472fcf..0beda11a5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -88,7 +88,7 @@ public inline fun Buffer.mapIndexed( */ public inline fun Buffer.mapIndexed( crossinline block: (index: Int, value: T) -> R, -): Buffer = BufferFactory(Buffer.Companion::auto).invoke(size) { block(it, get(it)) } +): Buffer = Buffer.auto(size) { block(it, get(it)) } /** * Fold given buffer according to [operation] @@ -105,7 +105,7 @@ public inline fun Buffer.fold(initial: R, operation: (acc: R, T) -> R) @UnstableKMathAPI public inline fun Buffer.zip( other: Buffer, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::auto), + bufferFactory: BufferFactory = BufferFactory.auto(), crossinline transform: (T1, T2) -> R, ): Buffer { require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 07a137415..c108aa729 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.operations +import space.kscience.kmath.structures.* import kotlin.math.pow as kpow /** @@ -65,6 +66,8 @@ public interface ExtendedField : ExtendedFieldOps, Field, PowerOperatio */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object DoubleField : ExtendedField, Norm, ScaleOperations { + override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::DoubleBuffer) + override inline val zero: Double get() = 0.0 override inline val one: Double get() = 1.0 @@ -123,6 +126,8 @@ public val Double.Companion.algebra: DoubleField get() = DoubleField */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object FloatField : ExtendedField, Norm { + override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::FloatBuffer) + override inline val zero: Float get() = 0.0f override inline val one: Float get() = 1.0f @@ -177,11 +182,10 @@ public val Float.Companion.algebra: FloatField get() = FloatField */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object IntRing : Ring, Norm, NumericAlgebra { - override inline val zero: Int - get() = 0 + override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::IntBuffer) - override inline val one: Int - get() = 1 + override inline val zero: Int get() = 0 + override inline val one: Int get() = 1 override fun number(value: Number): Int = value.toInt() override inline fun add(left: Int, right: Int): Int = left + right @@ -201,11 +205,10 @@ public val Int.Companion.algebra: IntRing get() = IntRing */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ShortRing : Ring, Norm, NumericAlgebra { - override inline val zero: Short - get() = 0 + override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::ShortBuffer) - override inline val one: Short - get() = 1 + override inline val zero: Short get() = 0 + override inline val one: Short get() = 1 override fun number(value: Number): Short = value.toShort() override inline fun add(left: Short, right: Short): Short = (left + right).toShort() @@ -225,11 +228,10 @@ public val Short.Companion.algebra: ShortRing get() = ShortRing */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ByteRing : Ring, Norm, NumericAlgebra { - override inline val zero: Byte - get() = 0 + override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::ByteBuffer) - override inline val one: Byte - get() = 1 + override inline val zero: Byte get() = 0 + override inline val one: Byte get() = 1 override fun number(value: Number): Byte = value.toByte() override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte() @@ -249,11 +251,10 @@ public val Byte.Companion.algebra: ByteRing get() = ByteRing */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object LongRing : Ring, Norm, NumericAlgebra { - override inline val zero: Long - get() = 0L + override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::LongBuffer) - override inline val one: Long - get() = 1L + override inline val zero: Long get() = 0L + override inline val one: Long get() = 1L override fun number(value: Number): Long = value.toLong() override inline fun add(left: Long, right: Long): Long = left + right diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 1c79c257a..5757848fe 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -16,6 +16,14 @@ import kotlin.reflect.KClass */ public fun interface BufferFactory { public operator fun invoke(size: Int, builder: (Int) -> T): Buffer + + public companion object{ + public inline fun auto(): BufferFactory = + BufferFactory(Buffer.Companion::auto) + + public fun boxing(): BufferFactory = + BufferFactory(Buffer.Companion::boxing) + } } /** @@ -23,8 +31,16 @@ public fun interface BufferFactory { * * @param T the type of buffer. */ -public fun interface MutableBufferFactory: BufferFactory{ +public fun interface MutableBufferFactory : BufferFactory { override fun invoke(size: Int, builder: (Int) -> T): MutableBuffer + + public companion object { + public inline fun auto(): MutableBufferFactory = + MutableBufferFactory(MutableBuffer.Companion::auto) + + public fun boxing(): MutableBufferFactory = + MutableBufferFactory(MutableBuffer.Companion::boxing) + } } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt new file mode 100644 index 000000000..e7bf2b47c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt @@ -0,0 +1,57 @@ +/* + * 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.structures + +import kotlin.jvm.JvmInline + +/** + * Specialized [MutableBuffer] implementation over [ByteArray]. + * + * @property array the underlying array. + */ +@JvmInline +public value class ByteBuffer(public val array: ByteArray) : MutableBuffer { + override val size: Int get() = array.size + + override operator fun get(index: Int): Byte = array[index] + + override operator fun set(index: Int, value: Byte) { + array[index] = value + } + + override operator fun iterator(): ByteIterator = array.iterator() + override fun copy(): MutableBuffer = ByteBuffer(array.copyOf()) +} + +/** + * Creates a new [ByteBuffer] with the specified [size], where each element is calculated by calling the specified + * [init] function. + * + * The function [init] is called for each array element sequentially starting from the first one. + * It should return the value for a buffer element given its index. + */ +public inline fun ByteBuffer(size: Int, init: (Int) -> Byte): ByteBuffer = ByteBuffer(ByteArray(size) { init(it) }) + +/** + * Returns a new [ByteBuffer] of given elements. + */ +public fun ByteBuffer(vararg bytes: Byte): ByteBuffer = ByteBuffer(bytes) + +/** + * Returns a new [ByteArray] containing all the elements of this [Buffer]. + */ +public fun Buffer.toByteArray(): ByteArray = when (this) { + is ByteBuffer -> array.copyOf() + else -> ByteArray(size, ::get) +} + +/** + * Returns [ByteBuffer] over this array. + * + * @receiver the array. + * @return the new buffer. + */ +public fun ByteArray.asBuffer(): ByteBuffer = ByteBuffer(this) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt index 727a918ec..b6581e503 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt @@ -22,7 +22,7 @@ internal inline fun diff( block: DSField.() -> Unit, ) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - DSField(DoubleField, ::DoubleBuffer, order, mapOf(*parameters)).block() + DSField(DoubleField, order, mapOf(*parameters), ::DoubleBuffer).block() } internal class DSTest { diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt index eafd55513..1ead049e6 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt @@ -21,14 +21,14 @@ public typealias HyperSquareBin = DomainBin /** * Multivariate histogram space for hyper-square real-field bins. - * @param bufferFactory is an optional parameter used to optimize buffer production. + * @param valueBufferFactory is an optional parameter used to optimize buffer production. */ public class UniformHistogramGroupND>( override val valueAlgebraND: FieldOpsND, private val lower: Buffer, private val upper: Buffer, private val binNums: IntArray = IntArray(lower.size) { 20 }, - private val bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), + private val valueBufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, ) : HistogramGroupND { init { @@ -94,7 +94,7 @@ public class UniformHistogramGroupND>( } } hBuilder.apply(builder) - val values: BufferND = ndCounter.mapToBuffer(bufferFactory) { it.value } + val values: BufferND = ndCounter.mapToBuffer(valueBufferFactory) { it.value } return HistogramND(this, values) } @@ -114,12 +114,12 @@ public class UniformHistogramGroupND>( public fun > Histogram.Companion.uniformNDFromRanges( valueAlgebraND: FieldOpsND, vararg ranges: ClosedFloatingPointRange, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), + bufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, ): UniformHistogramGroupND = UniformHistogramGroupND( valueAlgebraND, ranges.map(ClosedFloatingPointRange::start).asBuffer(), ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer(), - bufferFactory = bufferFactory + valueBufferFactory = bufferFactory ) public fun Histogram.Companion.uniformDoubleNDFromRanges( @@ -140,7 +140,7 @@ public fun Histogram.Companion.uniformDoubleNDFromRanges( public fun > Histogram.Companion.uniformNDFromRanges( valueAlgebraND: FieldOpsND, vararg ranges: Pair, Int>, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), + bufferFactory: BufferFactory = valueAlgebraND.elementAlgebra.bufferFactory, ): UniformHistogramGroupND = UniformHistogramGroupND( valueAlgebraND, ListBuffer( @@ -154,7 +154,7 @@ public fun > Histogram.Companion.uniformNDFromRanges( .map(ClosedFloatingPointRange::endInclusive) ), ranges.map(Pair, Int>::second).toIntArray(), - bufferFactory = bufferFactory + valueBufferFactory = bufferFactory ) public fun Histogram.Companion.uniformDoubleNDFromRanges( diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 890318e31..1c88922ac 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -35,7 +35,7 @@ public fun interface Sampler { public fun Sampler.sampleBuffer( generator: RandomGenerator, size: Int, - bufferFactory: BufferFactory = BufferFactory(Buffer.Companion::boxing), + bufferFactory: BufferFactory = BufferFactory.boxing(), ): Chain> { require(size > 1) //creating temporary storage once From a1a2c41846b5a720cb05ec4bee9c5136c74b55c9 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 17:13:05 +0300 Subject: [PATCH 136/174] Add a bit more utilities for maps and refactor polynomials' code. --- .../LabeledPolynomial.kt | 100 ++++++++---------- .../NumberedPolynomial.kt | 100 +++++++----------- .../collectionUtils.kt | 39 ++++++- 3 files changed, 117 insertions(+), 122 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index b07674a1e..7df51930e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -87,7 +87,7 @@ public class LabeledPolynomialSpace>( ) else LabeledPolynomialAsIs( mapOf(this@plus to 1U) to constantOne, - emptyMap() to constantOne * other, + emptyMap() to other.asConstant(), ) /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. @@ -98,7 +98,7 @@ public class LabeledPolynomialSpace>( ) else LabeledPolynomialAsIs( mapOf(this@minus to 1U) to constantOne, - emptyMap() to constantOne * -other, + emptyMap() to (-other).asConstant(), ) /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. @@ -106,7 +106,7 @@ public class LabeledPolynomialSpace>( public override operator fun Symbol.times(other: Int): LabeledPolynomial = if (other == 0) zero else LabeledPolynomialAsIs( - mapOf(this to 1U) to constantOne * other, + mapOf(this to 1U) to other.asConstant(), ) /** @@ -118,7 +118,7 @@ public class LabeledPolynomialSpace>( ) else LabeledPolynomialAsIs( mapOf(other to 1U) to constantOne, - emptyMap() to constantOne * this@plus, + emptyMap() to this@plus.asConstant(), ) /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. @@ -137,7 +137,7 @@ public class LabeledPolynomialSpace>( public override operator fun Int.times(other: Symbol): LabeledPolynomial = if (this == 0) zero else LabeledPolynomialAsIs( - mapOf(other to 1U) to constantOne * this@times, + mapOf(other to 1U) to this@times.asConstant(), ) /** @@ -146,11 +146,11 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ public override operator fun LabeledPolynomial.plus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) other.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } + when { + other == 0 -> this + coefficients.isEmpty() -> other.asPolynomial() + else -> LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), other.asConstant()) { it -> it + other } ) } /** @@ -159,11 +159,11 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ public override operator fun LabeledPolynomial.minus(other: Int): LabeledPolynomial = - if (other == 0) this - else with(coefficients) { - if (isEmpty()) (-other).asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } + when { + other == 0 -> this + coefficients.isEmpty() -> other.asPolynomial() + else -> LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), (-other).asConstant()) { it -> it - other } ) } /** @@ -186,11 +186,11 @@ public class LabeledPolynomialSpace>( * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ public override operator fun Int.plus(other: LabeledPolynomial): LabeledPolynomial = - if (this == 0) other - else with(other.coefficients) { - if (isEmpty()) this@plus.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } + when { + this == 0 -> other + other.coefficients.isEmpty() -> this@plus.asPolynomial() + else -> LabeledPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyMap(), this@plus.asConstant()) { it -> this@plus + it } ) } /** @@ -275,12 +275,10 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun C.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@plus.asLabeledPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } - ) - } + if (other.coefficients.isEmpty()) this@plus.asLabeledPolynomial() + else LabeledPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyMap(), this@plus) { it -> this@plus + it } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ @@ -304,22 +302,18 @@ public class LabeledPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun LabeledPolynomial.plus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asLabeledPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), other) { it -> it + other } - ) - } + if (coefficients.isEmpty()) other.asLabeledPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), other) { it -> it + other } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun LabeledPolynomial.minus(other: C): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asLabeledPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(emptyMap(), -other) { it -> it - other } - ) - } + if (coefficients.isEmpty()) other.asLabeledPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(emptyMap(), -other) { it -> it - other } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ @@ -382,12 +376,10 @@ public class LabeledPolynomialSpace>( * Returns sum of the variable represented as a monic monomial and the polynomial. */ public override operator fun Symbol.plus(other: LabeledPolynomial): LabeledPolynomial = - with(other.coefficients) { - if (isEmpty()) this@plus.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } - ) - } + if (other.coefficients.isEmpty()) this@plus.asPolynomial() + else LabeledPolynomialAsIs( + other.coefficients.withPutOrChanged(mapOf(this@plus to 1U), constantOne) { it -> constantOne + it } + ) /** * Returns difference between the variable represented as a monic monomial and the polynomial. */ @@ -412,22 +404,18 @@ public class LabeledPolynomialSpace>( * Returns sum of the polynomial and the variable represented as a monic monomial. */ public override operator fun LabeledPolynomial.plus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(mapOf(other to 1U), constantOne) { it -> it + constantOne } + ) /** * Returns difference between the polynomial and the variable represented as a monic monomial. */ public override operator fun LabeledPolynomial.minus(other: Symbol): LabeledPolynomial = - with(coefficients) { - if (isEmpty()) other.asPolynomial() - else LabeledPolynomialAsIs( - withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else LabeledPolynomialAsIs( + coefficients.withPutOrChanged(mapOf(other to 1U), -constantOne) { it -> it - constantOne } + ) /** * Returns product of the polynomial and the variable represented as a monic monomial. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index 14c03ff7c..037419cfc 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -69,10 +69,9 @@ public class NumberedPolynomialSpace>( */ public override operator fun NumberedPolynomial.plus(other: Int): NumberedPolynomial = if (other == 0) this - else - NumberedPolynomialAsIs( - coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } - ) + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), other.asConstant()) { it -> it + other } + ) /** * Returns difference between the polynomial and the integer represented as a polynomial. * @@ -80,10 +79,9 @@ public class NumberedPolynomialSpace>( */ public override operator fun NumberedPolynomial.minus(other: Int): NumberedPolynomial = if (other == 0) this - else - NumberedPolynomialAsIs( - coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } - ) + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), (-other).asConstant()) { it -> it - other } + ) /** * Returns product of the polynomial and the integer represented as a polynomial. * @@ -105,31 +103,25 @@ public class NumberedPolynomialSpace>( */ public override operator fun Int.plus(other: NumberedPolynomial): NumberedPolynomial = if (this == 0) other - else - NumberedPolynomialAsIs( - other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } - ) + else NumberedPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyList(), this@plus.asConstant()) { it -> this@plus + it } + ) /** * Returns difference between the integer represented as a polynomial and the polynomial. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ public override operator fun Int.minus(other: NumberedPolynomial): NumberedPolynomial = - NumberedPolynomialAsIs( - other.coefficients - .toMutableMap() - .apply { - if (this@minus == 0) { - forEach { (key, value) -> this[key] = -value } - } else { - forEach { (key, value) -> if (key.isNotEmpty()) this[key] = -value } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } + when { + this == 0 -> -other + other.coefficients.isEmpty() -> this.asPolynomial() + else -> NumberedPolynomialAsIs( + buildMap(other.coefficients.size + 1) { + put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), { this@minus.asConstant() }, { it -> this@minus - it})) + other.coefficients.copyMapToBy(this, { _, c -> -c }) { currentC, _ -> currentC } } ) + } /** * Returns product of the integer represented as a polynomial and the polynomial. * @@ -148,29 +140,21 @@ public class NumberedPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun C.plus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@plus)) - else NumberedPolynomialAsIs( - withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } - ) - } + if (other.coefficients.isEmpty()) this@plus.asPolynomial() + else NumberedPolynomialAsIs( + other.coefficients.withPutOrChanged(emptyList(), this@plus) { it -> this@plus + it } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun C.minus(other: NumberedPolynomial): NumberedPolynomial = - with(other.coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to this@minus)) - else NumberedPolynomialAsIs( - toMutableMap() - .apply { - forEach { (degs, c) -> if (degs.isNotEmpty()) this[degs] = -c } - - val degs = emptyList() - - this[degs] = this@minus - getOrElse(degs) { constantZero } - } - ) - } + if (other.coefficients.isEmpty()) this@minus.asPolynomial() + else NumberedPolynomialAsIs( + buildMap(other.coefficients.size) { + put(emptyList(), other.coefficients.computeOnOrElse(emptyList(), this@minus) { it -> this@minus - it }) + other.coefficients.copyMapToBy(this, { _, c -> -c }, { currentC, _ -> currentC }) + } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ @@ -183,22 +167,18 @@ public class NumberedPolynomialSpace>( * Returns sum of the constant represented as a polynomial and the polynomial. */ override operator fun NumberedPolynomial.plus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) - else NumberedPolynomialAsIs( - withPutOrChanged(emptyList(), other) { it -> it + other } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), other) { it -> it + other } + ) /** * Returns difference between the constant represented as a polynomial and the polynomial. */ override operator fun NumberedPolynomial.minus(other: C): NumberedPolynomial = - with(coefficients) { - if (isEmpty()) NumberedPolynomialAsIs(mapOf(emptyList() to other)) - else NumberedPolynomialAsIs( - withPutOrChanged(emptyList(), -other) { it -> it - other } - ) - } + if (coefficients.isEmpty()) other.asPolynomial() + else NumberedPolynomialAsIs( + coefficients.withPutOrChanged(emptyList(), -other) { it -> it - other } + ) /** * Returns product of the constant represented as a polynomial and the polynomial. */ @@ -264,13 +244,7 @@ public class NumberedPolynomialSpace>( /** * Instance of unit polynomial (unit of the polynomial ring). */ - override val one: NumberedPolynomial by lazy { - NumberedPolynomialAsIs( - mapOf( - emptyList() to constantOne // 1 * x_1^0 * x_2^0 * ... - ) - ) - } + override val one: NumberedPolynomial by lazy { NumberedPolynomialAsIs(mapOf(emptyList() to constantOne)) } /** * Maximal index (ID) of variable occurring in the polynomial with positive power. If there is no such variable, diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt index 1d3da4c8b..ee32aa9a7 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt @@ -9,6 +9,40 @@ import kotlin.contracts.InvocationKind.* import kotlin.contracts.contract +// TODO: Docs +internal inline fun Map.computeOn(key: K, compute: (V?) -> R): R { + contract { + callsInPlace(compute, EXACTLY_ONCE) + } + return compute(get(key)) +} + +// TODO: Docs +internal inline fun Map.computeOnOrElse(key: K, defaultResult: () -> R, compute: (value: V) -> R): R { + contract { + callsInPlace(defaultResult, AT_MOST_ONCE) + callsInPlace(compute, AT_MOST_ONCE) + } + @Suppress("UNCHECKED_CAST") + return (if (key !in this) defaultResult() else compute(get(key) as V)) +} + +// TODO: Docs +internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (value: V) -> R): R { + contract { + callsInPlace(compute, AT_MOST_ONCE) + } + return computeOnOrElse(key, { defaultResult }, compute) +} + +// TODO: Docs +internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (key: K, value: V) -> R): R { + contract { + callsInPlace(compute, AT_MOST_ONCE) + } + return computeOnOrElse(key, { defaultResult }, { it -> compute(key, it) }) +} + /** * Applies the [transformation][transform] to the value corresponding to the given [key] or null instead if it's not * present. @@ -21,7 +55,7 @@ internal inline fun MutableMap.applyToKey(key: K, transform: (cu contract { callsInPlace(transform, EXACTLY_ONCE) } - return transform(get(key)).also { this[key] = it } + return computeOn(key, transform).also { this[key] = it } } /** @@ -39,8 +73,7 @@ internal inline fun MutableMap.putOrChange(key: K, valueOnPut: () - callsInPlace(valueOnPut, AT_MOST_ONCE) callsInPlace(transformOnChange, AT_MOST_ONCE) } - @Suppress("UNCHECKED_CAST") - return (if (key !in this) valueOnPut() else transformOnChange(get(key) as V)).also { this[key] = it } + return computeOnOrElse(key, valueOnPut, transformOnChange).also { this[key] = it } } /** From 3a91cb2579862e7ef9d617a46d6c8b44c8e61438 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 18:46:40 +0300 Subject: [PATCH 137/174] Draft another DSL for labeled polynomials. Add variance. --- .../LabeledPolynomial.kt | 2 +- .../ListPolynomial.kt | 4 +- .../NumberedPolynomial.kt | 2 +- .../Polynomial.kt | 2 +- .../RationalFunction.kt | 6 +- .../labeledConstructors.kt | 255 ++++++++++++++++++ 6 files changed, 263 insertions(+), 8 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt index 7df51930e..e2320114b 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt @@ -75,7 +75,7 @@ internal constructor( * @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 LabeledPolynomialSpace>( +public class LabeledPolynomialSpace>( public override val ring: A, ) : MultivariatePolynomialSpace>, PolynomialSpaceOverRing, A> { /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt index 17c42ac8c..d0e58c0d6 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt @@ -60,7 +60,7 @@ public data class ListPolynomial( * @param A type of provided underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public open class ListPolynomialSpace>( +public open class ListPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** @@ -366,7 +366,7 @@ public open class ListPolynomialSpace>( * @param A type of underlying ring of constants. It's [Ring] of [C]. * @param ring underlying ring of constants of type [A]. */ -public class ScalableListPolynomialSpace( +public class ScalableListPolynomialSpace( ring: A, ) : ListPolynomialSpace(ring), ScaleOperations> where A : Ring, A : ScaleOperations { override fun scale(a: ListPolynomial, value: Double): ListPolynomial = diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt index 037419cfc..d2fc5ffa1 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt @@ -59,7 +59,7 @@ internal constructor( * @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 NumberedPolynomialSpace>( +public class NumberedPolynomialSpace>( public override val ring: A, ) : PolynomialSpaceOverRing, A> { /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt index 61ea5a342..66308a7bc 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt @@ -252,7 +252,7 @@ public interface PolynomialSpace> : Ring

{ * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, A: Ring> : PolynomialSpace { +public interface PolynomialSpaceOverRing, out A: Ring> : PolynomialSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt index f664ae9db..da91c8d61 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt @@ -464,7 +464,7 @@ public interface RationalFunctionSpaceOverRing< C, P: Polynomial, R: RationalFunction, - A: Ring + out A: Ring > : RationalFunctionSpace { /** @@ -566,7 +566,7 @@ public interface RationalFunctionSpaceOverPolynomialSpace< C, P: Polynomial, R: RationalFunction, - AP: PolynomialSpace, + out AP: PolynomialSpace, > : RationalFunctionSpace { /** @@ -1341,7 +1341,7 @@ public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpac V, P: Polynomial, R: RationalFunction, - AP: MultivariatePolynomialSpace, + out AP: MultivariatePolynomialSpace, > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt index 43048089e..d74c0e1fb 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt @@ -416,6 +416,261 @@ public inline fun > LabeledPolynomialSpace.LabeledPolynomial @UnstableKMathAPI public inline fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL1(initialCapacity: Int? = null, block: DSL1LabeledPolynomialBuilder.() -> Unit) : LabeledPolynomial = DSL1LabeledPolynomialBuilder({ left: C, right: C -> left + right }, initialCapacity).apply(block).build() +/** + * Marks DSL that allows to more simply create [LabeledPolynomial]s with good performance. + * + * For example, polynomial \(5 a^2 c^3 - 6 b\) can be described as + * ``` + * Int.algebra { + * val numberedPolynomial : NumberedPolynomial = NumberedPolynomial { + * 5 { a inPowerOf 2u; c inPowerOf 3u } // 5 a^2 c^3 + + * (-6) { b inPowerOf 1u } // (-6) b^1 + * } + * } + * ``` + * @usesMathJax + */ +@DslMarker +@UnstableKMathAPI +internal annotation class LabeledPolynomialBuilderDSL2 + +/** + * Builder of [LabeledPolynomial]. It should be used as an implicit context for lambdas that describe [LabeledPolynomial]. + */ +@UnstableKMathAPI +@LabeledPolynomialBuilderDSL2 +public class DSL2LabeledPolynomialBuilder( + private val ring: Ring, + /** + * Initial capacity of coefficients map. + */ + initialCapacity: Int? = null +) { + /** + * Coefficients storage. Any declaration of any monomial updates the storage. + * Afterward the storage will be used as a resulting coefficients map. + */ + private val coefficients: MutableMap, C> = if (initialCapacity != null) LinkedHashMap(initialCapacity) else LinkedHashMap() + + /** + * Builds the resulting coefficients map. + * + * In fact, it just returns [coefficients] as regular coefficients map of type `Map, C>`. + */ + @PublishedApi + internal fun build(): LabeledPolynomial = LabeledPolynomial(coefficients) + + public inner class Term internal constructor( + internal val signature: Map = HashMap(), + internal val coefficient: C + ) + + private inline fun submit(signature: Map, onPut: Ring.() -> C, onChange: Ring.(C) -> C) { + coefficients.putOrChange<_, C>(signature, { ring.onPut() }, { ring.onChange(it) }) + } + + private inline fun submit(signature: Map, lazyCoefficient: Ring.() -> C) { + submit(signature, lazyCoefficient, { it + lazyCoefficient() }) + } + + private fun submit(signature: Map, coefficient: C) { + submit(signature) { coefficient } + } + + // TODO: `@submit` will be resolved differently. Change it to `@C`. + private fun C.submit() = submit(emptyMap(), { this@submit }) + + private fun Symbol.submit() = submit(mapOf(this to 1u), { one }) + + private fun Term.submit(): Submit { + submit(signature, coefficient) + return Submit + } + + public object Submit + + public operator fun C.unaryPlus(): Submit { + submit() + return Submit + } + + public operator fun C.unaryMinus(): Submit { + submit(emptyMap(), { -this@unaryMinus }, { it - this@unaryMinus }) + return Submit + } + + public operator fun C.plus(other: C): Submit { + submit(emptyMap(), { this@plus + other }) + return Submit + } + + public operator fun C.minus(other: C): Submit { + submit(emptyMap(), { this@minus - other }) + return Submit + } + + public operator fun C.times(other: C): C = ring { this@times * other } + + public operator fun C.plus(other: Symbol): Submit { + submit(emptyMap(), this) + submit(mapOf(other to 1u), ring.one) + return Submit + } + + public operator fun C.minus(other: Symbol): Submit { + submit(emptyMap(), this) + submit(mapOf(other to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun C.times(other: Symbol): Term = Term(mapOf(other to 1u), this) + + public operator fun C.plus(other: Term): Submit { + submit(emptyMap(), this) + other.submit() + return Submit + } + + public operator fun C.minus(other: Term): Submit { + submit(emptyMap(), this) + submit(other.signature, { -other.coefficient }, { it - other.coefficient }) + return Submit + } + + public operator fun C.times(other: Term): Term = Term(other.signature, ring { this@times * other.coefficient }) + + public operator fun Symbol.plus(other: C): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Symbol.minus(other: C): Submit { + this.submit() + submit(emptyMap(), { -other }, { it - other }) + return Submit + } + + public operator fun Symbol.times(other: C): Term = Term(mapOf(this to 1u), other) + + public operator fun Symbol.unaryPlus(): Submit { + this.submit() + return Submit + } + + public operator fun Symbol.unaryMinus(): Submit { + submit(mapOf(this to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun Symbol.plus(other: Symbol): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Symbol.minus(other: Symbol): Submit { + this.submit() + submit(mapOf(other to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun Symbol.times(other: Symbol): Term = + if (this == other) Term(mapOf(this to 2u), ring.one) + else Term(mapOf(this to 1u, other to 1u), ring.one) + + public operator fun Symbol.plus(other: Term): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Symbol.minus(other: Term): Submit { + this.submit() + submit(other.signature, { -other.coefficient }, { it - other.coefficient }) + return Submit + } + + public operator fun Symbol.times(other: Term): Term = + Term( + other.signature.withPutOrChanged(this, 1u) { it -> it + 1u }, + other.coefficient + ) + + public operator fun Term.plus(other: C): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Term.minus(other: C): Submit { + this.submit() + submit(emptyMap(), { -other }, { it - other }) + return Submit + } + + public operator fun Term.times(other: C): Term = + Term( + signature, + ring { coefficient * other } + ) + + public operator fun Term.plus(other: Symbol): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Term.minus(other: Symbol): Submit { + this.submit() + submit(mapOf(other to 1u), { -one }, { it - one }) + return Submit + } + + public operator fun Term.times(other: Symbol): Term = + Term( + signature.withPutOrChanged(other, 1u) { it -> it + 1u }, + coefficient + ) + + public operator fun Term.unaryPlus(): Submit { + this.submit() + return Submit + } + + public operator fun Term.unaryMinus(): Submit { + submit(signature, { -coefficient }, { it - coefficient }) + return Submit + } + + public operator fun Term.plus(other: Term): Submit { + this.submit() + other.submit() + return Submit + } + + public operator fun Term.minus(other: Term): Submit { + this.submit() + submit(other.signature, { -other.coefficient }, { it - other.coefficient }) + return Submit + } + + public operator fun Term.times(other: Term): Term = + Term( + mergeBy(signature, other.signature) { deg1, deg2 -> deg1 + deg2 }, + ring { coefficient * other.coefficient } + ) +} + +//@UnstableKMathAPI +//public fun Ring.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder.() -> Unit): LabeledPolynomial = DSL2LabeledPolynomialBuilder(this, initialCapacity).apply(block).build() + +@UnstableKMathAPI +public fun > LabeledPolynomialSpace.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder.() -> Unit): LabeledPolynomial = DSL2LabeledPolynomialBuilder(ring, initialCapacity).apply(block).build() + +@UnstableKMathAPI +public fun > LabeledRationalFunctionSpace.LabeledPolynomialDSL2(initialCapacity: Int? = null, block: DSL2LabeledPolynomialBuilder.() -> Unit): LabeledPolynomial = DSL2LabeledPolynomialBuilder(ring, initialCapacity).apply(block).build() + // Waiting for context receivers :( FIXME: Replace with context receivers when they will be available /** From 58d7015782bc24c12e11ff2c84d0fe2c631a3c59 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 20:15:30 +0300 Subject: [PATCH 138/174] Remove utils modules. Revive suddenly lost tests. --- kmath-functions/build.gradle.kts | 5 - .../kmath/functions/testUtils/IntModulo.kt | 38 +- .../functions/testUtils/IntModuloUtils.kt | 8 +- .../kmath/functions/testUtils/Rational.kt | 54 +- .../kmath/functions/testUtils/misc.kt | 0 kmath-polynomial/build.gradle.kts | 6 - .../kmath/functions/AlgebraicStubTest.kt | 589 +++++++++++ .../kmath/functions/ListPolynomialTest.kt | 544 ++++++++++ .../kmath/functions/ListPolynomialUtilTest.kt | 982 ++++++++++++++++++ .../kmath/functions/testUtils/BufferUtils.kt | 2 +- .../kmath/functions/testUtils/IntModulo.kt | 38 +- .../functions/testUtils/IntModuloUtils.kt | 9 +- .../kmath/functions/testUtils/NTMisc.kt | 0 .../kmath/functions/testUtils/Rational.kt | 54 +- .../kmath/functions/testUtils/assertion.kt | 12 +- .../kmath/functions/testUtils/misc.kt | 14 +- settings.gradle.kts | 2 - test-utils-functions/build.gradle.kts | 14 - .../kmath/functions/testUtils/assertion.kt | 22 - test-utils-polynomial/build.gradle.kts | 14 - 20 files changed, 2229 insertions(+), 178 deletions(-) rename {test-utils-functions/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt (80%) rename {test-utils-functions/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt (54%) rename {test-utils-polynomial/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt (78%) rename {test-utils-functions/src/commonMain => kmath-functions/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/misc.kt (100%) create mode 100644 kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt create mode 100644 kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt create mode 100644 kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt (80%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt (79%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt (53%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt (100%) rename {test-utils-functions/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt (78%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt (92%) rename {test-utils-polynomial/src/commonMain => kmath-polynomial/src/commonTest}/kotlin/space/kscience/kmath/functions/testUtils/misc.kt (58%) delete mode 100644 test-utils-functions/build.gradle.kts delete mode 100644 test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt delete mode 100644 test-utils-polynomial/build.gradle.kts diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 149a8f277..eec17e82b 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -12,11 +12,6 @@ kotlin.sourceSets { api(project(":kmath-core")) } } - commonTest { - dependencies { - api(projects.testUtilsFunctions) - } - } } dependencies { diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt similarity index 80% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 21095d858..ef601c941 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -11,9 +11,9 @@ import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations -public class IntModulo { - public val residue: Int - public val modulus: Int +class IntModulo { + val residue: Int + val modulus: Int @PublishedApi internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { @@ -27,16 +27,16 @@ public class IntModulo { } } - public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - public operator fun unaryPlus(): IntModulo = this - public operator fun unaryMinus(): IntModulo = + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = IntModulo( if (residue == 0) 0 else modulus - residue, modulus, toCheckInput = false ) - public operator fun plus(other: IntModulo): IntModulo { + operator fun plus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not add two residue different modulo" } return IntModulo( (residue + other.residue) % modulus, @@ -44,13 +44,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun plus(other: Int): IntModulo = + operator fun plus(other: Int): IntModulo = IntModulo( (residue + other) % modulus, modulus, toCheckInput = false ) - public operator fun minus(other: IntModulo): IntModulo { + operator fun minus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not subtract two residue different modulo" } return IntModulo( (residue - other.residue) % modulus, @@ -58,13 +58,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun minus(other: Int): IntModulo = + operator fun minus(other: Int): IntModulo = IntModulo( (residue - other) % modulus, modulus, toCheckInput = false ) - public operator fun times(other: IntModulo): IntModulo { + operator fun times(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not multiply two residue different modulo" } return IntModulo( (residue * other.residue) % modulus, @@ -72,13 +72,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun times(other: Int): IntModulo = + operator fun times(other: Int): IntModulo = IntModulo( (residue * other) % modulus, modulus, toCheckInput = false ) - public operator fun div(other: IntModulo): IntModulo { + operator fun div(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not divide two residue different modulo" } val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } @@ -88,7 +88,7 @@ public class IntModulo { toCheckInput = false ) } - public operator fun div(other: Int): IntModulo { + operator fun div(other: Int): IntModulo { val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } return IntModulo( @@ -109,11 +109,11 @@ public class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -public class IntModuloRing : Ring, ScaleOperations { +class IntModuloRing : Ring, ScaleOperations { - public val modulus: Int + val modulus: Int - public constructor(modulus: Int) { + constructor(modulus: Int) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus } @@ -121,7 +121,7 @@ public class IntModuloRing : Ring, ScaleOperations { override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) + fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right @@ -130,7 +130,7 @@ public class IntModuloRing : Ring, ScaleOperations { override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg override fun scale(a: IntModulo, value: Double): IntModulo = a * value.toInt() } \ No newline at end of file diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt similarity index 54% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index e534c243e..730a455bf 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -9,10 +9,10 @@ import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.PolynomialSpace -public fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = +fun PolynomialSpace.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = +fun IntModuloRing.Polynomial(vararg coefs: Int): Polynomial = Polynomial(coefs.map { IntModulo(it, modulus) }) -public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +fun PolynomialSpace.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt similarity index 78% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 27b0eb21e..19cb77df5 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -12,14 +12,14 @@ import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps @Suppress("NAME_SHADOWING") -public class Rational { - public companion object { - public val ZERO: Rational = Rational(0L) - public val ONE: Rational = Rational(1L) +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) } - public val numerator: Long - public val denominator: Long + val numerator: Long + val denominator: Long internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { @@ -35,16 +35,16 @@ public class Rational { } } - public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - public constructor(numerator: Long) : this(numerator, 1L, false) + 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) - public operator fun unaryPlus(): Rational = this - public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - public operator fun plus(other: Rational): Rational { + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -56,19 +56,19 @@ public class Rational { toCheckInput = false ) } - public operator fun plus(other: Int): Rational = + operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun plus(other: Long): Rational = + operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator, toCheckInput = false ) - public operator fun minus(other: Rational): Rational { + operator fun minus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -80,19 +80,19 @@ public class Rational { toCheckInput = false ) } - public operator fun minus(other: Int): Rational = + operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun minus(other: Long): Rational = + operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator, toCheckInput = false ) - public operator fun times(other: Rational): Rational { + operator fun times(other: Rational): Rational { val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) return Rational( @@ -101,7 +101,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Int): Rational { + operator fun times(other: Int): Rational { val other = other.toLong() val denominatorAndOtherGcd = gcd(denominator, other) return Rational( @@ -110,7 +110,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Long): Rational { + operator fun times(other: Long): Rational { val denominatorAndOtherGcd = gcd(denominator, other) return Rational( numerator * (other / denominatorAndOtherGcd), @@ -118,7 +118,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Rational): Rational { + operator fun div(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val numeratorsGcd = gcd(numerator, other.numerator) return Rational( @@ -126,7 +126,7 @@ public class Rational { (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) } - public operator fun div(other: Int): Rational { + operator fun div(other: Int): Rational { val other = other.toLong() val numeratorAndOtherGcd = gcd(numerator, other) return Rational( @@ -135,7 +135,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Long): Rational { + operator fun div(other: Long): Rational { val numeratorAndOtherGcd = gcd(numerator, other) return Rational( numerator / numeratorAndOtherGcd, @@ -158,7 +158,7 @@ public class Rational { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object RationalField : Field, NumbersAddOps { +object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 100% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt rename to kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index b0f4a095c..85b87fb34 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -12,12 +12,6 @@ kotlin.sourceSets { api(projects.kmathCore) } } - commonTest { - dependencies { - api(projects.testUtilsPolynomial) - api(kotlin("test")) - } - } } dependencies { diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt new file mode 100644 index 000000000..487cd9ee1 --- /dev/null +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -0,0 +1,589 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.functions + + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.Field +import kotlin.jvm.JvmInline +import kotlin.test.Test +import kotlin.test.assertEquals + +@JvmInline +value class Expr(val expr: String) + +object ExprRing : Field { + override fun Expr.unaryMinus(): Expr = Expr("-${expr}") + override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})") + override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})") + override val zero: Expr = Expr("0") + override val one: Expr = Expr("1") + override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})") + override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)") +} + +class AlgebraicStubTest { + @Test + fun test_addMultipliedBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + addMultipliedByDoubling(Expr("57"), Expr("179"), 0u).expr, + "tried addMultipliedBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 + 179)", + addMultipliedByDoubling(Expr("57"), Expr("179"), 1u).expr, + "tried addMultipliedBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 2u).expr, + "tried addMultipliedBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 3u).expr, + "tried addMultipliedBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 4u).expr, + "tried addMultipliedBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 5u).expr, + "tried addMultipliedBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 6u).expr, + "tried addMultipliedBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 7u).expr, + "tried addMultipliedBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 8u).expr, + "tried addMultipliedBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + multiplyByDoubling(Expr("57"), 0u).expr, + "tried multiplyBySquaring(57, 0u)" + ) + assertEquals( + "57", + multiplyByDoubling(Expr("57"), 1u).expr, + "tried multiplyBySquaring(57, 1u)" + ) + assertEquals( + "(57 + 57)", + multiplyByDoubling(Expr("57"), 2u).expr, + "tried multiplyBySquaring(57, 2u)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyByDoubling(Expr("57"), 3u).expr, + "tried multiplyBySquaring(57, 3u)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyByDoubling(Expr("57"), 4u).expr, + "tried multiplyBySquaring(57, 4u)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 5u).expr, + "tried multiplyBySquaring(57, 5u)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 6u).expr, + "tried multiplyBySquaring(57, 6u)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 7u).expr, + "tried multiplyBySquaring(57, 7u)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 8u).expr, + "tried multiplyBySquaring(57, 8u)" + ) + } + } + @Test + fun test_addMultipliedBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + addMultipliedByDoubling(Expr("57"), Expr("179"), 0).expr, + "tried addMultipliedBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 + 179)", + addMultipliedByDoubling(Expr("57"), Expr("179"), 1).expr, + "tried addMultipliedBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 + -179)", + addMultipliedByDoubling(Expr("57"), Expr("179"), -1).expr, + "tried addMultipliedBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 2).expr, + "tried addMultipliedBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 + (-179 + -179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -2).expr, + "tried addMultipliedBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 + 179) + (179 + 179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 3).expr, + "tried addMultipliedBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 + -179) + (-179 + -179))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -3).expr, + "tried addMultipliedBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 4).expr, + "tried addMultipliedBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -4).expr, + "tried addMultipliedBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 + 179) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 5).expr, + "tried addMultipliedBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 + -179) + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -5).expr, + "tried addMultipliedBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 6).expr, + "tried addMultipliedBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -6).expr, + "tried addMultipliedBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 7).expr, + "tried addMultipliedBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179)))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -7).expr, + "tried addMultipliedBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 + (((179 + 179) + (179 + 179)) + ((179 + 179) + (179 + 179))))", + addMultipliedByDoubling(Expr("57"), Expr("179"), 8).expr, + "tried addMultipliedBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 + (((-179 + -179) + (-179 + -179)) + ((-179 + -179) + (-179 + -179))))", + addMultipliedByDoubling(Expr("57"), Expr("179"), -8).expr, + "tried addMultipliedBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_multiplyBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + multiplyByDoubling(Expr("57"), 0).expr, + "tried multiplyBySquaring(57, 0)" + ) + assertEquals( + "57", + multiplyByDoubling(Expr("57"), 1).expr, + "tried multiplyBySquaring(57, 1)" + ) + assertEquals( + "-57", + multiplyByDoubling(Expr("57"), -1).expr, + "tried multiplyBySquaring(57, -1)" + ) + assertEquals( + "(57 + 57)", + multiplyByDoubling(Expr("57"), 2).expr, + "tried multiplyBySquaring(57, 2)" + ) + assertEquals( + "(-57 + -57)", + multiplyByDoubling(Expr("57"), -2).expr, + "tried multiplyBySquaring(57, -2)" + ) + assertEquals( + "(57 + (57 + 57))", + multiplyByDoubling(Expr("57"), 3).expr, + "tried multiplyBySquaring(57, 3)" + ) + assertEquals( + "(-57 + (-57 + -57))", + multiplyByDoubling(Expr("57"), -3).expr, + "tried multiplyBySquaring(57, -3)" + ) + assertEquals( + "((57 + 57) + (57 + 57))", + multiplyByDoubling(Expr("57"), 4).expr, + "tried multiplyBySquaring(57, 4)" + ) + assertEquals( + "((-57 + -57) + (-57 + -57))", + multiplyByDoubling(Expr("57"), -4).expr, + "tried multiplyBySquaring(57, -4)" + ) + assertEquals( + "(57 + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 5).expr, + "tried multiplyBySquaring(57, 5)" + ) + assertEquals( + "(-57 + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -5).expr, + "tried multiplyBySquaring(57, -5)" + ) + assertEquals( + "((57 + 57) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 6).expr, + "tried multiplyBySquaring(57, 6)" + ) + assertEquals( + "((-57 + -57) + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -6).expr, + "tried multiplyBySquaring(57, -6)" + ) + assertEquals( + "((57 + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 7).expr, + "tried multiplyBySquaring(57, 7)" + ) + assertEquals( + "((-57 + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -7).expr, + "tried multiplyBySquaring(57, -7)" + ) + assertEquals( + "(((57 + 57) + (57 + 57)) + ((57 + 57) + (57 + 57)))", + multiplyByDoubling(Expr("57"), 8).expr, + "tried multiplyBySquaring(57, 8)" + ) + assertEquals( + "(((-57 + -57) + (-57 + -57)) + ((-57 + -57) + (-57 + -57)))", + multiplyByDoubling(Expr("57"), -8).expr, + "tried multiplyBySquaring(57, -8)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "57", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0u)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1u)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2u)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3u)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4u)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5u)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6u)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7u)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8u)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_UInt() { + ExprRing { + assertEquals( + "0", + exponentiateBySquaring(Expr("57"), 0u).expr, + "tried exponentiationBySquaring(57, 0u)" + ) + assertEquals( + "57", + exponentiateBySquaring(Expr("57"), 1u).expr, + "tried exponentiationBySquaring(57, 1u)" + ) + assertEquals( + "(57 * 57)", + exponentiateBySquaring(Expr("57"), 2u).expr, + "tried exponentiationBySquaring(57, 2u)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiateBySquaring(Expr("57"), 3u).expr, + "tried exponentiationBySquaring(57, 3u)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiateBySquaring(Expr("57"), 4u).expr, + "tried exponentiationBySquaring(57, 4u)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 5u).expr, + "tried exponentiationBySquaring(57, 5u)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 6u).expr, + "tried exponentiationBySquaring(57, 6u)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 7u).expr, + "tried exponentiationBySquaring(57, 7u)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 8u).expr, + "tried exponentiationBySquaring(57, 8u)" + ) + } + } + @Test + fun test_multiplyExponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "57", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0).expr, + "tried multiplyExponentiationBySquaring(57, 179, 0)" + ) + assertEquals( + "(57 * 179)", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1).expr, + "tried multiplyExponentiationBySquaring(57, 179, 1)" + ) + assertEquals( + "(57 * (1 / 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -1).expr, + "tried multiplyExponentiationBySquaring(57, 179, -1)" + ) + assertEquals( + "(57 * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2).expr, + "tried multiplyExponentiationBySquaring(57, 179, 2)" + ) + assertEquals( + "(57 * ((1 / 179) * (1 / 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -2).expr, + "tried multiplyExponentiationBySquaring(57, 179, -2)" + ) + assertEquals( + "((57 * 179) * (179 * 179))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3).expr, + "tried multiplyExponentiationBySquaring(57, 179, 3)" + ) + assertEquals( + "((57 * (1 / 179)) * ((1 / 179) * (1 / 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -3).expr, + "tried multiplyExponentiationBySquaring(57, 179, -3)" + ) + assertEquals( + "(57 * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4).expr, + "tried multiplyExponentiationBySquaring(57, 179, 4)" + ) + assertEquals( + "(57 * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -4).expr, + "tried multiplyExponentiationBySquaring(57, 179, -4)" + ) + assertEquals( + "((57 * 179) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5).expr, + "tried multiplyExponentiationBySquaring(57, 179, 5)" + ) + assertEquals( + "((57 * (1 / 179)) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -5).expr, + "tried multiplyExponentiationBySquaring(57, 179, -5)" + ) + assertEquals( + "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6).expr, + "tried multiplyExponentiationBySquaring(57, 179, 6)" + ) + assertEquals( + "((57 * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -6).expr, + "tried multiplyExponentiationBySquaring(57, 179, -6)" + ) + assertEquals( + "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7).expr, + "tried multiplyExponentiationBySquaring(57, 179, 7)" + ) + assertEquals( + "(((57 * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -7).expr, + "tried multiplyExponentiationBySquaring(57, 179, -7)" + ) + assertEquals( + "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8).expr, + "tried multiplyExponentiationBySquaring(57, 179, 8)" + ) + assertEquals( + "(57 * ((((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179))) * (((1 / 179) * (1 / 179)) * ((1 / 179) * (1 / 179)))))", + multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), -8).expr, + "tried multiplyExponentiationBySquaring(57, 179, -8)" + ) + } + } + @Test + fun test_exponentiationBySquaring_for_Int() { + ExprRing { + assertEquals( + "0", + exponentiateBySquaring(Expr("57"), 0).expr, + "tried exponentiationBySquaring(57, 0)" + ) + assertEquals( + "57", + exponentiateBySquaring(Expr("57"), 1).expr, + "tried exponentiationBySquaring(57, 1)" + ) + assertEquals( + "(1 / 57)", + exponentiateBySquaring(Expr("57"), -1).expr, + "tried exponentiationBySquaring(57, -1)" + ) + assertEquals( + "(57 * 57)", + exponentiateBySquaring(Expr("57"), 2).expr, + "tried exponentiationBySquaring(57, 2)" + ) + assertEquals( + "((1 / 57) * (1 / 57))", + exponentiateBySquaring(Expr("57"), -2).expr, + "tried exponentiationBySquaring(57, -2)" + ) + assertEquals( + "(57 * (57 * 57))", + exponentiateBySquaring(Expr("57"), 3).expr, + "tried exponentiationBySquaring(57, 3)" + ) + assertEquals( + "((1 / 57) * ((1 / 57) * (1 / 57)))", + exponentiateBySquaring(Expr("57"), -3).expr, + "tried exponentiationBySquaring(57, -3)" + ) + assertEquals( + "((57 * 57) * (57 * 57))", + exponentiateBySquaring(Expr("57"), 4).expr, + "tried exponentiationBySquaring(57, 4)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57)))", + exponentiateBySquaring(Expr("57"), -4).expr, + "tried exponentiationBySquaring(57, -4)" + ) + assertEquals( + "(57 * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 5).expr, + "tried exponentiationBySquaring(57, 5)" + ) + assertEquals( + "((1 / 57) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -5).expr, + "tried exponentiationBySquaring(57, -5)" + ) + assertEquals( + "((57 * 57) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 6).expr, + "tried exponentiationBySquaring(57, 6)" + ) + assertEquals( + "(((1 / 57) * (1 / 57)) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -6).expr, + "tried exponentiationBySquaring(57, -6)" + ) + assertEquals( + "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 7).expr, + "tried exponentiationBySquaring(57, 7)" + ) + assertEquals( + "(((1 / 57) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -7).expr, + "tried exponentiationBySquaring(57, -7)" + ) + assertEquals( + "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", + exponentiateBySquaring(Expr("57"), 8).expr, + "tried exponentiationBySquaring(57, 8)" + ) + assertEquals( + "((((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))) * (((1 / 57) * (1 / 57)) * ((1 / 57) * (1 / 57))))", + exponentiateBySquaring(Expr("57"), -8).expr, + "tried exponentiationBySquaring(57, -8)" + ) + } + } +} \ No newline at end of file diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt new file mode 100644 index 000000000..e7d8dfd8c --- /dev/null +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -0,0 +1,544 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +@file:Suppress("LocalVariableName") + +package space.kscience.kmath.functions + +import space.kscience.kmath.functions.testUtils.IntModuloRing +import space.kscience.kmath.functions.testUtils.ListPolynomial +import space.kscience.kmath.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import kotlin.test.* + + +class ListPolynomialTest { + @Test + fun test_Polynomial_Int_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 2, + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(-2)) + 2, + "test 3" + ) + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 + 0, + "test 4" + ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + polynomial_5 + 0, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + 1, + "test 7" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + 2, + "test 8" + ) + } + } + @Test + fun test_Polynomial_Int_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - -3, + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 2, + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(2)) - 2, + "test 3" + ) + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + polynomial_4 - 0, + "test 4" + ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertEquals( + polynomial_5, + polynomial_5 - 0, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - 1, + "test 6" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - 1, + "test 7" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - 2, + "test 8" + ) + } + } + @Test + fun test_Polynomial_Int_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * 27, + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(7, 0, 49, 21, 14) * 15, + "test 2" + ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + polynomial * 0, + "test 3" + ) + assertSame( + polynomial, + polynomial * 1, + "test 4" + ) + } + } + @Test + fun test_Int_Polynomial_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + -3 + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + 2 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + 2 + ListPolynomial(Rational(-2)), + "test 3" + ) + val polynomial_4 = ListPolynomial() + assertSame( + polynomial_4, + 0 + polynomial_4, + "test 4" + ) + val polynomial_5 = ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)) + assertSame( + polynomial_5, + 0 + polynomial_5, + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + 1 + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-1)), + 1 + ListPolynomial(Rational(-2)), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(2)), + 2 + ListPolynomial(), + "test 8" + ) + } + } + @Test + fun test_Int_Polynomial_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + 3 - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + -2 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + -2 - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(-32, 9), Rational(-8, -9), Rational(8, 7)), + 0 - ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + "test 4" + ) + assertEquals( + ListPolynomial(), + 0 - ListPolynomial(), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + -1 - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(1)), + -1 - ListPolynomial(Rational(-2)), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(-2)), + -2 - ListPolynomial(), + "test 8" + ) + } + } + @Test + fun test_Int_Polynomial_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + val polynomial = ListPolynomial(22, 26, 13, 15, 26) + assertSame( + zero, + 0 * polynomial, + "test 3" + ) + assertSame( + polynomial, + 1 * polynomial, + "test 4" + ) + } + } + @Test + fun test_Polynomial_Constant_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(-2)) + Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial() + Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)) + Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + ListPolynomial(Rational(-2)) + Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial() + Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - Rational(-3), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(2), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(2)) - Rational(2), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial() - Rational(0), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(2), Rational(0), Rational(0), Rational(0)) - Rational(1), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(2)) - Rational(1), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + ListPolynomial() - Rational(2), + "test 7" + ) + } + } + @Test + fun test_Polynomial_Constant_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + ListPolynomial(22, 26, 13, 15, 26) * 27.asConstant(), + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(7, 0, 49, 21, 14) * 15.asConstant(), + "test 2" + ) + } + } + @Test + fun test_Constant_Polynomial_plus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-22, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(-3) + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(2) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(2) + ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(0) + ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(-1), Rational(0), Rational(0), Rational(0)), + Rational(1) + ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(-1)), + Rational(1) + ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(2)), + Rational(2) + ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_minus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(32, 9), Rational(-8, 9), Rational(-8, 7)), + Rational(3) - ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0)), + Rational(-2) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(-2) - ListPolynomial(Rational(-2)), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0)), + Rational(0) - ListPolynomial(), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(1), Rational(0), Rational(0), Rational(0)), + Rational(-1) - ListPolynomial(Rational(-2), Rational(0), Rational(0), Rational(0)), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(1)), + Rational(-1) - ListPolynomial(Rational(-2)), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(-2)), + Rational(-2) - ListPolynomial(), + "test 7" + ) + } + } + @Test + fun test_Constant_Polynomial_times() { + IntModuloRing(35).listPolynomialSpace { + assertEquals( + ListPolynomial(34, 2, 1, 20, 2), + 27 * ListPolynomial(22, 26, 13, 15, 26), + "test 1" + ) + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + 15 * ListPolynomial(7, 0, 49, 21, 14), + "test 2" + ) + } + } + @Test + fun test_Polynomial_unaryMinus() { + RationalField.listPolynomialSpace { + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-5, 9), Rational(8, 9), Rational(8, 7), Rational(0), Rational(0)), + -ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7), Rational(0), Rational(0)), + "test 2" + ) + } + } + @Test + fun test_Polynomial_Polynomial_plus() { + RationalField.listPolynomialSpace { + // (5/9 - 8/9 x - 8/7 x^2) + (-5/7 + 5/1 x + 5/8 x^2) ?= -10/63 + 37/9 x - 29/56 x^2 + assertEquals( + ListPolynomial(Rational(-10, 63), Rational(37, 9), Rational(-29, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) + + ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) + (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 5/12 x + 2/4 x^2 + assertEquals( + ListPolynomial(Rational(-2, 9), Rational(-5, 12), Rational(2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) + + ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) + (-6/3 - 7/2 x + 2/3 x^2) ?= -18/7 - 23/6 x + 2/3 x^2 + assertEquals( + ListPolynomial(Rational(-18, 7), Rational(-23, 6), Rational(2, 3), Rational(0)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) + + ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) + (2/4 + 6/9 x + 4/9 x^2) ?= 0 + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) + + ListPolynomial(Rational(2, 4), Rational(6, 9), Rational(4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_minus() { + RationalField.listPolynomialSpace { + // (5/9 - 8/9 x - 8/7 x^2) - (-5/7 + 5/1 x + 5/8 x^2) ?= 80/63 - 53/9 x - 99/56 x^2 + assertEquals( + ListPolynomial(Rational(80, 63), Rational(-53, 9), Rational(-99, 56)), + ListPolynomial(Rational(5, 9), Rational(-8, 9), Rational(-8, 7)) - + ListPolynomial(Rational(-5, 7), Rational(5, 1), Rational(5, 8)), + "test 1" + ) + // (-2/9 - 8/3 x) - (0 + 9/4 x + 2/4 x^2) ?= -2/9 - 59/12 x - 2/4 x^2 + assertEquals( + ListPolynomial(Rational(-2, 9), Rational(-59, 12), Rational(-2, 4)), + ListPolynomial(Rational(-2, 9), Rational(-8, 3)) - + ListPolynomial(Rational(0), Rational(9, 4), Rational(2, 4)), + "test 2" + ) + // (-4/7 - 2/6 x + 0 x^2 + 0 x^3) - (-6/3 - 7/2 x + 2/3 x^2) ?= 10/7 + 19/6 x - 2/3 x^2 + assertEquals( + ListPolynomial(Rational(10, 7), Rational(19, 6), Rational(-2, 3), Rational(0)), + ListPolynomial(Rational(-4, 7), Rational(-2, 6), Rational(0), Rational(0)) - + ListPolynomial(Rational(-6, 3), Rational(-7, 2), Rational(2, 3)), + "test 3" + ) + // (-2/4 - 6/9 x - 4/9 x^2) - (-2/4 - 6/9 x - 4/9 x^2) ?= 0 + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)) - + ListPolynomial(Rational(-2, 4), Rational(-6, 9), Rational(-4, 9)), + "test 4" + ) + } + } + @Test + fun test_Polynomial_Polynomial_times() { + IntModuloRing(35).listPolynomialSpace { + // (1 + x + x^2) * (1 - x + x^2) ?= 1 + x^2 + x^4 + assertEquals( + ListPolynomial(1, 0, 1, 0, 1), + ListPolynomial(1, -1, 1) * ListPolynomial(1, 1, 1), + "test 1" + ) + // Spoiler: 5 * 7 = 0 + assertEquals( + ListPolynomial(0, 0, 0, 0, 0), + ListPolynomial(5, -25, 10) * ListPolynomial(21, 14, -7), + "test 2" + ) + } + } +} \ No newline at end of file diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt new file mode 100644 index 000000000..339643d02 --- /dev/null +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -0,0 +1,982 @@ +/* + * 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.functions.testUtils.Rational +import space.kscience.kmath.functions.testUtils.RationalField +import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.test.assertEquals + + +@OptIn(UnstableKMathAPI::class) +class ListPolynomialUtilTest { + @Test + fun test_Polynomial_substitute_Double() { + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 0.0, + ListPolynomial(1.0, -2.0, 1.0).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 1.1931904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 2" + ) + assertEquals( + 0.5681904761904762, + ListPolynomial(0.0, 2.6666666666666665, 0.5714285714285714, 1.5).substitute(0.2), + 0.001, + "test 3" + ) + assertEquals( + 1.1811904761904761, + ListPolynomial(0.625, 2.6666666666666665, 0.5714285714285714, 0.0).substitute(0.2), + 0.001, + "test 4" + ) + assertEquals( + 1.1703333333333332, + ListPolynomial(0.625, 2.6666666666666665, 0.0, 1.5).substitute(0.2), + 0.001, + "test 5" + ) + } + @Test + fun test_Polynomial_substitute_Constant() { + assertEquals( + Rational(0), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(25057, 21000), + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 2" + ) + assertEquals( + Rational(2983, 5250), + ListPolynomial(Rational(0), Rational(8, 3), Rational(4, 7), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 3" + ) + assertEquals( + Rational(4961, 4200), + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(4, 7), Rational(0)) + .substitute(RationalField, Rational(1, 5)), + "test 4" + ) + assertEquals( + Rational(3511, 3000), + ListPolynomial(Rational(5, 8), Rational(8, 3), Rational(0), Rational(3, 2)) + .substitute(RationalField, Rational(1, 5)), + "test 5" + ) + } + @Test + fun test_Polynomial_substitute_Polynomial() { + assertEquals( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(709, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(655, 378), Rational(155, 252), Rational(19, 525), Rational(2, 875)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(677, 378), Rational(97, 180), Rational(1, 75), Rational(0)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(653, 378), Rational(221, 420), Rational(4, 175), Rational(2, 875)), + ListPolynomial(Rational(1, 7), Rational(9, 4), Rational(0), Rational(2, 7)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(1, 5))), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(89, 54), Rational(0), Rational(0), Rational(0)), + ListPolynomial(Rational(0), Rational(9, 4), Rational(1, 3), Rational(0)) + .substitute(RationalField, ListPolynomial(Rational(6, 9), Rational(0))), + "test 6" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_Polynomial_substitute_RationalFunction() { + assertEquals( + ListRationalFunction(ListPolynomial(Rational(0)), ListPolynomial(Rational(1))), + ListPolynomial(Rational(1), Rational(-2), Rational(1)) + .substitute(RationalField, ListRationalFunction(ListPolynomial(Rational(1)), ListPolynomial(Rational(1)))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(66349, 243), + Rational(-17873, 405), + Rational(173533, 3780), + Rational(-91141, 567), + Rational(5773909, 105840), + Rational(-23243, 630), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(-130, 27), + Rational(115, 18), + Rational(-797, 54), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(-14, 9), + Rational(31, 14), + Rational(-5077, 980), + Rational(99, 35) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(25, 9), + Rational(-25, 6), + Rational(1985, 144), + Rational(-55, 6), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(0), + Rational(-9, 5), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(6, 9), + Rational(-3, 7) + ), + ListPolynomial( + Rational(0), + Rational(10, 6), + Rational(-10, 8), + Rational(11, 3) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-898, 27), + Rational(271, 45), + Rational(-65, 12) , + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(5, 3), + Rational(-5, 4), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(-9, 5), + Rational(0) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(6, 9), + Rational(0) + ), + ListPolynomial( + Rational(-13, 9), + Rational(10, 6), + Rational(-10, 8), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(56872, 243), + Rational(0, 1), + Rational(-90, 7), + Rational(-3718, 81), + Rational(9, 49), + Rational(0, 1), + Rational(1573, 27) + ), + ListPolynomial( + Rational(169, 81), + Rational(0, 1), + Rational(0, 1), + Rational(-286, 27), + Rational(0, 1), + Rational(0, 1), + Rational(121, 9) + ) + ), + ListPolynomial( + Rational(13, 3), + Rational(0), + Rational(5, 5) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(15, 1), + Rational(0), + Rational(-3, 7) + ), + ListPolynomial( + Rational(-13, 9), + Rational(0), + Rational(0), + Rational(11, 3) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Double() { + assertEquals( + 0.0, + ListRationalFunction( + ListPolynomial(1.0, -2.0, 1.0), + ListPolynomial(-6.302012278484357, 5.831971885376948, -9.271604788393432, 5.494387848015814, -3.7187384450880785) + ).substitute(1.0), + 0.001, + "test 1" + ) + assertEquals( + 2.693702616649797, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 2" + ) + assertEquals( + 2.692226268901378, + ListRationalFunction( + ListPolynomial(0.0, -1.660411278951134, -3.793740946372443, -9.624569269490076), + ListPolynomial(0.0, -1.862973627119981, 4.776550592888336, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 3" + ) + assertEquals( + -0.7394904842099175, + ListRationalFunction( + ListPolynomial(-5.848840571263625, -1.660411278951134, -3.793740946372443, 0.0), + ListPolynomial(-2.9680680215311073, -1.862973627119981, 4.776550592888336, 0.0) + ).substitute(-7.53452770353279), + 0.001, + "test 4" + ) + assertEquals( + 3.526835209398159, + ListRationalFunction( + ListPolynomial(-5.848840571263625, 0.0, 0.0, -9.624569269490076), + ListPolynomial(-2.9680680215311073, 0.0, 0.0, -2.7320154512368466) + ).substitute(-7.53452770353279), + 0.001, + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Constant() { + assertEquals( + Rational(0), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, Rational(1)), + "test 1" + ) + assertEquals( + Rational(1149615, 61306), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 2" + ) + assertEquals( + Rational(3495, 586), + ListRationalFunction( + ListPolynomial(Rational(0), Rational(18, 3), Rational(18, 8), Rational(9, 1)), + ListPolynomial(Rational(0), Rational(-6, 5), Rational(-12, 7), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 3" + ) + assertEquals( + Rational(-88605, 77392), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(18, 3), Rational(18, 8), Rational(0)), + ListPolynomial(Rational(11, 9), Rational(-6, 5), Rational(-12, 7), Rational(0)), + ).substitute(RationalField, Rational(-7, 8)), + "test 4" + ) + assertEquals( + Rational(116145, 3794), + ListRationalFunction( + ListPolynomial(Rational(17, 7), Rational(0), Rational(0), Rational(9, 1)), + ListPolynomial(Rational(11, 9), Rational(0), Rational(0), Rational(2, 1)), + ).substitute(RationalField, Rational(-7, 8)), + "test 5" + ) + } + @Test + fun test_RationalFunction_substitute_Polynomial() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)), + ).substitute(RationalField, ListPolynomial(Rational(1))), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-283303, 36), + Rational(-23593, 24), + Rational(368713, 192), + Rational(1455, 8), + Rational(-272171, 1536), + Rational(-2149, 192), + Rational(469, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(5797, 12), + Rational(595, 16), + Rational(-5285, 72), + Rational(-745, 192), + Rational(1105, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(-11, 12), + Rational(325, 192), + Rational(21, 32), + Rational(-1739, 1536), + Rational(227, 192), + Rational(-59, 64), + Rational(11, 48), + Rational(-11, 96) + ), + ListPolynomial( + Rational(0, 1), + Rational(15, 16), + Rational(-265, 144), + Rational(-25, 192), + Rational(25, 288), + Rational(5, 48), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(-11, 6) + ), + ListPolynomial( + Rational(0, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(0, 1), + Rational(-1, 4), + Rational(2, 4) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(149723, 36), + Rational(8483, 24), + Rational(639, 64), + Rational(3, 32), + Rational(0), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ), + ListPolynomial( + Rational(937, 12), + Rational(55, 16), + Rational(5, 144), + Rational(0), + Rational(0), + Rational(0), + Rational(0) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(11, 3), + Rational(-9, 4), + Rational(-6, 1), + Rational(0) + ), + ListPolynomial( + Rational(-2, 3), + Rational(-15, 4), + Rational(5, 9), + Rational(0) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(-1, 4), + Rational(0) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(-216509, 18), + Rational(0, 1), + Rational(2673, 1), + Rational(0, 1), + Rational(-891, 4), + Rational(0, 1), + Rational(33, 4), + Rational(0, 1), + Rational(-11, 96) + ), + ListPolynomial( + Rational(1213, 3), + Rational(0, 1), + Rational(-135, 2), + Rational(0, 1), + Rational(15, 4), + Rational(0, 1), + Rational(-5, 72) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(2, 9), + Rational(0), + Rational(0), + Rational(0), + Rational(-11, 6) + ), + ListPolynomial( + Rational(-2, 3), + Rational(0), + Rational(0), + Rational(-5, 9) + ) + ).substitute(RationalField, + ListPolynomial( + Rational(-9, 1), + Rational(0), + Rational(2, 4) + ) + ), + "test 5" + ) + } + @Test + @Ignore // FIXME: This tests work only for sane realisations of the substitutions. Currently, it is not. + // Sane algorithm for substitution p(q/r) (p, q, and r are polynomials) should return denominator r^deg(p), + // not r^(deg(p)(deg(p)+1)/2) as it is now. + fun test_RationalFunction_substitute_RationalFunction() { + assertEquals( + ListRationalFunction( + ListPolynomial(Rational(0)), + ListPolynomial(Rational(1)) + ), + ListRationalFunction( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1)) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial(Rational(1)), + ListPolynomial(Rational(1)) + ) + ), + "test 1" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(130087, 3888), + Rational(-2866333, 65610), + Rational(-5076229, 97200), + Rational(222136997, 3280500), + Rational(754719329, 20995200), + Rational(-12010283, 324000), + Rational(-2011967, 172800), + Rational(18607, 2880), + Rational(4705, 4096) + ), + ListPolynomial( + Rational(-143820355, 3779136), + Rational(73886869, 1574640), + Rational(1440175193, 15746400), + Rational(-5308968857, 52488000), + Rational(-186910083731, 2099520000), + Rational(125043463, 1555200), + Rational(5299123, 388800), + Rational(-213757, 15360), + Rational(1380785, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 2" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(5173, 18225), + Rational(904291, 364500), + Rational(283127, 43200), + Rational(37189, 5760), + Rational(147, 128) + ), + ListPolynomial( + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(-163589, 911250), + Rational(-881831, 291600), + Rational(-10722229, 777600), + Rational(-640921, 46080), + Rational(86303, 9216) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-10, 5), + Rational(18, 8), + Rational(-8, 8) + ), + ListPolynomial( + Rational(0), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(0), + Rational(-2, 5), + Rational(-14, 7) + ), + ListPolynomial( + Rational(0), + Rational(5, 9), + Rational(1, 8) + ) + ) + ), + "test 3" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(445, 16), + Rational(-2011, 54), + Rational(1359199, 72900), + Rational(-135733, 32805), + Rational(2254, 6561), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ), + ListPolynomial( + Rational(-2018387, 46656), + Rational(82316437, 1574640), + Rational(-9335047, 393660), + Rational(15765889, 3280500), + Rational(-242089, 656100), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1), + Rational(0, 1) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(-10, 5), + Rational(18, 8), + Rational(0) + ), + ListPolynomial( + Rational(-14, 8), + Rational(-14, 8), + Rational(-19, 6), + Rational(14, 3), + Rational(0) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(-2, 5), + Rational(0) + ), + ListPolynomial( + Rational(-6, 4), + Rational(5, 9), + Rational(0) + ) + ) + ), + "test 4" + ) + assertEquals( + ListRationalFunction( + ListPolynomial( + Rational(41635, 3888), + Rational(0, 1), + Rational(-279187, 11664), + Rational(0, 1), + Rational(103769, 3456), + Rational(0, 1), + Rational(-11017, 768), + Rational(0, 1), + Rational(4097, 4096) + ), + ListPolynomial( + Rational(-13811791, 3779136), + Rational(0, 1), + Rational(-9999395, 419904), + Rational(0, 1), + Rational(6376601, 124416), + Rational(0, 1), + Rational(-3668315, 82944), + Rational(0, 1), + Rational(2097089, 147456) + ) + ), + ListRationalFunction( + ListPolynomial( + Rational(1, 1), + Rational(0), + Rational(0), + Rational(-8, 8) + ), + ListPolynomial( + Rational(-14, 8), + Rational(0), + Rational(0), + Rational(0), + Rational(8, 9) + ) + ).substitute(RationalField, + ListRationalFunction( + ListPolynomial( + Rational(14, 9), + Rational(0), + Rational(-14, 7) + ), + ListPolynomial( + Rational(-6, 4), + Rational(0), + Rational(1, 8) + ) + ) + ), + "test 5" + ) + } + @Test + fun test_Polynomial_derivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).derivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(8, 9), Rational(15, 7), Rational(-20, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).derivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(-8, 3), Rational(8, 9), Rational(15, 7), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).derivative(RationalField), + "test 4" + ) + } + @Test + fun test_Polynomial_nthDerivative() { + assertEquals( + ListPolynomial(Rational(-2), Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 1), + "test 1" + ) + assertFailsWithTypeAndMessage( + "Order of derivative must be non-negative", + "test2" + ) { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(2)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthDerivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(-20, 3)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthDerivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(8, 9), Rational(30, 7), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthDerivative(RationalField, 2), + "test 9" + ) + } + @Test + fun test_Polynomial_antiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).antiderivative(RationalField), + "test 1" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 2" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(4, 27), Rational(5, 28), Rational(-1, 9)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).antiderivative(RationalField), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(1, 5), Rational(-4, 3), Rational(4, 27), Rational(5, 28), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).antiderivative(RationalField), + "test 4" + ) + } + @Test + fun test_Polynomial_nthAntiderivative() { + assertEquals( + ListPolynomial(Rational(0), Rational(1), Rational(-1), Rational(1, 3)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 1), + "test 1" + ) + assertFailsWithTypeAndMessage( + "Order of antiderivative must be non-negative", + "test2" + ) { + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, -1) + } + assertEquals( + ListPolynomial(Rational(1), Rational(-2), Rational(1)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 0), + "test 3" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 2), Rational(-1, 3), Rational(1, 12)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 2), + "test 4" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(1, 6), Rational(-1, 12), Rational(1, 60)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 3), + "test 5" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 24), Rational(-1, 60), Rational(1, 360)), + ListPolynomial(Rational(1), Rational(-2), Rational(1)).nthAntiderivative(RationalField, 4), + "test 6" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 7" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(0), Rational(0), Rational(1, 27), Rational(1, 28), Rational(-1, 54)), + ListPolynomial(Rational(0), Rational(0), Rational(4, 9), Rational(5, 7), Rational(-5, 9)).nthAntiderivative(RationalField, 2), + "test 8" + ) + assertEquals( + ListPolynomial(Rational(0), Rational(0), Rational(1, 10), Rational(-4, 9), Rational(1, 27), Rational(1, 28), Rational(0)), + ListPolynomial(Rational(1, 5), Rational(-8, 3), Rational(4, 9), Rational(5, 7), Rational(0)).nthAntiderivative(RationalField, 2), + "test 9" + ) + } +} \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt similarity index 80% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt index afd26dd36..3297733b1 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt @@ -9,4 +9,4 @@ import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer -public fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() \ No newline at end of file +fun bufferOf(vararg elements: T): Buffer = elements.asBuffer() \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt similarity index 79% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 933c4dc4c..5bac4cd73 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -10,9 +10,9 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.operations.Ring -public class IntModulo { - public val residue: Int - public val modulus: Int +class IntModulo { + val residue: Int + val modulus: Int @PublishedApi internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { @@ -26,16 +26,16 @@ public class IntModulo { } } - public constructor(residue: Int, modulus: Int) : this(residue, modulus, true) + constructor(residue: Int, modulus: Int) : this(residue, modulus, true) - public operator fun unaryPlus(): IntModulo = this - public operator fun unaryMinus(): IntModulo = + operator fun unaryPlus(): IntModulo = this + operator fun unaryMinus(): IntModulo = IntModulo( if (residue == 0) 0 else modulus - residue, modulus, toCheckInput = false ) - public operator fun plus(other: IntModulo): IntModulo { + operator fun plus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not add two residue different modulo" } return IntModulo( (residue + other.residue) % modulus, @@ -43,13 +43,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun plus(other: Int): IntModulo = + operator fun plus(other: Int): IntModulo = IntModulo( (residue + other) % modulus, modulus, toCheckInput = false ) - public operator fun minus(other: IntModulo): IntModulo { + operator fun minus(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not subtract two residue different modulo" } return IntModulo( (residue - other.residue) % modulus, @@ -57,13 +57,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun minus(other: Int): IntModulo = + operator fun minus(other: Int): IntModulo = IntModulo( (residue - other) % modulus, modulus, toCheckInput = false ) - public operator fun times(other: IntModulo): IntModulo { + operator fun times(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not multiply two residue different modulo" } return IntModulo( (residue * other.residue) % modulus, @@ -71,13 +71,13 @@ public class IntModulo { toCheckInput = false ) } - public operator fun times(other: Int): IntModulo = + operator fun times(other: Int): IntModulo = IntModulo( (residue * other) % modulus, modulus, toCheckInput = false ) - public operator fun div(other: IntModulo): IntModulo { + operator fun div(other: IntModulo): IntModulo { require(modulus == other.modulus) { "can not divide two residue different modulo" } val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } @@ -87,7 +87,7 @@ public class IntModulo { toCheckInput = false ) } - public operator fun div(other: Int): IntModulo { + operator fun div(other: Int): IntModulo { val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } return IntModulo( @@ -108,11 +108,11 @@ public class IntModulo { } @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") -public class IntModuloRing : Ring { +class IntModuloRing : Ring { - public val modulus: Int + val modulus: Int - public constructor(modulus: Int) { + constructor(modulus: Int) { require(modulus != 0) { "modulus can not be zero" } this.modulus = if (modulus < 0) -modulus else modulus } @@ -120,7 +120,7 @@ public class IntModuloRing : Ring { override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val one: IntModulo get() = IntModulo(1, modulus, toCheckInput = false) - public fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) + fun number(arg: Int): IntModulo = IntModulo(arg, modulus, toCheckInput = false) override inline fun add(left: IntModulo, right: IntModulo): IntModulo = left + right override inline fun multiply(left: IntModulo, right: IntModulo): IntModulo = left * right @@ -129,5 +129,5 @@ public class IntModuloRing : Ring { override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.minus(arg: IntModulo): IntModulo = this - arg override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg - public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg + inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg } \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt similarity index 53% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 32ca1c3aa..33fd03aa0 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -6,15 +6,14 @@ package space.kscience.kmath.functions.testUtils import space.kscience.kmath.functions.ListPolynomial -import space.kscience.kmath.functions.Polynomial import space.kscience.kmath.functions.ListPolynomialSpace import space.kscience.kmath.functions.PolynomialSpaceOverRing -public fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = +fun ListPolynomialSpace.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, ring.modulus) }) -public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = +fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial = ListPolynomial(coefs.map { IntModulo(it, modulus) }) -public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) -public fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file +fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus) +fun PolynomialSpaceOverRing.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus) \ No newline at end of file diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt similarity index 100% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt similarity index 78% rename from test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 27b0eb21e..19cb77df5 100644 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -12,14 +12,14 @@ import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.NumbersAddOps @Suppress("NAME_SHADOWING") -public class Rational { - public companion object { - public val ZERO: Rational = Rational(0L) - public val ONE: Rational = Rational(1L) +class Rational { + companion object { + val ZERO: Rational = Rational(0L) + val ONE: Rational = Rational(1L) } - public val numerator: Long - public val denominator: Long + val numerator: Long + val denominator: Long internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { if (toCheckInput) { @@ -35,16 +35,16 @@ public class Rational { } } - public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) - public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) - public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) - public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) - public constructor(numerator: Int) : this(numerator.toLong(), 1L, false) - public constructor(numerator: Long) : this(numerator, 1L, false) + 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) - public operator fun unaryPlus(): Rational = this - public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) - public operator fun plus(other: Rational): Rational { + operator fun unaryPlus(): Rational = this + operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) + operator fun plus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -56,19 +56,19 @@ public class Rational { toCheckInput = false ) } - public operator fun plus(other: Int): Rational = + operator fun plus(other: Int): Rational = Rational( numerator + denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun plus(other: Long): Rational = + operator fun plus(other: Long): Rational = Rational( numerator + denominator * other, denominator, toCheckInput = false ) - public operator fun minus(other: Rational): Rational { + operator fun minus(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val dividedThisDenominator = denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd @@ -80,19 +80,19 @@ public class Rational { toCheckInput = false ) } - public operator fun minus(other: Int): Rational = + operator fun minus(other: Int): Rational = Rational( numerator - denominator * other.toLong(), denominator, toCheckInput = false ) - public operator fun minus(other: Long): Rational = + operator fun minus(other: Long): Rational = Rational( numerator - denominator * other, denominator, toCheckInput = false ) - public operator fun times(other: Rational): Rational { + operator fun times(other: Rational): Rational { val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) return Rational( @@ -101,7 +101,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Int): Rational { + operator fun times(other: Int): Rational { val other = other.toLong() val denominatorAndOtherGcd = gcd(denominator, other) return Rational( @@ -110,7 +110,7 @@ public class Rational { toCheckInput = false ) } - public operator fun times(other: Long): Rational { + operator fun times(other: Long): Rational { val denominatorAndOtherGcd = gcd(denominator, other) return Rational( numerator * (other / denominatorAndOtherGcd), @@ -118,7 +118,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Rational): Rational { + operator fun div(other: Rational): Rational { val denominatorsGcd = gcd(denominator, other.denominator) val numeratorsGcd = gcd(numerator, other.numerator) return Rational( @@ -126,7 +126,7 @@ public class Rational { (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) ) } - public operator fun div(other: Int): Rational { + operator fun div(other: Int): Rational { val other = other.toLong() val numeratorAndOtherGcd = gcd(numerator, other) return Rational( @@ -135,7 +135,7 @@ public class Rational { toCheckInput = false ) } - public operator fun div(other: Long): Rational { + operator fun div(other: Long): Rational { val numeratorAndOtherGcd = gcd(numerator, other) return Rational( numerator / numeratorAndOtherGcd, @@ -158,7 +158,7 @@ public class Rational { @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object RationalField : Field, NumbersAddOps { +object RationalField : Field, NumbersAddOps { override inline val zero: Rational get() = Rational.ZERO override inline val one: Rational get() = Rational.ONE diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt similarity index 92% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 5d0b77aa8..4ef87f736 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -13,7 +13,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith -public fun assertContentEquals( +fun assertContentEquals( expected: Map, actual: Map, absoluteTolerance: Double, @@ -23,7 +23,7 @@ public fun assertContentEquals( for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) } -public fun assertEquals( +fun assertEquals( expected: NumberedPolynomial, actual: NumberedPolynomial, absoluteTolerance: Double, @@ -37,7 +37,7 @@ public fun assertEquals( ) } -public fun assertEquals( +fun assertEquals( expected: LabeledPolynomial, actual: LabeledPolynomial, absoluteTolerance: Double, @@ -51,7 +51,7 @@ public fun assertEquals( ) } -public fun assertEquals( +fun assertEquals( expected: NumberedRationalFunction, actual: NumberedRationalFunction, absoluteTolerance: Double, @@ -71,7 +71,7 @@ public fun assertEquals( ) } -public fun assertEquals( +fun assertEquals( expected: LabeledRationalFunction, actual: LabeledRationalFunction, absoluteTolerance: Double, @@ -91,7 +91,7 @@ public fun assertEquals( ) } -public inline fun assertFailsWithTypeAndMessage( +inline fun assertFailsWithTypeAndMessage( expectedMessage: String? = null, assertionMessage: String? = null, block: () -> Unit diff --git a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt similarity index 58% rename from test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt rename to kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt index 051fc0f37..93c3f8ea5 100644 --- a/test-utils-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/misc.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -9,11 +9,11 @@ import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.symbol -public val o: Rational = Rational(0) +val o: Rational = Rational(0) -public val x: Symbol by symbol -public val y: Symbol by symbol -public val z: Symbol by symbol -public val t: Symbol by symbol -public val s: Symbol by symbol -public val iota: Symbol by symbol \ No newline at end of file +val x: Symbol by symbol +val y: Symbol by symbol +val z: Symbol by symbol +val t: Symbol by symbol +val s: Symbol by symbol +val iota: Symbol by symbol \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index bdd83d04e..336e1c36b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,9 +26,7 @@ include( ":kmath-core", ":kmath-coroutines", ":kmath-functions", - ":test-utils-functions", ":kmath-polynomial", - ":test-utils-polynomial", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", diff --git a/test-utils-functions/build.gradle.kts b/test-utils-functions/build.gradle.kts deleted file mode 100644 index 8476abecc..000000000 --- a/test-utils-functions/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(projects.kmathCore) - api(projects.kmathFunctions) - api(kotlin("test")) - } - } -} diff --git a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt deleted file mode 100644 index 5cf82996f..000000000 --- a/test-utils-functions/src/commonMain/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions.testUtils - -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - - -public inline fun assertFailsWithTypeAndMessage( - expectedMessage: String? = null, - assertionMessage: String? = null, - block: () -> Unit -) { - assertEquals( - expectedMessage, - assertFailsWith(T::class, assertionMessage, block).message, - assertionMessage - ) -} \ No newline at end of file diff --git a/test-utils-polynomial/build.gradle.kts b/test-utils-polynomial/build.gradle.kts deleted file mode 100644 index e10e1f2b1..000000000 --- a/test-utils-polynomial/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(projects.kmathCore) - api(projects.kmathPolynomial) - api(kotlin("test")) - } - } -} From 99c7174802e263d1961322a658d85b5e0da9d0a4 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 20:55:10 +0300 Subject: [PATCH 139/174] Turn Polynomial data class back. --- .../kotlin/space/kscience/kmath/functions/Polynomial.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 1e811d3ba..b57697dd9 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 @@ -10,7 +10,6 @@ package space.kscience.kmath.functions import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -import kotlin.jvm.JvmInline import kotlin.math.max import kotlin.math.min @@ -20,8 +19,7 @@ import kotlin.math.min * * @param C the type of constants. */ -@JvmInline -public value class Polynomial( +public data class Polynomial( /** * List that contains coefficients of the polynomial. * From 2d86cf1cc7e6294185038b2b34fc08c7bd17b040 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 21:55:35 +0300 Subject: [PATCH 140/174] Remove power overriding and algebraic stub. --- .../kscience/kmath/functions/Polynomial.kt | 4 - .../kscience/kmath/functions/algebraicStub.kt | 51 ------- .../kmath/functions/AlgebraicStubTest.kt | 129 ------------------ 3 files changed, 184 deletions(-) delete mode 100644 kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt delete mode 100644 kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt 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 b57697dd9..9275ff8eb 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 @@ -247,10 +247,6 @@ public open class PolynomialSpace( ) } } - /** - * Raises [arg] to the integer power [exponent]. - */ // TODO: To optimize boxing - override fun power(arg: Polynomial, exponent: UInt): Polynomial = exponentiateBySquaring(arg, exponent) /** * Instance of zero polynomial (zero of the polynomial ring). diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt deleted file mode 100644 index 5eb1af4dc..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.operations.* - - -// TODO: All of this should be moved to algebraic structures' place for utilities -// FIXME: 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.exponentiateBySquaring(arg: C, exponent: UInt): C = - when { - exponent == 0u -> zero - exponent == 1u -> arg - exponent and 1u == 0u -> exponentiateBySquaring(arg * arg, exponent shr 1) - exponent and 1u == 1u -> multiplyExponentiatedBySquaring(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") - } - -// FIXME: 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.multiplyExponentiatedBySquaring(base: C, arg: C, exponent: UInt): C = - when { - exponent == 0u -> base - exponent == 1u -> base * arg - exponent and 1u == 0u -> multiplyExponentiatedBySquaring(base, arg * arg, exponent shr 1) - exponent and 1u == 1u -> multiplyExponentiatedBySquaring(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/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt deleted file mode 100644 index 5782292b1..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.functions - - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.Field -import kotlin.jvm.JvmInline -import kotlin.test.Test -import kotlin.test.assertEquals - -@JvmInline -value class Expr(val expr: String) - -object ExprRing : Field { - override fun Expr.unaryMinus(): Expr = Expr("-${expr}") - override fun add(left: Expr, right: Expr): Expr = Expr("(${left.expr} + ${right.expr})") - override fun multiply(left: Expr, right: Expr): Expr = Expr("(${left.expr} * ${right.expr})") - override val zero: Expr = Expr("0") - override val one: Expr = Expr("1") - override fun divide(left: Expr, right: Expr): Expr = Expr("(${left.expr} / ${right.expr})") - override fun scale(a: Expr, value: Double): Expr = Expr("(${a.expr} / $value)") -} - -class AlgebraicStubTest { - @Test - fun test_multiplyExponentiationBySquaring_for_UInt() { - ExprRing { - assertEquals( - "57", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 0u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 0u)" - ) - assertEquals( - "(57 * 179)", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 1u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 1u)" - ) - assertEquals( - "(57 * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 2u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 2u)" - ) - assertEquals( - "((57 * 179) * (179 * 179))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 3u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 3u)" - ) - assertEquals( - "(57 * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 4u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 4u)" - ) - assertEquals( - "((57 * 179) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 5u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 5u)" - ) - assertEquals( - "((57 * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 6u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 6u)" - ) - assertEquals( - "(((57 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179)))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 7u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 7u)" - ) - assertEquals( - "(57 * (((179 * 179) * (179 * 179)) * ((179 * 179) * (179 * 179))))", - multiplyExponentiatedBySquaring(Expr("57"), Expr("179"), 8u).expr, - "tried multiplyExponentiationBySquaring(57, 179, 8u)" - ) - } - } - @Test - fun test_exponentiationBySquaring_for_UInt() { - ExprRing { - assertEquals( - "0", - exponentiateBySquaring(Expr("57"), 0u).expr, - "tried exponentiationBySquaring(57, 0u)" - ) - assertEquals( - "57", - exponentiateBySquaring(Expr("57"), 1u).expr, - "tried exponentiationBySquaring(57, 1u)" - ) - assertEquals( - "(57 * 57)", - exponentiateBySquaring(Expr("57"), 2u).expr, - "tried exponentiationBySquaring(57, 2u)" - ) - assertEquals( - "(57 * (57 * 57))", - exponentiateBySquaring(Expr("57"), 3u).expr, - "tried exponentiationBySquaring(57, 3u)" - ) - assertEquals( - "((57 * 57) * (57 * 57))", - exponentiateBySquaring(Expr("57"), 4u).expr, - "tried exponentiationBySquaring(57, 4u)" - ) - assertEquals( - "(57 * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 5u).expr, - "tried exponentiationBySquaring(57, 5u)" - ) - assertEquals( - "((57 * 57) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 6u).expr, - "tried exponentiationBySquaring(57, 6u)" - ) - assertEquals( - "((57 * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 7u).expr, - "tried exponentiationBySquaring(57, 7u)" - ) - assertEquals( - "(((57 * 57) * (57 * 57)) * ((57 * 57) * (57 * 57)))", - exponentiateBySquaring(Expr("57"), 8u).expr, - "tried exponentiationBySquaring(57, 8u)" - ) - } - } -} \ No newline at end of file From f48e4483cc282730f6d7b6e9bddbb47046360682 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 16 Jul 2022 22:21:13 +0300 Subject: [PATCH 141/174] Last cosmetic changes. --- .../kscience/kmath/functions/Polynomial.kt | 81 +++++++++---------- .../kmath/functions/polynomialUtil.kt | 4 +- 2 files changed, 39 insertions(+), 46 deletions(-) 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 9275ff8eb..1f9bab52c 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 @@ -50,7 +50,7 @@ public data class Polynomial( */ public val coefficients: List ) { - override fun toString(): String = "ListPolynomial$coefficients" + override fun toString(): String = "Polynomial$coefficients" } /** @@ -63,7 +63,7 @@ public data class Polynomial( */ public open class PolynomialSpace( /** - * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. + * Underlying ring of constants. Its operations on constants are used by local operations on constants and polynomials. */ public val ring: A, ) : Ring>, ScaleOperations> where A : Ring, A : ScaleOperations { @@ -191,61 +191,54 @@ public open class PolynomialSpace( /** * Returns negation of the polynomial. */ - public override operator fun Polynomial.unaryMinus(): Polynomial = - with(ring) { - Polynomial(coefficients.map { -it }) - } + public override operator fun Polynomial.unaryMinus(): Polynomial = ring { + Polynomial(coefficients.map { -it }) + } /** * Returns sum of the polynomials. */ - public override operator fun Polynomial.plus(other: Polynomial): Polynomial { - with(ring) { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] + other.coefficients[it] - } + public override operator fun Polynomial.plus(other: Polynomial): Polynomial = ring { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] + other.coefficients[it] } - ) - } + } + ) } /** * Returns difference of the polynomials. */ - public override operator fun Polynomial.minus(other: Polynomial): Polynomial { - with(ring) { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(max(thisDegree, otherDegree) + 1) { - when { - it > thisDegree -> -other.coefficients[it] - it > otherDegree -> coefficients[it] - else -> coefficients[it] - other.coefficients[it] - } + public override operator fun Polynomial.minus(other: Polynomial): Polynomial = ring { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(max(thisDegree, otherDegree) + 1) { + when { + it > thisDegree -> -other.coefficients[it] + it > otherDegree -> coefficients[it] + else -> coefficients[it] - other.coefficients[it] } - ) - } + } + ) } /** * Returns product of the polynomials. */ - public override operator fun Polynomial.times(other: Polynomial): Polynomial { - with(ring) { - val thisDegree = degree - val otherDegree = other.degree - return Polynomial( - List(thisDegree + otherDegree + 1) { d -> - (max(0, d - otherDegree)..min(thisDegree, d)) - .map { coefficients[it] * other.coefficients[d - it] } - .reduce { acc, rational -> acc + rational } - } - ) - } + public override operator fun Polynomial.times(other: Polynomial): Polynomial = ring { + val thisDegree = degree + val otherDegree = other.degree + return Polynomial( + List(thisDegree + otherDegree + 1) { d -> + (max(0, d - otherDegree)..min(thisDegree, d)) + .map { coefficients[it] * other.coefficients[d - it] } + .reduce { acc, rational -> acc + rational } + } + ) } /** 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 f745bf6e4..c9377a6c1 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 @@ -91,7 +91,7 @@ public fun Polynomial.integrate( public fun > Polynomial.integrate( ring: Field, range: ClosedRange, -): C { +): C = ring { val antiderivative = integrate(ring) - return ring { antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) } + return antiderivative.value(ring, range.endInclusive) - antiderivative.value(ring, range.start) } \ No newline at end of file From 7de157ce24da9346f323c3226ce93d0355d996bf Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Sun, 17 Jul 2022 14:21:12 +0200 Subject: [PATCH 142/174] Re-introduce line/straight segment, rename components to start/end --- .../trajectory/dubins/DubinsPathFactory.kt | 124 +++++++++--------- .../kscience/kmath/trajectory/segments/Arc.kt | 12 +- .../kmath/trajectory/segments/Line.kt | 23 ---- .../kmath/trajectory/segments/Straight.kt | 18 +++ .../space/kscience/kmath/trajectory/Math.kt | 13 +- .../kmath/trajectory/dubins/DubinsTests.kt | 20 ++- .../kmath/trajectory/segments/LineTests.kt | 15 +-- 7 files changed, 106 insertions(+), 119 deletions(-) delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt index 91287b952..04c639576 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt @@ -6,21 +6,18 @@ package space.kscience.kmath.trajectory.dubins import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Arc -import space.kscience.kmath.trajectory.segments.LineSegment +import space.kscience.kmath.trajectory.segments.* import space.kscience.kmath.trajectory.segments.components.Circle import space.kscience.kmath.trajectory.segments.components.Pose2D -import space.kscience.kmath.trajectory.segments.length -import space.kscience.kmath.trajectory.segments.theta +import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos import kotlin.math.sin public class DubinsPathFactory( - private val base: Pose2D, - private val direction: Pose2D, + private val start: Pose2D, + private val end: Pose2D, private val turningRadius: Double ) { @@ -30,9 +27,9 @@ public class DubinsPathFactory( public val rlr: DubinsPath? get() { - val c1 = base.getRightCircle(turningRadius) - val c2 = direction.getRightCircle(turningRadius) - val centers = Line2D(c1.center, c2.center) + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val centers = Straight(c1.center, c2.center) if (centers.length > turningRadius * 4) return null var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) @@ -45,17 +42,17 @@ public class DubinsPathFactory( dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, base, p1, Arc.Direction.RIGHT) + val a1 = Arc(c1.center, start, p1, Arc.Direction.RIGHT) val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) - val a3 = Arc(c2.center, p2, direction, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, p2, end, Arc.Direction.RIGHT) return DubinsPath(a1, a2, a3) } private val lrl: DubinsPath? get() { - val c1 = base.getLeftCircle(turningRadius) - val c2 = direction.getLeftCircle(turningRadius) - val centers = Line2D(c1.center, c2.center) + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val centers = Straight(c1.center, c2.center) if (centers.length > turningRadius * 4) return null var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) @@ -68,54 +65,54 @@ public class DubinsPathFactory( dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, base, p1, Arc.Direction.LEFT) + val a1 = Arc(c1.center, start, p1, Arc.Direction.LEFT) val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, p2, direction, Arc.Direction.LEFT) + val a3 = Arc(c2.center, p2, end, Arc.Direction.LEFT) return DubinsPath(a1, a2, a3) } public val rsr: DubinsPath get() { - val c1 = base.getRightCircle(turningRadius) - val c2 = direction.getRightCircle(turningRadius) - val l = leftOuterTangent(c1, c2) - val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) - return DubinsPath(a1, LineSegment(l), a3) + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val s = leftOuterTangent(c1, c2) + val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) + return DubinsPath(a1, s, a3) } public val lsl: DubinsPath get() { - val c1 = base.getLeftCircle(turningRadius) - val c2 = direction.getLeftCircle(turningRadius) - val l = rightOuterTangent(c1, c2) - val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) - return DubinsPath(a1, LineSegment(l), a3) + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val s = rightOuterTangent(c1, c2) + val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) + return DubinsPath(a1, s, a3) } public val rsl: DubinsPath? get() { - val c1 = base.getRightCircle(turningRadius) - val c2 = direction.getLeftCircle(turningRadius) - val l = rightInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val s = rightInnerTangent(c1, c2) + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc(c1.center, base, l.base, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.LEFT) - return DubinsPath(a1, LineSegment(l), a3) + val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) + return DubinsPath(a1, s, a3) } public val lsr: DubinsPath? get() { - val c1 = base.getLeftCircle(turningRadius) - val c2 = direction.getRightCircle(turningRadius) - val l = leftInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || l == null) return null + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val s = leftInnerTangent(c1, c2) + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc(c1.center, base, l.base, Arc.Direction.LEFT) - val a3 = Arc(c2.center, l.direction, direction, Arc.Direction.RIGHT) - return DubinsPath(a1, LineSegment(l), a3) + val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) + return DubinsPath(a1, s, a3) } } @@ -133,8 +130,8 @@ private fun Pose2D.getTangentCircles(radius: Double): Pair { private fun leftOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.LEFT) private fun rightOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.RIGHT) -private fun outerTangent(a: Circle, b: Circle, side: SIDE): Line2D { - val centers = Line2D(a.center, b.center) +private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { + val centers = Straight(a.center, b.center) val p1 = when (side) { SIDE.LEFT -> Vector2D( a.center.x - a.radius * cos(centers.theta), @@ -145,29 +142,28 @@ private fun outerTangent(a: Circle, b: Circle, side: SIDE): Line2D { a.center.y - a.radius * sin(centers.theta) ) } - return Line2D( + return Straight( p1, - Vector2D(p1.x + (centers.direction.x - centers.base.x), p1.y + (centers.direction.y - centers.base.y)) + Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) ) } private fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) private fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.RIGHT) -private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Line2D? { - val centers = Line2D(base.center, direction.center) - return if (centers.length > base.radius * 2) { - val angle = theta( - when (side) { - SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) - SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) - } - ) - val dX = base.radius * sin(angle) - val dY = base.radius * cos(angle) - val p1 = Vector2D(base.center.x + dX, base.center.y + dY) - val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) - Line2D(p1, p2) - } else { - null - } +private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? { + val centers = Straight(base.center, direction.center) + if (centers.length < base.radius * 2) return null + val angle = theta( + when (side) { + SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) + SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) + } + ) + val dX = base.radius * sin(angle) + val dY = base.radius * cos(angle) + val p1 = Vector2D(base.center.x + dX, base.center.y + dY) + val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) + return Straight(p1, p2) } + +internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt index b8a81a070..b5e091db7 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt @@ -1,8 +1,8 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.dubins.theta import space.kscience.kmath.trajectory.segments.components.Circle import space.kscience.kmath.trajectory.segments.components.Pose2D import kotlin.math.PI @@ -14,11 +14,11 @@ public class Arc( internal val direction: Direction ) : Circle(center, center.distanceTo(a)), Segment { - private val l1 = Line2D(center, a) - private val l2 = Line2D(center, b) + private val s1 = Straight(center, a) + private val s2 = Straight(center, b) - internal val pose1 = calculatePose(a, l1.theta) - internal val pose2 = calculatePose(b, l2.theta) + internal val pose1 = calculatePose(a, s1.theta) + internal val pose2 = calculatePose(b, s2.theta) private val angle = calculateAngle() override val length: Double = calculateLength() @@ -26,7 +26,7 @@ public class Arc( LEFT, RIGHT } - private fun calculateAngle() = theta(if (direction == Direction.LEFT) l1.theta - l2.theta else l2.theta - l1.theta) + private fun calculateAngle() = theta(if (direction == Direction.LEFT) s1.theta - s2.theta else s2.theta - s1.theta) private fun calculateLength(): Double { val proportion = angle / (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt deleted file mode 100644 index 0e23b27f1..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Line.kt +++ /dev/null @@ -1,23 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Line2D -import space.kscience.kmath.operations.DoubleField.pow -import kotlin.math.PI -import kotlin.math.atan2 -import kotlin.math.sqrt - -public data class LineSegment( - internal val line: Line2D -) : Segment { - override val length: Double - get() = line.length -} - -internal val Line2D.theta: Double - get() = theta(atan2(direction.x - base.x, direction.y - base.y)) - -internal val Line2D.length: Double - get() = base.distanceTo(direction) - -internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt new file mode 100644 index 000000000..444025d83 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt @@ -0,0 +1,18 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.dubins.theta +import kotlin.math.PI +import kotlin.math.atan2 + +public data class Straight( + internal val start: Vector2D, + internal val end: Vector2D +) : Segment { + override val length: Double + get() = start.distanceTo(end) + + internal val theta: Double + get() = theta(atan2(end.x - start.x, end.y - start.y)) +} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index f52bb56f2..92b2f1df9 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,9 +1,8 @@ package space.kscience.kmath.trajectory -import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.segments.Straight import space.kscience.kmath.trajectory.segments.components.Pose2D -import space.kscience.kmath.trajectory.segments.theta import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin @@ -15,13 +14,13 @@ fun Double.radiansToDegrees() = this * 180 / PI fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta fun Pose2D.equalsFloat(other: Pose2D) = x.equalFloat(other.x) && y.equalFloat(other.y) && theta.equalFloat(other.theta) -fun Line2D.inverse() = Line2D(direction, base) -fun Line2D.shift(shift: Int, width: Double): Line2D { +fun Straight.inverse() = Straight(end, start) +fun Straight.shift(shift: Int, width: Double): Straight { val dX = width * sin(inverse().theta) val dY = width * sin(theta) - return Line2D( - Vector2D(base.x - dX * shift, base.y - dY * shift), - Vector2D(direction.x - dX * shift, direction.y - dY * shift) + return Straight( + Vector2D(start.x - dX * shift, start.y - dY * shift), + Vector2D(end.x - dX * shift, end.y - dY * shift) ) } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 583e7a4e0..efe35e5d8 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -6,15 +6,13 @@ package space.kscience.kmath.trajectory.dubins import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.segments.Arc -import space.kscience.kmath.trajectory.segments.LineSegment import space.kscience.kmath.trajectory.equalFloat import space.kscience.kmath.trajectory.equalsFloat import space.kscience.kmath.trajectory.inverse +import space.kscience.kmath.trajectory.segments.Straight import space.kscience.kmath.trajectory.segments.components.Pose2D -import space.kscience.kmath.trajectory.segments.theta import space.kscience.kmath.trajectory.shift import kotlin.test.Test import kotlin.test.assertNotNull @@ -25,11 +23,11 @@ class DubinsTests { @Test fun dubinsTest() { - val line = Line2D(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) - val lineP1 = line.shift(1, 10.0).inverse() + val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + val lineP1 = straight.shift(1, 10.0).inverse() - val start = Pose2D(line.direction, line.theta) - val end = Pose2D(lineP1.base, lineP1.theta) + val start = Pose2D(straight.end, straight.theta) + val end = Pose2D(lineP1.start, lineP1.theta) val radius = 2.0 val dubins = DubinsPathFactory(start, end, radius) @@ -58,10 +56,10 @@ class DubinsTests { val b = path.b as Arc assertTrue(path.a.pose2.equalsFloat(b.pose1)) assertTrue(path.c.pose1.equalsFloat(b.pose2)) - } else if (path.b is LineSegment) { - val b = (path.b as LineSegment).line - assertTrue(path.a.pose2.equalsFloat(Pose2D(b.base, b.theta))) - assertTrue(path.c.pose1.equalsFloat(Pose2D(b.direction, b.theta))) + } else if (path.b is Straight) { + val b = path.b as Straight + assertTrue(path.a.pose2.equalsFloat(Pose2D(b.start, b.theta))) + assertTrue(path.c.pose1.equalsFloat(Pose2D(b.end, b.theta))) } } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index 30f5ef6d8..e8184e178 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.Line2D import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.math.pow @@ -13,21 +12,21 @@ class LineTests { @Test fun lineTest() { - val line = Line2D(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) - assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), line.length) - assertEquals(45.0, line.theta.radiansToDegrees()) + val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), straight.length) + assertEquals(45.0, straight.theta.radiansToDegrees()) } @Test fun lineAngleTest() { val zero = Vector2D(0.0, 0.0) - val north = Line2D(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) + val north = Straight(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) assertEquals(0.0, north.theta.radiansToDegrees()) - val east = Line2D(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) + val east = Straight(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) assertEquals(90.0, east.theta.radiansToDegrees()) - val south = Line2D(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) + val south = Straight(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) assertEquals(180.0, south.theta.radiansToDegrees()) - val west = Line2D(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) + val west = Straight(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) assertEquals(270.0, west.theta.radiansToDegrees()) } } From 3260c3d17146226f465aa98a5fc6f8a7cb4262cd Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Sun, 17 Jul 2022 14:39:43 +0200 Subject: [PATCH 143/174] Pose2D facrtory function --- .../space/kscience/kmath/trajectory/segments/Arc.kt | 12 +++++++----- .../kmath/trajectory/segments/components/Pose2D.kt | 6 +++--- .../kscience/kmath/trajectory/dubins/DubinsTests.kt | 10 +++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt index b5e091db7..fe101f359 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt @@ -34,9 +34,11 @@ public class Arc( } private fun calculatePose(vector: Vector2D, theta: Double): Pose2D = - if (direction == Direction.LEFT) { - Pose2D(vector.x, vector.y, theta(theta - PI / 2)) - } else { - Pose2D(vector.x, vector.y, theta(theta + PI / 2)) - } + Pose2D.of( + vector, + when (direction) { + Direction.LEFT -> theta(theta - PI / 2) + Direction.RIGHT -> theta(theta + PI / 2) + } + ) } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt index d00dfbd96..c49da3187 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt @@ -1,13 +1,13 @@ package space.kscience.kmath.trajectory.segments.components import space.kscience.kmath.geometry.Vector2D -import kotlin.math.cos -import kotlin.math.sin public data class Pose2D( override val x: Double, override val y: Double, public val theta: Double ) : Vector2D { - internal constructor(vector: Vector2D, theta: Double) : this(vector.x, vector.y, theta) + internal companion object { + internal fun of(vector: Vector2D, theta: Double) = Pose2D(vector.x, vector.y, theta) + } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index efe35e5d8..025aab2b7 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -7,10 +7,10 @@ package space.kscience.kmath.trajectory.dubins import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Arc import space.kscience.kmath.trajectory.equalFloat import space.kscience.kmath.trajectory.equalsFloat import space.kscience.kmath.trajectory.inverse +import space.kscience.kmath.trajectory.segments.Arc import space.kscience.kmath.trajectory.segments.Straight import space.kscience.kmath.trajectory.segments.components.Pose2D import space.kscience.kmath.trajectory.shift @@ -26,8 +26,8 @@ class DubinsTests { val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) val lineP1 = straight.shift(1, 10.0).inverse() - val start = Pose2D(straight.end, straight.theta) - val end = Pose2D(lineP1.start, lineP1.theta) + val start = Pose2D.of(straight.end, straight.theta) + val end = Pose2D.of(lineP1.start, lineP1.theta) val radius = 2.0 val dubins = DubinsPathFactory(start, end, radius) @@ -58,8 +58,8 @@ class DubinsTests { assertTrue(path.c.pose1.equalsFloat(b.pose2)) } else if (path.b is Straight) { val b = path.b as Straight - assertTrue(path.a.pose2.equalsFloat(Pose2D(b.start, b.theta))) - assertTrue(path.c.pose1.equalsFloat(Pose2D(b.end, b.theta))) + assertTrue(path.a.pose2.equalsFloat(Pose2D.of(b.start, b.theta))) + assertTrue(path.c.pose1.equalsFloat(Pose2D.of(b.end, b.theta))) } } } From 8faa312424f37bf6aa4b6db3c33e166709c346d2 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Sun, 17 Jul 2022 14:56:21 +0200 Subject: [PATCH 144/174] Dubins factory functions --- .../kmath/trajectory/dubins/DubinsPath.kt | 106 +++++++++++ .../trajectory/dubins/DubinsPathFactory.kt | 169 ------------------ .../trajectory/dubins/TrajectoryFunctions.kt | 67 +++++++ .../kmath/trajectory/dubins/DubinsTests.kt | 4 +- 4 files changed, 175 insertions(+), 171 deletions(-) delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt index 005d7fd60..ad67fa11d 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt @@ -5,8 +5,16 @@ package space.kscience.kmath.trajectory.dubins +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.segments.Arc import space.kscience.kmath.trajectory.segments.Segment +import space.kscience.kmath.trajectory.segments.Straight +import space.kscience.kmath.trajectory.segments.components.Circle +import space.kscience.kmath.trajectory.segments.components.Pose2D +import kotlin.math.acos +import kotlin.math.cos +import kotlin.math.sin public class DubinsPath( public val a: Arc, @@ -27,4 +35,102 @@ public class DubinsPath( public enum class TYPE { RLR, LRL, RSR, LSL, RSL, LSR } + + public companion object { + public fun all(start: Pose2D, end: Pose2D, turningRadius: Double): List = + listOfNotNull( + rlr(start, end, turningRadius), + lrl(start, end, turningRadius), + rsr(start, end, turningRadius), + lsl(start, end, turningRadius), + rsl(start, end, turningRadius), + lsr(start, end, turningRadius) + ) + public fun shortest(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath = + all(start, end, turningRadius).minByOrNull { it.length }!! + + public fun rlr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val centers = Straight(c1.center, c2.center) + if (centers.length > turningRadius * 4) return null + + var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, start, p1, Arc.Direction.RIGHT) + val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) + val a3 = Arc(c2.center, p2, end, Arc.Direction.RIGHT) + return DubinsPath(a1, a2, a3) + } + + public fun lrl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val centers = Straight(c1.center, c2.center) + if (centers.length > turningRadius * 4) return null + + var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) + var dX = turningRadius * sin(theta) + var dY = turningRadius * cos(theta) + val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val e = Circle(p, turningRadius) + val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) + dX = turningRadius * sin(theta) + dY = turningRadius * cos(theta) + val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val a1 = Arc(c1.center, start, p1, Arc.Direction.LEFT) + val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, p2, end, Arc.Direction.LEFT) + return DubinsPath(a1, a2, a3) + } + + public fun rsr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath { + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val s = leftOuterTangent(c1, c2) + val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) + return DubinsPath(a1, s, a3) + } + + public fun lsl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath { + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val s = rightOuterTangent(c1, c2) + val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) + return DubinsPath(a1, s, a3) + } + + public fun rsl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { + val c1 = start.getRightCircle(turningRadius) + val c2 = end.getLeftCircle(turningRadius) + val s = rightInnerTangent(c1, c2) + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null + + val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) + return DubinsPath(a1, s, a3) + } + + public fun lsr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { + val c1 = start.getLeftCircle(turningRadius) + val c2 = end.getRightCircle(turningRadius) + val s = leftInnerTangent(c1, c2) + if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null + + val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) + val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) + return DubinsPath(a1, s, a3) + } + } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt deleted file mode 100644 index 04c639576..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPathFactory.kt +++ /dev/null @@ -1,169 +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.trajectory.dubins - -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.* -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D -import kotlin.math.PI -import kotlin.math.acos -import kotlin.math.cos -import kotlin.math.sin - -public class DubinsPathFactory( - private val start: Pose2D, - private val end: Pose2D, - private val turningRadius: Double -) { - - public val all: List get() = listOfNotNull(rlr, lrl, rsr, lsl, rsl, lsr) - public val shortest: DubinsPath get() = all.minByOrNull { it.length }!! - public operator fun get(type: DubinsPath.TYPE): DubinsPath? = all.find { it.type == type } - - public val rlr: DubinsPath? - get() { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val centers = Straight(c1.center, c2.center) - if (centers.length > turningRadius * 4) return null - - var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, start, p1, Arc.Direction.RIGHT) - val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) - val a3 = Arc(c2.center, p2, end, Arc.Direction.RIGHT) - return DubinsPath(a1, a2, a3) - } - - private val lrl: DubinsPath? - get() { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val centers = Straight(c1.center, c2.center) - if (centers.length > turningRadius * 4) return null - - var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) - var dX = turningRadius * sin(theta) - var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) - theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) - dX = turningRadius * sin(theta) - dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, start, p1, Arc.Direction.LEFT) - val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, p2, end, Arc.Direction.LEFT) - return DubinsPath(a1, a2, a3) - } - - public val rsr: DubinsPath - get() { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val s = leftOuterTangent(c1, c2) - val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) - return DubinsPath(a1, s, a3) - } - - public val lsl: DubinsPath - get() { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val s = rightOuterTangent(c1, c2) - val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) - return DubinsPath(a1, s, a3) - } - - public val rsl: DubinsPath? - get() { - val c1 = start.getRightCircle(turningRadius) - val c2 = end.getLeftCircle(turningRadius) - val s = rightInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - - val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) - return DubinsPath(a1, s, a3) - } - - public val lsr: DubinsPath? - get() { - val c1 = start.getLeftCircle(turningRadius) - val c2 = end.getRightCircle(turningRadius) - val s = leftInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - - val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) - return DubinsPath(a1, s, a3) - } -} - -private enum class SIDE { - LEFT, RIGHT -} - -private fun Pose2D.getLeftCircle(radius: Double): Circle = getTangentCircles(radius).first -private fun Pose2D.getRightCircle(radius: Double): Circle = getTangentCircles(radius).second -private fun Pose2D.getTangentCircles(radius: Double): Pair { - val dX = radius * cos(theta) - val dY = radius * sin(theta) - return Circle(Vector2D(x - dX, y + dY), radius) to Circle(Vector2D(x + dX, y - dY), radius) -} - -private fun leftOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.LEFT) -private fun rightOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.RIGHT) -private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { - val centers = Straight(a.center, b.center) - val p1 = when (side) { - SIDE.LEFT -> Vector2D( - a.center.x - a.radius * cos(centers.theta), - a.center.y + a.radius * sin(centers.theta) - ) - SIDE.RIGHT -> Vector2D( - a.center.x + a.radius * cos(centers.theta), - a.center.y - a.radius * sin(centers.theta) - ) - } - return Straight( - p1, - Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) - ) -} - -private fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) -private fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.RIGHT) -private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? { - val centers = Straight(base.center, direction.center) - if (centers.length < base.radius * 2) return null - val angle = theta( - when (side) { - SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) - SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) - } - ) - val dX = base.radius * sin(angle) - val dY = base.radius * cos(angle) - val p1 = Vector2D(base.center.x + dX, base.center.y + dY) - val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) - return Straight(p1, p2) -} - -internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt new file mode 100644 index 000000000..547cb99fc --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt @@ -0,0 +1,67 @@ +/* + * 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.trajectory.dubins + +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.segments.Straight +import space.kscience.kmath.trajectory.segments.components.Circle +import space.kscience.kmath.trajectory.segments.components.Pose2D +import kotlin.math.PI +import kotlin.math.acos +import kotlin.math.cos +import kotlin.math.sin + +private enum class SIDE { + LEFT, RIGHT +} + +internal fun Pose2D.getLeftCircle(radius: Double): Circle = getTangentCircles(radius).first +internal fun Pose2D.getRightCircle(radius: Double): Circle = getTangentCircles(radius).second +internal fun Pose2D.getTangentCircles(radius: Double): Pair { + val dX = radius * cos(theta) + val dY = radius * sin(theta) + return Circle(Vector2D(x - dX, y + dY), radius) to Circle(Vector2D(x + dX, y - dY), radius) +} + +internal fun leftOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.LEFT) +internal fun rightOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.RIGHT) +private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { + val centers = Straight(a.center, b.center) + val p1 = when (side) { + SIDE.LEFT -> Vector2D( + a.center.x - a.radius * cos(centers.theta), + a.center.y + a.radius * sin(centers.theta) + ) + SIDE.RIGHT -> Vector2D( + a.center.x + a.radius * cos(centers.theta), + a.center.y - a.radius * sin(centers.theta) + ) + } + return Straight( + p1, + Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) + ) +} + +internal fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) +internal fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.RIGHT) +private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? { + val centers = Straight(base.center, direction.center) + if (centers.length < base.radius * 2) return null + val angle = theta( + when (side) { + SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) + SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) + } + ) + val dX = base.radius * sin(angle) + val dY = base.radius * cos(angle) + val p1 = Vector2D(base.center.x + dX, base.center.y + dY) + val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) + return Straight(p1, p2) +} + +internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 025aab2b7..a5288e40d 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -29,7 +29,7 @@ class DubinsTests { val start = Pose2D.of(straight.end, straight.theta) val end = Pose2D.of(lineP1.start, lineP1.theta) val radius = 2.0 - val dubins = DubinsPathFactory(start, end, radius) + val dubins = DubinsPath.all(start, end, radius) val absoluteDistance = start.distanceTo(end) println("Absolute distance: $absoluteDistance") @@ -43,7 +43,7 @@ class DubinsTests { ) expectedLengths.forEach { - val path = dubins[it.key] + val path = dubins.find { p -> p.type === it.key } assertNotNull(path, "Path ${it.key} not found") println("${it.key}: ${path.length}") assertTrue(it.value.equalFloat(path.length)) From 86fce7ec68d10dda664ddd936652eacd387c83b8 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Sun, 17 Jul 2022 15:47:05 +0200 Subject: [PATCH 145/174] Arc contains circle, circle direction is computed from poses, factory function can create Arc based on Vector points and provided direction --- .../kmath/trajectory/dubins/DubinsPath.kt | 28 ++++---- .../kscience/kmath/trajectory/segments/Arc.kt | 64 +++++++++++-------- .../kmath/trajectory/dubins/DubinsTests.kt | 12 ++-- .../kmath/trajectory/segments/ArcTests.kt | 6 +- 4 files changed, 61 insertions(+), 49 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt index ad67fa11d..ee4f38662 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt @@ -65,9 +65,9 @@ public class DubinsPath( dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, start, p1, Arc.Direction.RIGHT) - val a2 = Arc(e.center, p1, p2, Arc.Direction.LEFT) - val a3 = Arc(c2.center, p2, end, Arc.Direction.RIGHT) + val a1 = Arc.of(c1.center, start, p1, Arc.Direction.RIGHT) + val a2 = Arc.of(e.center, p1, p2, Arc.Direction.LEFT) + val a3 = Arc.of(c2.center, p2, end, Arc.Direction.RIGHT) return DubinsPath(a1, a2, a3) } @@ -87,9 +87,9 @@ public class DubinsPath( dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc(c1.center, start, p1, Arc.Direction.LEFT) - val a2 = Arc(e.center, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, p2, end, Arc.Direction.LEFT) + val a1 = Arc.of(c1.center, start, p1, Arc.Direction.LEFT) + val a2 = Arc.of(e.center, p1, p2, Arc.Direction.RIGHT) + val a3 = Arc.of(c2.center, p2, end, Arc.Direction.LEFT) return DubinsPath(a1, a2, a3) } @@ -97,8 +97,8 @@ public class DubinsPath( val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = leftOuterTangent(c1, c2) - val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) + val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.RIGHT) + val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.RIGHT) return DubinsPath(a1, s, a3) } @@ -106,8 +106,8 @@ public class DubinsPath( val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = rightOuterTangent(c1, c2) - val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) + val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.LEFT) + val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.LEFT) return DubinsPath(a1, s, a3) } @@ -117,8 +117,8 @@ public class DubinsPath( val s = rightInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.LEFT) + val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.RIGHT) + val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.LEFT) return DubinsPath(a1, s, a3) } @@ -128,8 +128,8 @@ public class DubinsPath( val s = leftInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc(c2.center, s.end, end, Arc.Direction.RIGHT) + val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.LEFT) + val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.RIGHT) return DubinsPath(a1, s, a3) } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt index fe101f359..966e1e4e2 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt @@ -1,44 +1,56 @@ package space.kscience.kmath.trajectory.segments -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.dubins.theta import space.kscience.kmath.trajectory.segments.components.Circle import space.kscience.kmath.trajectory.segments.components.Pose2D import kotlin.math.PI -public class Arc( - center: Vector2D, - a: Vector2D, - b: Vector2D, - internal val direction: Direction -) : Circle(center, center.distanceTo(a)), Segment { +public data class Arc( + public val circle: Circle, + public val start: Pose2D, + public val end: Pose2D +) : Segment { - private val s1 = Straight(center, a) - private val s2 = Straight(center, b) + internal companion object { + fun of(center: Vector2D, start: Vector2D, end: Vector2D, direction: Direction): Arc { + val s1 = Straight(center, start) + val s2 = Straight(center, end) + val pose1 = calculatePose(start, s1.theta, direction) + val pose2 = calculatePose(end, s2.theta, direction) + return Arc(Circle(center, s1.length), pose1, pose2) + } - internal val pose1 = calculatePose(a, s1.theta) - internal val pose2 = calculatePose(b, s2.theta) - private val angle = calculateAngle() - override val length: Double = calculateLength() + private fun calculatePose(vector: Vector2D, theta: Double, direction: Direction): Pose2D = + Pose2D.of( + vector, + when (direction) { + Direction.LEFT -> theta(theta - PI / 2) + Direction.RIGHT -> theta(theta + PI / 2) + } + ) + } - public enum class Direction { + internal enum class Direction { LEFT, RIGHT } - private fun calculateAngle() = theta(if (direction == Direction.LEFT) s1.theta - s2.theta else s2.theta - s1.theta) - - private fun calculateLength(): Double { + override val length: Double get() { + val angle: Double = theta(if (direction == Direction.LEFT) start.theta - end.theta else end.theta - start.theta) val proportion = angle / (2 * PI) - return circumference * proportion + return circle.circumference * proportion + } + + internal val direction: Direction = if (start.y < circle.center.y) { + if (start.theta > PI) Direction.RIGHT else Direction.LEFT + } else if (start.y > circle.center.y) { + if (start.theta < PI) Direction.RIGHT else Direction.LEFT + } else { + if (start.theta == 0.0) { + if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT + } else { + if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT + } } - private fun calculatePose(vector: Vector2D, theta: Double): Pose2D = - Pose2D.of( - vector, - when (direction) { - Direction.LEFT -> theta(theta - PI / 2) - Direction.RIGHT -> theta(theta + PI / 2) - } - ) } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index a5288e40d..47e6ac2ef 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -48,18 +48,18 @@ class DubinsTests { println("${it.key}: ${path.length}") assertTrue(it.value.equalFloat(path.length)) - assertTrue(start.equalsFloat(path.a.pose1)) - assertTrue(end.equalsFloat(path.c.pose2)) + assertTrue(start.equalsFloat(path.a.start)) + assertTrue(end.equalsFloat(path.c.end)) // Not working, theta double precision inaccuracy if (path.b is Arc) { val b = path.b as Arc - assertTrue(path.a.pose2.equalsFloat(b.pose1)) - assertTrue(path.c.pose1.equalsFloat(b.pose2)) + assertTrue(path.a.end.equalsFloat(b.start)) + assertTrue(path.c.start.equalsFloat(b.end)) } else if (path.b is Straight) { val b = path.b as Straight - assertTrue(path.a.pose2.equalsFloat(Pose2D.of(b.start, b.theta))) - assertTrue(path.c.pose1.equalsFloat(Pose2D.of(b.end, b.theta))) + assertTrue(path.a.end.equalsFloat(Pose2D.of(b.start, b.theta))) + assertTrue(path.c.start.equalsFloat(Pose2D.of(b.end, b.theta))) } } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index a59643c0c..5b4ae6d7a 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -11,9 +11,9 @@ class ArcTests { @Test fun arcTest() { val circle = Circle(Vector2D(0.0, 0.0), 2.0) - val arc = Arc(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) + val arc = Arc.of(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) assertEquals(circle.circumference / 4, arc.length, 1.0) - assertEquals(0.0, arc.pose1.theta.radiansToDegrees()) - assertEquals(90.0, arc.pose2.theta.radiansToDegrees()) + assertEquals(0.0, arc.start.theta.radiansToDegrees()) + assertEquals(90.0, arc.end.theta.radiansToDegrees()) } } From 429eefa3f7750c4d8e6dfccabb1206c77988ec38 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Sun, 17 Jul 2022 15:48:08 +0200 Subject: [PATCH 146/174] Arc direction as computed property --- .../kscience/kmath/trajectory/segments/Arc.kt | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt index 966e1e4e2..1c02dd952 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt @@ -35,22 +35,25 @@ public data class Arc( LEFT, RIGHT } - override val length: Double get() { - val angle: Double = theta(if (direction == Direction.LEFT) start.theta - end.theta else end.theta - start.theta) - val proportion = angle / (2 * PI) - return circle.circumference * proportion - } - - internal val direction: Direction = if (start.y < circle.center.y) { - if (start.theta > PI) Direction.RIGHT else Direction.LEFT - } else if (start.y > circle.center.y) { - if (start.theta < PI) Direction.RIGHT else Direction.LEFT - } else { - if (start.theta == 0.0) { - if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT - } else { - if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT + override val length: Double + get() { + val angle: Double = + theta(if (direction == Direction.LEFT) start.theta - end.theta else end.theta - start.theta) + val proportion = angle / (2 * PI) + return circle.circumference * proportion + } + + internal val direction: Direction + get() = if (start.y < circle.center.y) { + if (start.theta > PI) Direction.RIGHT else Direction.LEFT + } else if (start.y > circle.center.y) { + if (start.theta < PI) Direction.RIGHT else Direction.LEFT + } else { + if (start.theta == 0.0) { + if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT + } else { + if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT + } } - } } From f2cbbeba2017af8dd54795e9c4b0ef82682b7715 Mon Sep 17 00:00:00 2001 From: Erik Schouten Date: Sun, 17 Jul 2022 15:56:24 +0200 Subject: [PATCH 147/174] Author details --- docs/templates/README-TEMPLATE.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index 4ffa9e75f..c466324b8 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -103,3 +103,10 @@ The project requires a lot of additional work. The most important thing we need required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues marked with [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. + +## Author +Erik Schouten + +Github: ESchouten + +Email: erik-schouten@hotmail.nl From 9d4df5d8e03a1aadb85109e3fabb2d25694b1695 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 08:22:41 +0300 Subject: [PATCH 148/174] Add and regenerate READMEs. Fix files' directory. --- README.md | 31 +++++++++++- kmath-ast/README.md | 6 +-- kmath-commons/README.md | 6 +-- kmath-complex/README.md | 10 ++-- kmath-core/README.md | 6 +-- kmath-coroutines/README.md | 6 +-- kmath-dimensions/README.md | 6 +-- kmath-ejml/README.md | 6 +-- kmath-for-real/README.md | 6 +-- kmath-functions/README.md | 6 +-- kmath-geometry/README.md | 6 +-- kmath-histograms/README.md | 6 +-- kmath-jafama/README.md | 6 +-- kmath-jupyter/README.md | 6 +-- kmath-kotlingrad/README.md | 6 +-- kmath-memory/README.md | 6 +-- kmath-multik/README.md | 6 +-- kmath-nd4j/README.md | 6 +-- kmath-optimization/README.md | 6 +-- kmath-polynomial/README.md | 50 +++++++++++++++++++ kmath-polynomial/build.gradle.kts | 43 +++++++++++++++- .../kmath/functions}/LabeledPolynomial.kt | 0 .../functions}/LabeledRationalFunction.kt | 0 .../kmath/functions}/ListPolynomial.kt | 0 .../kmath/functions}/ListRationalFunction.kt | 0 .../kmath/functions}/NumberedPolynomial.kt | 0 .../functions}/NumberedRationalFunction.kt | 0 .../kscience/kmath/functions}/Polynomial.kt | 0 .../kmath/functions}/RationalFunction.kt | 0 .../kmath/functions}/algebraicStub.kt | 0 .../kmath/functions}/collectionUtils.kt | 0 .../kmath/functions}/labeledConstructors.kt | 0 .../kscience/kmath/functions}/labeledUtil.kt | 0 .../kmath/functions}/listConstructors.kt | 0 .../kscience/kmath/functions}/listUtil.kt | 0 .../kscience/kmath/functions}/misc.kt | 0 .../kmath/functions}/numberedConstructors.kt | 0 .../kscience/kmath/functions}/numberedUtil.kt | 0 kmath-stat/README.md | 6 +-- kmath-symja/README.md | 6 +-- kmath-tensorflow/README.md | 6 +-- kmath-tensors/README.md | 6 +-- kmath-viktor/README.md | 6 +-- 43 files changed, 192 insertions(+), 74 deletions(-) create mode 100644 kmath-polynomial/README.md rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/LabeledPolynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/LabeledRationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/ListPolynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/ListRationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/NumberedPolynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/NumberedRationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/Polynomial.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/RationalFunction.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/algebraicStub.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/collectionUtils.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/labeledConstructors.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/labeledUtil.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/listConstructors.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/listUtil.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/misc.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/numberedConstructors.kt (100%) rename kmath-polynomial/src/commonMain/kotlin/{space.kscience.kmath.functions => space/kscience/kmath/functions}/numberedUtil.kt (100%) diff --git a/README.md b/README.md index 8353d341b..39cbf19c9 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ module definitions below. The module stability could have the following levels: > **Maturity**: PROTOTYPE > > **Features:** -> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers -> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions +> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations +> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition ### [kmath-core](kmath-core) @@ -214,6 +214,28 @@ One can still use generic algebras though. > > **Maturity**: EXPERIMENTAL +### [kmath-polynomial](kmath-polynomial) +> +> +> **Maturity**: PROTOTYPE +> +> **Features:** +> - [polynomial abstraction](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Abstraction for polynomial spaces. +> - [rational function abstraction](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt) : Abstraction for rational functions spaces. +> - ["list" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt) : List implementation of univariate polynomials. +> - ["list" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt) : List implementation of univariate rational functions. +> - ["list" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt) : Constructors for list polynomials and rational functions. +> - ["list" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt) : Utilities for list polynomials and rational functions. +> - ["numbered" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt) : Numbered implementation of multivariate polynomials. +> - ["numbered" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt) : Numbered implementation of multivariate rational functions. +> - ["numbered" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt) : Constructors for numbered polynomials and rational functions. +> - ["numbered" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt) : Utilities for numbered polynomials and rational functions. +> - ["labeled" polynomials](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt) : Labeled implementation of multivariate polynomials. +> - ["labeled" rational functions](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt) : Labeled implementation of multivariate rational functions. +> - ["labeled" polynomials and rational functions constructors](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt) : Constructors for labeled polynomials and rational functions. +> - ["labeled" polynomials and rational functions utilities](kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt) : Utilities for labeled polynomials and rational functions. + + ### [kmath-stat](kmath-stat) > > @@ -245,6 +267,11 @@ One can still use generic algebras though. > > **Maturity**: DEVELOPMENT +### [test-utils](test-utils) +> +> +> **Maturity**: EXPERIMENTAL + ## Multi-platform support diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 553c60bb3..c6da64982 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0' + implementation 'space.kscience:kmath-ast:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0") + implementation("space.kscience:kmath-ast:0.3.1-dev-1") } ``` diff --git a/kmath-commons/README.md b/kmath-commons/README.md index 7195e6fb1..89f1f6c9f 100644 --- a/kmath-commons/README.md +++ b/kmath-commons/README.md @@ -6,7 +6,7 @@ Commons math binding for kmath ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-commons:0.3.0' + implementation 'space.kscience:kmath-commons:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-commons:0.3.0") + implementation("space.kscience:kmath-commons:0.3.1-dev-1") } ``` diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 4646c6a80..f00952065 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -2,13 +2,13 @@ Complex and hypercomplex number systems in KMath. - - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers - - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions + - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations + - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0' + implementation 'space.kscience:kmath-complex:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0") + implementation("space.kscience:kmath-complex:0.3.1-dev-1") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index 4fddd327c..e84ca38d7 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0' + implementation 'space.kscience:kmath-core:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0") + implementation("space.kscience:kmath-core:0.3.1-dev-1") } ``` diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md index d0fef6e0f..337d8e037 100644 --- a/kmath-coroutines/README.md +++ b/kmath-coroutines/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-coroutines:0.3.0' + implementation 'space.kscience:kmath-coroutines:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-coroutines:0.3.0") + implementation("space.kscience:kmath-coroutines:0.3.1-dev-1") } ``` diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md index 650bcafde..12aa2a7fa 100644 --- a/kmath-dimensions/README.md +++ b/kmath-dimensions/README.md @@ -6,7 +6,7 @@ A proof of concept module for adding type-safe dimensions to structures ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-dimensions:0.3.0' + implementation 'space.kscience:kmath-dimensions:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-dimensions:0.3.0") + implementation("space.kscience:kmath-dimensions:0.3.1-dev-1") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index eaa90120f..2d6c661e4 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0' + implementation 'space.kscience:kmath-ejml:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0") + implementation("space.kscience:kmath-ejml:0.3.1-dev-1") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 9e8f95a16..5a8376976 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0' + implementation 'space.kscience:kmath-for-real:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0") + implementation("space.kscience:kmath-for-real:0.3.1-dev-1") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3f44bd3f9..1292424b5 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0' + implementation 'space.kscience:kmath-functions:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0") + implementation("space.kscience:kmath-functions:0.3.1-dev-1") } ``` diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md index 6602f5510..72d275697 100644 --- a/kmath-geometry/README.md +++ b/kmath-geometry/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-geometry:0.3.0' + implementation 'space.kscience:kmath-geometry:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-geometry:0.3.0") + implementation("space.kscience:kmath-geometry:0.3.1-dev-1") } ``` diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md index 27f1b43ec..5fd91ee0c 100644 --- a/kmath-histograms/README.md +++ b/kmath-histograms/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-histograms:0.3.0' + implementation 'space.kscience:kmath-histograms:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-histograms:0.3.0") + implementation("space.kscience:kmath-histograms:0.3.1-dev-1") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index fe6afb835..c008c76ca 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0' + implementation 'space.kscience:kmath-jafama:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0") + implementation("space.kscience:kmath-jafama:0.3.1-dev-1") } ``` diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md index db58ad840..3c9832625 100644 --- a/kmath-jupyter/README.md +++ b/kmath-jupyter/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jupyter:0.3.0' + implementation 'space.kscience:kmath-jupyter:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jupyter:0.3.0") + implementation("space.kscience:kmath-jupyter:0.3.1-dev-1") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 52e8b3116..457652aaf 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0' + implementation 'space.kscience:kmath-kotlingrad:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0") + implementation("space.kscience:kmath-kotlingrad:0.3.1-dev-1") } ``` diff --git a/kmath-memory/README.md b/kmath-memory/README.md index 9f4520bd8..536d7f145 100644 --- a/kmath-memory/README.md +++ b/kmath-memory/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-memory:0.3.0' + implementation 'space.kscience:kmath-memory:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-memory:0.3.0") + implementation("space.kscience:kmath-memory:0.3.1-dev-1") } ``` diff --git a/kmath-multik/README.md b/kmath-multik/README.md index edfce6f79..0f5b65b4c 100644 --- a/kmath-multik/README.md +++ b/kmath-multik/README.md @@ -6,7 +6,7 @@ JetBrains Multik connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-multik:0.3.0' + implementation 'space.kscience:kmath-multik:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-multik:0.3.0") + implementation("space.kscience:kmath-multik:0.3.1-dev-1") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 0bcae138e..bb065a300 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0' + implementation 'space.kscience:kmath-nd4j:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0") + implementation("space.kscience:kmath-nd4j:0.3.1-dev-1") } ``` diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md index 63e0f43e3..d7441ebd1 100644 --- a/kmath-optimization/README.md +++ b/kmath-optimization/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-optimization:0.3.0' + implementation 'space.kscience:kmath-optimization:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-optimization:0.3.0") + implementation("space.kscience:kmath-optimization:0.3.1-dev-1") } ``` diff --git a/kmath-polynomial/README.md b/kmath-polynomial/README.md new file mode 100644 index 000000000..640ea8876 --- /dev/null +++ b/kmath-polynomial/README.md @@ -0,0 +1,50 @@ +# Module kmath-polynomial + +Polynomial extra utilities and rational functions + +## Features + + - [polynomial abstraction](src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Abstraction for polynomial spaces. + - [rational function abstraction](src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt) : Abstraction for rational functions spaces. + - ["list" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt) : List implementation of univariate polynomials. + - ["list" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt) : List implementation of univariate rational functions. + - ["list" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt) : Constructors for list polynomials and rational functions. + - ["list" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt) : Utilities for list polynomials and rational functions. + - ["numbered" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt) : Numbered implementation of multivariate polynomials. + - ["numbered" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt) : Numbered implementation of multivariate rational functions. + - ["numbered" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt) : Constructors for numbered polynomials and rational functions. + - ["numbered" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt) : Utilities for numbered polynomials and rational functions. + - ["labeled" polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt) : Labeled implementation of multivariate polynomials. + - ["labeled" rational functions](src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt) : Labeled implementation of multivariate rational functions. + - ["labeled" polynomials and rational functions constructors](src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt) : Constructors for labeled polynomials and rational functions. + - ["labeled" polynomials and rational functions utilities](src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt) : Utilities for labeled polynomials and rational functions. + + +## Usage + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-polynomial:0.3.1-dev-1`. + +**Gradle Groovy:** +```groovy +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-polynomial:0.3.1-dev-1' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-polynomial:0.3.1-dev-1") +} +``` diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index 85b87fb34..dd0d9e77d 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -22,5 +22,46 @@ readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) -// feature("TODO") { "TODO" } + feature("polynomial abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt") { + "Abstraction for polynomial spaces." + } + feature("rational function abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt") { + "Abstraction for rational functions spaces." + } + feature("\"list\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt") { + "List implementation of univariate polynomials." + } + feature("\"list\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt") { + "List implementation of univariate rational functions." + } + feature("\"list\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt") { + "Constructors for list polynomials and rational functions." + } + feature("\"list\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt") { + "Utilities for list polynomials and rational functions." + } + feature("\"numbered\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt") { + "Numbered implementation of multivariate polynomials." + } + feature("\"numbered\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt") { + "Numbered implementation of multivariate rational functions." + } + feature("\"numbered\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt") { + "Constructors for numbered polynomials and rational functions." + } + feature("\"numbered\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt") { + "Utilities for numbered polynomials and rational functions." + } + feature("\"labeled\" polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt") { + "Labeled implementation of multivariate polynomials." + } + feature("\"labeled\" rational functions", "src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt") { + "Labeled implementation of multivariate rational functions." + } + feature("\"labeled\" polynomials and rational functions constructors", "src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt") { + "Constructors for labeled polynomials and rational functions." + } + feature("\"labeled\" polynomials and rational functions utilities", "src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt") { + "Utilities for labeled polynomials and rational functions." + } } diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/LabeledRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/ListRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedPolynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/NumberedRationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/Polynomial.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/RationalFunction.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/algebraicStub.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/collectionUtils.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/labeledUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/listUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/misc.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedConstructors.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt diff --git a/kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt similarity index 100% rename from kmath-polynomial/src/commonMain/kotlin/space.kscience.kmath.functions/numberedUtil.kt rename to kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt diff --git a/kmath-stat/README.md b/kmath-stat/README.md index 80c6e0fcd..7ed20fcf4 100644 --- a/kmath-stat/README.md +++ b/kmath-stat/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-stat:0.3.0' + implementation 'space.kscience:kmath-stat:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-stat:0.3.0") + implementation("space.kscience:kmath-stat:0.3.1-dev-1") } ``` diff --git a/kmath-symja/README.md b/kmath-symja/README.md index ea2d5d68f..a96b0e835 100644 --- a/kmath-symja/README.md +++ b/kmath-symja/README.md @@ -6,7 +6,7 @@ Symja integration module ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-symja:0.3.0' + implementation 'space.kscience:kmath-symja:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-symja:0.3.0") + implementation("space.kscience:kmath-symja:0.3.1-dev-1") } ``` diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md index 7852c07be..83f2eb315 100644 --- a/kmath-tensorflow/README.md +++ b/kmath-tensorflow/README.md @@ -6,7 +6,7 @@ Google tensorflow connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensorflow:0.3.0' + implementation 'space.kscience:kmath-tensorflow:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensorflow:0.3.0") + implementation("space.kscience:kmath-tensorflow:0.3.1-dev-1") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 44ee47675..4208cd83d 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0' + implementation 'space.kscience:kmath-tensors:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0") + implementation("space.kscience:kmath-tensors:0.3.1-dev-1") } ``` diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md index 5d7c2dea1..abff20427 100644 --- a/kmath-viktor/README.md +++ b/kmath-viktor/README.md @@ -6,7 +6,7 @@ Binding for https://github.com/JetBrains-Research/viktor ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-viktor:0.3.0' + implementation 'space.kscience:kmath-viktor:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-viktor:0.3.0") + implementation("space.kscience:kmath-viktor:0.3.1-dev-1") } ``` From 163a7c717a922b8f670475ad489184dd28716c11 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 08:28:47 +0300 Subject: [PATCH 149/174] Fix description. --- kmath-polynomial/README.md | 2 +- kmath-polynomial/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-polynomial/README.md b/kmath-polynomial/README.md index 640ea8876..a5078a7e0 100644 --- a/kmath-polynomial/README.md +++ b/kmath-polynomial/README.md @@ -1,6 +1,6 @@ # Module kmath-polynomial -Polynomial extra utilities and rational functions +Polynomials, rational functions, and utilities ## Features diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index dd0d9e77d..9c5083d2d 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -4,7 +4,7 @@ plugins { id("ru.mipt.npm.gradle.native") } -description = "Polynomial extra utilities and rational functions" +description = "Polynomials, rational functions, and utilities" kotlin.sourceSets { commonMain { From fe4eb96daed13a30d9c7f328fa49d2daefe9a2f5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 19:09:20 +0300 Subject: [PATCH 150/174] Add docs. --- .../kmath/functions/collectionUtils.kt | 451 ++++++++++++++++-- 1 file changed, 412 insertions(+), 39 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt index ee32aa9a7..0d2ea3653 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt @@ -9,7 +9,13 @@ import kotlin.contracts.InvocationKind.* import kotlin.contracts.contract -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or `null` if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the received value. + * @return result of the computation of the lambda. + */ internal inline fun Map.computeOn(key: K, compute: (V?) -> R): R { contract { callsInPlace(compute, EXACTLY_ONCE) @@ -17,7 +23,15 @@ internal inline fun Map.computeOn(key: K, compute: (V?) -> R) return compute(get(key)) } -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda + * [defaultResult] if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the value corresponding to the [key]. + * @param defaultResult lambda that is computed if the [key] is not present. + * @return result of [compute] lambda if the [key] is present or result of [defaultResult] otherwise. + */ internal inline fun Map.computeOnOrElse(key: K, defaultResult: () -> R, compute: (value: V) -> R): R { contract { callsInPlace(defaultResult, AT_MOST_ONCE) @@ -27,7 +41,15 @@ internal inline fun Map.computeOnOrElse(key: K, defaultResult: ( return (if (key !in this) defaultResult() else compute(get(key) as V)) } -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda + * [defaultResult] if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the value corresponding to the [key]. + * @param defaultResult default result that is returned in case of the [key]'s absence. + * @return result of [compute] lambda if the [key] is present or [defaultResult] otherwise. + */ internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (value: V) -> R): R { contract { callsInPlace(compute, AT_MOST_ONCE) @@ -35,7 +57,15 @@ internal inline fun Map.computeOnOrElse(key: K, defaultResult: R return computeOnOrElse(key, { defaultResult }, compute) } -// TODO: Docs +/** + * Computes the given lambda [compute] on value corresponding to the provided [key] or computes the given lambda + * [defaultResult] if the key is not present. + * + * @param key key which corresponding value will be used if it's present. + * @param compute lambda that is computed on the value corresponding to the [key]. + * @param defaultResult default result that is returned in case of the [key]'s absence. + * @return result of [compute] lambda if the [key] is present or [defaultResult] otherwise. + */ internal inline fun Map.computeOnOrElse(key: K, defaultResult: R, compute: (key: K, value: V) -> R): R { contract { callsInPlace(compute, AT_MOST_ONCE) @@ -374,8 +404,20 @@ internal inline fun > Map.copyMapToBy(des internal inline fun > Map.copyMapToBy(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: V) -> W): D = copyMapToBy(destination, { (key, value) -> transform(key, value) }, { _, currentValue, newValue -> resolve(currentValue, newValue) }) -// TODO: Docs -internal fun > mergeTo(map1: Map, map2: Map, destination: D): D { +/** + * Merges [the first map][map1] and [the second map][map2] prioritising the second one, puts result to the [destination] + * and returns the [destination]. + * + * Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values + * in the [destination] if needed. For every key appearing in both maps corresponding value from the second map is + * chosen. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param destination the map where result of the merge is put. + * @return the destination. + */ +internal fun > mergeTo(map1: Map, map2: Map, destination: D): D { for ((key, value) in map1) { destination.put(key, value) } @@ -385,7 +427,20 @@ internal fun > mergeTo(map1: Map, map2: Map< return destination } -// TODO: Docs +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda, puts result to the + * [destination] and returns the [destination]. + * + * Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values + * in the [destination] if needed. For every key appearing in both maps corresponding value is a result of the [resolve] + * lambda calculated on the key and its corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @param destination the map where result of the merge is put. + * @return the destination. + */ internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (key: K, value1: V1, value2: V2) -> W): D { for (key in map2.keys) { destination.remove(key) @@ -400,27 +455,82 @@ internal inline fun > mergeToBy(map1: Ma return destination } -// TODO: Docs +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda, puts result to the + * [destination] and returns the [destination]. + * + * Precisely, corresponding keys and values of the received maps are put into the destination overriding existing values + * in the [destination] if needed. For every key appearing in both maps corresponding value is a result of the [resolve] + * lambda calculated on the key's corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @param destination the map where result of the merge is put. + * @return the destination. + */ internal inline fun > mergeToBy(map1: Map, map2: Map, destination: D, resolve: (value1: V1, value2: V2) -> W): D = mergeToBy(map1, map2, destination) { _, value1, value2 -> resolve(value1, value2) } -// TODO: Docs +/** + * Merges [the first map][map1] and [the second map][map2] prioritising the second one. + * + * Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after + * afterwards. For every key appearing in both maps corresponding value from the second map is chosen. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @return the result of the merge. + */ internal fun merge(map1: Map, map2: Map): Map { val result = LinkedHashMap(map1.size + map2.size) return mergeTo(map1, map2, result) } -// TODO: Docs -internal inline fun mergeBy(map1: Map, map2: Map, transform: (key: K, value1: V1, value2: V2) -> W): Map { +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda. + * + * Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after + * afterwards. For every key appearing in both maps corresponding value is a result of the [resolve] lambda calculated + * on the key and its corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @return the result of the merge. + */ +internal inline fun mergeBy(map1: Map, map2: Map, resolve: (key: K, value1: V1, value2: V2) -> W): Map { val result = LinkedHashMap(map1.size + map2.size) - return mergeToBy(map1, map2, result, transform) + return mergeToBy(map1, map2, result, resolve) } -// TODO: Docs -internal inline fun mergeBy(map1: Map, map2: Map, transform: (value1: V1, value2: V2) -> W): Map = - mergeBy(map1, map2) { _, value1, value2 -> transform(value1, value2) } +/** + * Merges [the first map][map1] and [the second map][map2] resolving conflicts with [resolve] lambda. + * + * Precisely, corresponding keys and values of the received maps are put into a new empty map which is returned after + * afterwards. For every key appearing in both maps corresponding value is a result of the [resolve] lambda calculated + * on the key's corresponding values from the merged maps. + * + * @param map1 the first (less prioritised) map to merge. + * @param map2 the second (more prioritised) map to merge. + * @param resolve lambda function that resolves merge conflicts. + * @return the result of the merge. + */ +internal inline fun mergeBy(map1: Map, map2: Map, resolve: (value1: V1, value2: V2) -> W): Map = + mergeBy(map1, map2) { _, value1, value2 -> resolve(value1, value2) } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs provided by [transform] function applied to each element of the + * given collection resolving conflicts with [resolve] function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each element to key-value. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): D { for (element in this) { val (key, value) = transform(element) @@ -429,7 +539,20 @@ internal inline fun > Iterable.associateTo(dest return destination } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function and value is + * provided by [valueTransform] applied to each element of the given collection, resolving conflicts with [resolve] + * function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): D { for (element in this) { val key = keySelector(element) @@ -439,7 +562,19 @@ internal inline fun > Iterable.associateByTo(de return destination } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function applied to each + * element of the given collection and value is the element itself, resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): D { for (element in this) { val key = keySelector(element) @@ -448,86 +583,324 @@ internal inline fun > Iterable.associateByTo(desti return destination } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs provided by [transform] function applied to each element of the + * given collection resolving conflicts with [resolve] function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each element to key-value pair. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateTo(destination: D, transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): D = associateTo(destination, transform) { _, currentValue, newValue -> resolve(currentValue, newValue) } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function and value is + * provided by [valueTransform] applied to each element of the given collection, resolving conflicts with [resolve] + * function and returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): D = associateByTo(destination, keySelector, valueTransform) { _, currentValue, newValue -> resolve(currentValue, newValue) } -// TODO: Docs +/** + * Populates the [destination] map with key-value pairs, where key is provided by [keySelector] function applied to each + * element of the given collection and value is the element itself, resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Iterable.associateByTo(destination: D, keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): D = associateByTo(destination, keySelector) { _, currentValue, newValue -> resolve(currentValue, newValue) } -// TODO: Docs +/** + * Returns a map containing key-value pairs provided by [transform] function applied to elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with the + * key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new value + * from the pair. + * + * @param transform function which transforms each element to key-value pair. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = associateTo(LinkedHashMap(), transform, resolve) -// TODO: Docs +/** + * Returns a map containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to + * elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new + * value from the pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (key: K, currentValue: V, newValue: V) -> V): Map = associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) -// TODO: Docs +/** + * Returns a map containing the elements from the given collection indexed by the key returned from [keySelector] + * function applied to each element. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes the key, current value corresponding to the key, and new + * value from the pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (key: K, currentValue: T, newValue: T) -> T): Map = associateByTo(LinkedHashMap(), keySelector, resolve) -// TODO: Docs +/** + * Returns a map containing key-value pairs provided by [transform] function applied to elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the + * pair. + * + * @param transform function which transforms each element to key-value pair. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associate(transform: (T) -> Pair, resolve: (currentValue: V, newValue: V) -> V): Map = associateTo(LinkedHashMap(), transform, resolve) -// TODO: Docs +/** + * Returns a map containing the values provided by [valueTransform] and indexed by [keySelector] functions applied to + * elements of the given collection. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the + * pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param valueTransform lambda functions that generates value for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, valueTransform: (T) -> V, resolve: (currentValue: V, newValue: V) -> V): Map = associateByTo(LinkedHashMap(), keySelector, valueTransform, resolve) -// TODO: Docs +/** + * Returns a map containing the elements from the given collection indexed by the key returned from [keySelector] + * function applied to each element. + * + * All pairs are added in order of iteration. If some key is already added to the map, adding new key-value pair with + * the key is resolved with [resolve] function which takes current value corresponding to the key and new value from the + * pair. + * + * @param keySelector lambda functions that generates keys for the key-value pairs. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Iterable.associateBy(keySelector: (T) -> K, resolve: (currentValue: T, newValue: T) -> T): Map = associateByTo(LinkedHashMap(), keySelector, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, transform, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (key: K, currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (Map.Entry) -> W, resolve: (currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, transform, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys of this map and the values obtained + * by applying the [transform] function to each entry in this map resolving conflicts with [resolve] function and + * returns the [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new value. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapValuesTo(destination: D, transform: (key: K, value: V) -> W, resolve: (currentValue: W, newValue: W) -> W): D = entries.associateByTo(destination, { it.key }, { (key, value) -> transform(key, value) }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, transform, { it.value }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, transform, { it.value }, resolve) -// TODO: Docs +/** + * Populates the given [destination] map with entries having the keys obtained by applying the [transform] function to + * each entry in this map and the values of this map, resolving conflicts with [resolve] function and returns the + * [destination]. + * + * All pairs are added and resolved in order of iteration. + * + * @param destination the destination of the generated key-value pairs. + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the [destination]. + */ internal inline fun > Map.mapKeysTo(destination: D, transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): D = entries.associateByTo(destination, { (key, value) -> transform(key, value) }, { it.value }, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which receives some key, its current, and new + * corresponding values. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (key: L, currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (Map.Entry) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) -// TODO: Docs +/** + * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this + * map and the values of this map and resolving conflicts with [resolve] function.. + * + * All pairs are added and resolved in order of iteration. + * + * @param transform function which transforms each key-value pair to new key. + * @param resolve lambda function that resolves merge conflicts which current and new values corresponding to some key. + * @return the result map. + */ internal inline fun Map.mapKeys(transform: (key: K, value: V) -> L, resolve: (currentValue: V, newValue: V) -> V): Map = mapKeysTo(LinkedHashMap(size), transform, resolve) \ No newline at end of file From e1b8fcdbbf78d13a04aa0602e2f341d420f8b103 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 20 Jul 2022 19:10:35 +0300 Subject: [PATCH 151/174] Two consecutive dots... --- .../kotlin/space/kscience/kmath/functions/collectionUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt index 0d2ea3653..c9146a493 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt @@ -894,7 +894,7 @@ internal inline fun Map.mapKeys(transform: (Map.Entry) /** * Returns a new map with entries having the keys obtained by applying the [transform] function to each entry in this - * map and the values of this map and resolving conflicts with [resolve] function.. + * map and the values of this map and resolving conflicts with [resolve] function. * * All pairs are added and resolved in order of iteration. * From 0c6ad35c13ecf6bff31170092685e71ce016f1b5 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Sat, 23 Jul 2022 10:24:52 +0300 Subject: [PATCH 152/174] Simplify the version catalog usage. --- kmath-functions/build.gradle.kts | 2 +- kmath-polynomial/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index eec17e82b..337875ba4 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -15,7 +15,7 @@ kotlin.sourceSets { } dependencies { - dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${npmlibs.versions.dokka.get()}") } readme { diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index 9c5083d2d..5e66f83ec 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -15,7 +15,7 @@ kotlin.sourceSets { } dependencies { - dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${versionCatalogs.named("npmlibs").findVersion("dokka").get().requiredVersion}") + dokkaPlugin("org.jetbrains.dokka:mathjax-plugin:${npmlibs.versions.dokka.get()}") } readme { From 1e8a8cac7efa0d10495aca413ed3c5fa82c6fba1 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 24 Jul 2022 12:01:02 +0300 Subject: [PATCH 153/174] Fix readme --- .github/CODEOWNERS | 3 +++ .space/CODEOWNERS | 0 README.md | 19 ++++++++++++++----- docs/templates/README-TEMPLATE.md | 12 ++---------- kmath-ast/README.md | 6 +++--- kmath-commons/README.md | 6 +++--- kmath-complex/README.md | 10 +++++----- kmath-core/README.md | 6 +++--- kmath-coroutines/README.md | 6 +++--- kmath-dimensions/README.md | 6 +++--- kmath-ejml/README.md | 6 +++--- kmath-for-real/README.md | 6 +++--- kmath-functions/README.md | 6 +++--- kmath-geometry/README.md | 6 +++--- kmath-histograms/README.md | 6 +++--- kmath-jafama/README.md | 6 +++--- kmath-jupyter/README.md | 6 +++--- kmath-kotlingrad/README.md | 6 +++--- kmath-memory/README.md | 6 +++--- kmath-multik/README.md | 6 +++--- kmath-nd4j/README.md | 6 +++--- kmath-optimization/README.md | 6 +++--- kmath-stat/README.md | 6 +++--- kmath-symja/README.md | 6 +++--- kmath-tensorflow/README.md | 6 +++--- kmath-tensors/README.md | 6 +++--- kmath-trajectory/README.md | 12 +++++++----- kmath-trajectory/build.gradle.kts | 2 ++ kmath-trajectory/docs/README-TEMPLATE.md | 13 +++++++++++++ kmath-viktor/README.md | 6 +++--- 30 files changed, 112 insertions(+), 91 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .space/CODEOWNERS create mode 100644 kmath-trajectory/docs/README-TEMPLATE.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..7273b6a50 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +@altavir + +/kmath-trajectory @ESchouten \ No newline at end of file diff --git a/.space/CODEOWNERS b/.space/CODEOWNERS new file mode 100644 index 000000000..e69de29bb diff --git a/README.md b/README.md index 8353d341b..63238f320 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ module definitions below. The module stability could have the following levels: > **Maturity**: PROTOTYPE > > **Features:** -> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers -> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions +> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations +> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition ### [kmath-core](kmath-core) @@ -240,11 +240,21 @@ One can still use generic algebras though. > - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. +### [kmath-trajectory](kmath-trajectory) +> Path and trajectory optimization +> +> **Maturity**: PROTOTYPE + ### [kmath-viktor](kmath-viktor) > > > **Maturity**: DEVELOPMENT +### [test-utils](test-utils) +> +> +> **Maturity**: EXPERIMENTAL + ## Multi-platform support @@ -261,8 +271,7 @@ performance and flexibility. We expect to focus on creating convenient universal API first and then work on increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be -better than SciPy. +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. ## Requirements @@ -294,4 +303,4 @@ Gradle `6.0+` is required for multiplatform artifacts. The project requires a lot of additional work. The most important thing we need is a feedback about what features are required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues marked with -[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. +[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index b8446a76f..1633f3ff1 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -69,8 +69,7 @@ performance and flexibility. We expect to focus on creating convenient universal API first and then work on increasing performance for specific cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be -better than SciPy. +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. ## Requirements @@ -102,11 +101,4 @@ Gradle `6.0+` is required for multiplatform artifacts. The project requires a lot of additional work. The most important thing we need is a feedback about what features are required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues marked with -[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. - -## Author -Erik Schouten - -Github: ESchouten - -Email: erik-schouten@hotmail.nl +[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 553c60bb3..c6da64982 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0' + implementation 'space.kscience:kmath-ast:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0") + implementation("space.kscience:kmath-ast:0.3.1-dev-1") } ``` diff --git a/kmath-commons/README.md b/kmath-commons/README.md index 7195e6fb1..89f1f6c9f 100644 --- a/kmath-commons/README.md +++ b/kmath-commons/README.md @@ -6,7 +6,7 @@ Commons math binding for kmath ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-commons:0.3.0' + implementation 'space.kscience:kmath-commons:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-commons:0.3.0") + implementation("space.kscience:kmath-commons:0.3.1-dev-1") } ``` diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 4646c6a80..f00952065 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -2,13 +2,13 @@ Complex and hypercomplex number systems in KMath. - - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers - - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions + - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex numbers operations + - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions and their composition ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0' + implementation 'space.kscience:kmath-complex:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0") + implementation("space.kscience:kmath-complex:0.3.1-dev-1") } ``` diff --git a/kmath-core/README.md b/kmath-core/README.md index 4fddd327c..e84ca38d7 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,7 +15,7 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0' + implementation 'space.kscience:kmath-core:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0") + implementation("space.kscience:kmath-core:0.3.1-dev-1") } ``` diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md index d0fef6e0f..337d8e037 100644 --- a/kmath-coroutines/README.md +++ b/kmath-coroutines/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-coroutines:0.3.0' + implementation 'space.kscience:kmath-coroutines:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-coroutines:0.3.0") + implementation("space.kscience:kmath-coroutines:0.3.1-dev-1") } ``` diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md index 650bcafde..12aa2a7fa 100644 --- a/kmath-dimensions/README.md +++ b/kmath-dimensions/README.md @@ -6,7 +6,7 @@ A proof of concept module for adding type-safe dimensions to structures ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-dimensions:0.3.0' + implementation 'space.kscience:kmath-dimensions:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-dimensions:0.3.0") + implementation("space.kscience:kmath-dimensions:0.3.1-dev-1") } ``` diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index eaa90120f..2d6c661e4 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0' + implementation 'space.kscience:kmath-ejml:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0") + implementation("space.kscience:kmath-ejml:0.3.1-dev-1") } ``` diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 9e8f95a16..5a8376976 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0' + implementation 'space.kscience:kmath-for-real:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0") + implementation("space.kscience:kmath-for-real:0.3.1-dev-1") } ``` diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 3f44bd3f9..1292424b5 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0' + implementation 'space.kscience:kmath-functions:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0") + implementation("space.kscience:kmath-functions:0.3.1-dev-1") } ``` diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md index 6602f5510..72d275697 100644 --- a/kmath-geometry/README.md +++ b/kmath-geometry/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-geometry:0.3.0' + implementation 'space.kscience:kmath-geometry:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-geometry:0.3.0") + implementation("space.kscience:kmath-geometry:0.3.1-dev-1") } ``` diff --git a/kmath-histograms/README.md b/kmath-histograms/README.md index 27f1b43ec..5fd91ee0c 100644 --- a/kmath-histograms/README.md +++ b/kmath-histograms/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-histograms:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-histograms:0.3.0' + implementation 'space.kscience:kmath-histograms:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-histograms:0.3.0") + implementation("space.kscience:kmath-histograms:0.3.1-dev-1") } ``` diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index fe6afb835..c008c76ca 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,7 +7,7 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -17,7 +17,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0' + implementation 'space.kscience:kmath-jafama:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0") + implementation("space.kscience:kmath-jafama:0.3.1-dev-1") } ``` diff --git a/kmath-jupyter/README.md b/kmath-jupyter/README.md index db58ad840..3c9832625 100644 --- a/kmath-jupyter/README.md +++ b/kmath-jupyter/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-jupyter:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-jupyter:0.3.0' + implementation 'space.kscience:kmath-jupyter:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jupyter:0.3.0") + implementation("space.kscience:kmath-jupyter:0.3.1-dev-1") } ``` diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 52e8b3116..457652aaf 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -8,7 +8,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0' + implementation 'space.kscience:kmath-kotlingrad:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0") + implementation("space.kscience:kmath-kotlingrad:0.3.1-dev-1") } ``` diff --git a/kmath-memory/README.md b/kmath-memory/README.md index 9f4520bd8..536d7f145 100644 --- a/kmath-memory/README.md +++ b/kmath-memory/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-memory:0.3.0' + implementation 'space.kscience:kmath-memory:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-memory:0.3.0") + implementation("space.kscience:kmath-memory:0.3.1-dev-1") } ``` diff --git a/kmath-multik/README.md b/kmath-multik/README.md index edfce6f79..0f5b65b4c 100644 --- a/kmath-multik/README.md +++ b/kmath-multik/README.md @@ -6,7 +6,7 @@ JetBrains Multik connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-multik:0.3.0' + implementation 'space.kscience:kmath-multik:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-multik:0.3.0") + implementation("space.kscience:kmath-multik:0.3.1-dev-1") } ``` diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 0bcae138e..bb065a300 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0' + implementation 'space.kscience:kmath-nd4j:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0") + implementation("space.kscience:kmath-nd4j:0.3.1-dev-1") } ``` diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md index 63e0f43e3..d7441ebd1 100644 --- a/kmath-optimization/README.md +++ b/kmath-optimization/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-optimization:0.3.0' + implementation 'space.kscience:kmath-optimization:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-optimization:0.3.0") + implementation("space.kscience:kmath-optimization:0.3.1-dev-1") } ``` diff --git a/kmath-stat/README.md b/kmath-stat/README.md index 80c6e0fcd..7ed20fcf4 100644 --- a/kmath-stat/README.md +++ b/kmath-stat/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-stat:0.3.0' + implementation 'space.kscience:kmath-stat:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-stat:0.3.0") + implementation("space.kscience:kmath-stat:0.3.1-dev-1") } ``` diff --git a/kmath-symja/README.md b/kmath-symja/README.md index ea2d5d68f..a96b0e835 100644 --- a/kmath-symja/README.md +++ b/kmath-symja/README.md @@ -6,7 +6,7 @@ Symja integration module ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-symja:0.3.0' + implementation 'space.kscience:kmath-symja:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-symja:0.3.0") + implementation("space.kscience:kmath-symja:0.3.1-dev-1") } ``` diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md index 7852c07be..83f2eb315 100644 --- a/kmath-tensorflow/README.md +++ b/kmath-tensorflow/README.md @@ -6,7 +6,7 @@ Google tensorflow connector ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensorflow:0.3.0' + implementation 'space.kscience:kmath-tensorflow:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensorflow:0.3.0") + implementation("space.kscience:kmath-tensorflow:0.3.1-dev-1") } ``` diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 44ee47675..4208cd83d 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,7 +9,7 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0' + implementation 'space.kscience:kmath-tensors:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0") + implementation("space.kscience:kmath-tensors:0.3.1-dev-1") } ``` diff --git a/kmath-trajectory/README.md b/kmath-trajectory/README.md index cb2b6989f..ac2930b04 100644 --- a/kmath-trajectory/README.md +++ b/kmath-trajectory/README.md @@ -1,12 +1,11 @@ -# Module kmath-trajectory +# kmath-trajectory -## Usage ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-trajectory:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-trajectory:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +15,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-trajectory:0.3.0' + implementation 'space.kscience:kmath-trajectory:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +26,9 @@ repositories { } dependencies { - implementation("space.kscience:kmath-trajectory:0.3.0") + implementation("space.kscience:kmath-trajectory:0.3.1-dev-1") } ``` + +## Contributors +Erik Schouten (github: @ESchouten, email: erik-schouten@hotmail.nl) diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts index 502867ee3..db80be02a 100644 --- a/kmath-trajectory/build.gradle.kts +++ b/kmath-trajectory/build.gradle.kts @@ -11,5 +11,7 @@ kotlin.sourceSets.commonMain { } readme { + description = "Path and trajectory optimization" maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) } diff --git a/kmath-trajectory/docs/README-TEMPLATE.md b/kmath-trajectory/docs/README-TEMPLATE.md new file mode 100644 index 000000000..eb8e4a0c0 --- /dev/null +++ b/kmath-trajectory/docs/README-TEMPLATE.md @@ -0,0 +1,13 @@ +# kmath-trajectory + + +${features} + +${artifact} + +## Author +Erik Schouten + +Github: ESchouten + +Email: erik-schouten@hotmail.nl diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md index 5d7c2dea1..abff20427 100644 --- a/kmath-viktor/README.md +++ b/kmath-viktor/README.md @@ -6,7 +6,7 @@ Binding for https://github.com/JetBrains-Research/viktor ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.0`. +The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.1-dev-1`. **Gradle Groovy:** ```groovy @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-viktor:0.3.0' + implementation 'space.kscience:kmath-viktor:0.3.1-dev-1' } ``` **Gradle Kotlin DSL:** @@ -27,6 +27,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-viktor:0.3.0") + implementation("space.kscience:kmath-viktor:0.3.1-dev-1") } ``` From 323e8b6872137eb6da1b8c91aff1ce8b4e8d31d7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 26 Jul 2022 09:19:04 +0300 Subject: [PATCH 154/174] Code simplification for Dubins path --- .../space/kscience/kmath/geometry/Circle2D.kt | 18 ++++ .../space/kscience/kmath/geometry/Line.kt | 4 + .../kmath/trajectory/dubins/DubinsPath.kt | 82 +++++++++-------- ...oryFunctions.kt => trajectoryFunctions.kt} | 41 +++++---- .../kscience/kmath/trajectory/segments/Arc.kt | 59 ------------ .../kmath/trajectory/segments/Pose2D.kt | 21 +++++ .../kmath/trajectory/segments/Segment.kt | 5 -- .../kmath/trajectory/segments/Straight.kt | 18 ---- .../kmath/trajectory/segments/Trajectory.kt | 89 +++++++++++++++++++ .../trajectory/segments/components/Circle.kt | 11 --- .../trajectory/segments/components/Pose2D.kt | 13 --- .../space/kscience/kmath/trajectory/Math.kt | 10 +-- .../kmath/trajectory/dubins/DubinsTests.kt | 16 ++-- .../kmath/trajectory/segments/ArcTests.kt | 7 +- .../segments/{components => }/CircleTests.kt | 6 +- .../kmath/trajectory/segments/LineTests.kt | 12 +-- 16 files changed, 225 insertions(+), 187 deletions(-) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt rename kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/{TrajectoryFunctions.kt => trajectoryFunctions.kt} (51%) delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt rename kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/{components => }/CircleTests.kt (74%) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt new file mode 100644 index 000000000..8623335b9 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -0,0 +1,18 @@ +/* + * 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.geometry + +import kotlin.math.PI + +/** + * A circle in 2D space + */ +public class Circle2D( + public val center: Vector2D, + public val radius: Double +) + +public val Circle2D.circumference: Double get() = radius * 2 * PI diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index 8c6ccb55e..85bfcdd8f 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -5,6 +5,10 @@ package space.kscience.kmath.geometry +/** + * A line formed by [base] vector of start and a [direction] vector. Direction vector is not necessarily normalized, + * but its length does not affect line properties + */ public data class Line(val base: V, val direction: V) public typealias Line2D = Line diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt index ee4f38662..f510e3572 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt @@ -5,91 +5,95 @@ package space.kscience.kmath.trajectory.dubins +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Arc -import space.kscience.kmath.trajectory.segments.Segment -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.ArcSegment +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment +import space.kscience.kmath.trajectory.segments.Trajectory import kotlin.math.acos import kotlin.math.cos import kotlin.math.sin public class DubinsPath( - public val a: Arc, - public val b: Segment, - public val c: Arc, -) { + public val a: ArcSegment, + public val b: Trajectory, + public val c: ArcSegment, +) : Trajectory { public val type: TYPE = TYPE.valueOf( arrayOf( a.direction.name[0], - if (b is Arc) b.direction.name[0] else 'S', + if (b is ArcSegment) b.direction.name[0] else 'S', c.direction.name[0] ).toCharArray().concatToString() ) - public val length: Double = a.length + b.length + c.length + override val length: Double get() = a.length + b.length + c.length public enum class TYPE { RLR, LRL, RSR, LSL, RSL, LSR } public companion object { - public fun all(start: Pose2D, end: Pose2D, turningRadius: Double): List = - listOfNotNull( - rlr(start, end, turningRadius), - lrl(start, end, turningRadius), - rsr(start, end, turningRadius), - lsl(start, end, turningRadius), - rsl(start, end, turningRadius), - lsr(start, end, turningRadius) - ) + public fun all( + start: Pose2D, + end: Pose2D, + turningRadius: Double, + ): List = listOfNotNull( + rlr(start, end, turningRadius), + lrl(start, end, turningRadius), + rsr(start, end, turningRadius), + lsl(start, end, turningRadius), + rsl(start, end, turningRadius), + lsr(start, end, turningRadius) + ) + public fun shortest(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath = - all(start, end, turningRadius).minByOrNull { it.length }!! + all(start, end, turningRadius).minBy { it.length } public fun rlr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) - val centers = Straight(c1.center, c2.center) + val centers = StraightSegment(c1.center, c2.center) if (centers.length > turningRadius * 4) return null var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) + val e = Circle2D(p, turningRadius) val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc.of(c1.center, start, p1, Arc.Direction.RIGHT) - val a2 = Arc.of(e.center, p1, p2, Arc.Direction.LEFT) - val a3 = Arc.of(c2.center, p2, end, Arc.Direction.RIGHT) + val a1 = ArcSegment.of(c1.center, start, p1, ArcSegment.Direction.RIGHT) + val a2 = ArcSegment.of(e.center, p1, p2, ArcSegment.Direction.LEFT) + val a3 = ArcSegment.of(c2.center, p2, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, a2, a3) } public fun lrl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) - val centers = Straight(c1.center, c2.center) + val centers = StraightSegment(c1.center, c2.center) if (centers.length > turningRadius * 4) return null var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) - val e = Circle(p, turningRadius) + val e = Circle2D(p, turningRadius) val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) val p2 = Vector2D(e.center.x + dX, e.center.y + dY) - val a1 = Arc.of(c1.center, start, p1, Arc.Direction.LEFT) - val a2 = Arc.of(e.center, p1, p2, Arc.Direction.RIGHT) - val a3 = Arc.of(c2.center, p2, end, Arc.Direction.LEFT) + val a1 = ArcSegment.of(c1.center, start, p1, ArcSegment.Direction.LEFT) + val a2 = ArcSegment.of(e.center, p1, p2, ArcSegment.Direction.RIGHT) + val a3 = ArcSegment.of(c2.center, p2, end, ArcSegment.Direction.LEFT) return DubinsPath(a1, a2, a3) } @@ -97,8 +101,8 @@ public class DubinsPath( val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = leftOuterTangent(c1, c2) - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.RIGHT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.RIGHT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, s, a3) } @@ -106,8 +110,8 @@ public class DubinsPath( val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = rightOuterTangent(c1, c2) - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.LEFT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.LEFT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.LEFT) return DubinsPath(a1, s, a3) } @@ -117,8 +121,8 @@ public class DubinsPath( val s = rightInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.RIGHT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.LEFT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.RIGHT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.LEFT) return DubinsPath(a1, s, a3) } @@ -128,8 +132,8 @@ public class DubinsPath( val s = leftInnerTangent(c1, c2) if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null - val a1 = Arc.of(c1.center, start, s.start, Arc.Direction.LEFT) - val a3 = Arc.of(c2.center, s.end, end, Arc.Direction.RIGHT) + val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.LEFT) + val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, s, a3) } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt similarity index 51% rename from kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt rename to kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt index 547cb99fc..18384d349 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/TrajectoryFunctions.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt @@ -5,10 +5,10 @@ package space.kscience.kmath.trajectory.dubins +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos @@ -18,18 +18,19 @@ private enum class SIDE { LEFT, RIGHT } -internal fun Pose2D.getLeftCircle(radius: Double): Circle = getTangentCircles(radius).first -internal fun Pose2D.getRightCircle(radius: Double): Circle = getTangentCircles(radius).second -internal fun Pose2D.getTangentCircles(radius: Double): Pair { +internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first +internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second +internal fun Pose2D.getTangentCircles(radius: Double): Pair { val dX = radius * cos(theta) val dY = radius * sin(theta) - return Circle(Vector2D(x - dX, y + dY), radius) to Circle(Vector2D(x + dX, y - dY), radius) + return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) } -internal fun leftOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.LEFT) -internal fun rightOuterTangent(a: Circle, b: Circle) = outerTangent(a, b, SIDE.RIGHT) -private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { - val centers = Straight(a.center, b.center) +internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.LEFT) +internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.RIGHT) + +private fun outerTangent(a: Circle2D, b: Circle2D, side: SIDE): StraightSegment { + val centers = StraightSegment(a.center, b.center) val p1 = when (side) { SIDE.LEFT -> Vector2D( a.center.x - a.radius * cos(centers.theta), @@ -40,16 +41,20 @@ private fun outerTangent(a: Circle, b: Circle, side: SIDE): Straight { a.center.y - a.radius * sin(centers.theta) ) } - return Straight( + return StraightSegment( p1, Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) ) } -internal fun leftInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.LEFT) -internal fun rightInnerTangent(base: Circle, direction: Circle) = innerTangent(base, direction, SIDE.RIGHT) -private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? { - val centers = Straight(base.center, direction.center) +internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, SIDE.LEFT) + +internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, SIDE.RIGHT) + +private fun innerTangent(base: Circle2D, direction: Circle2D, side: SIDE): StraightSegment? { + val centers = StraightSegment(base.center, direction.center) if (centers.length < base.radius * 2) return null val angle = theta( when (side) { @@ -61,7 +66,7 @@ private fun innerTangent(base: Circle, direction: Circle, side: SIDE): Straight? val dY = base.radius * cos(angle) val p1 = Vector2D(base.center.x + dX, base.center.y + dY) val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) - return Straight(p1, p2) + return StraightSegment(p1, p2) } -internal fun theta(theta: Double) = (theta + (2 * PI)) % (2 * PI) +internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt deleted file mode 100644 index 1c02dd952..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Arc.kt +++ /dev/null @@ -1,59 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.dubins.theta -import space.kscience.kmath.trajectory.segments.components.Circle -import space.kscience.kmath.trajectory.segments.components.Pose2D -import kotlin.math.PI - -public data class Arc( - public val circle: Circle, - public val start: Pose2D, - public val end: Pose2D -) : Segment { - - internal companion object { - fun of(center: Vector2D, start: Vector2D, end: Vector2D, direction: Direction): Arc { - val s1 = Straight(center, start) - val s2 = Straight(center, end) - val pose1 = calculatePose(start, s1.theta, direction) - val pose2 = calculatePose(end, s2.theta, direction) - return Arc(Circle(center, s1.length), pose1, pose2) - } - - private fun calculatePose(vector: Vector2D, theta: Double, direction: Direction): Pose2D = - Pose2D.of( - vector, - when (direction) { - Direction.LEFT -> theta(theta - PI / 2) - Direction.RIGHT -> theta(theta + PI / 2) - } - ) - } - - internal enum class Direction { - LEFT, RIGHT - } - - override val length: Double - get() { - val angle: Double = - theta(if (direction == Direction.LEFT) start.theta - end.theta else end.theta - start.theta) - val proportion = angle / (2 * PI) - return circle.circumference * proportion - } - - internal val direction: Direction - get() = if (start.y < circle.center.y) { - if (start.theta > PI) Direction.RIGHT else Direction.LEFT - } else if (start.y > circle.center.y) { - if (start.theta < PI) Direction.RIGHT else Direction.LEFT - } else { - if (start.theta == 0.0) { - if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT - } else { - if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT - } - } - -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt new file mode 100644 index 000000000..3df34c107 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt @@ -0,0 +1,21 @@ +/* + * 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.trajectory.segments + +import space.kscience.kmath.geometry.Vector2D + +/** + * A [Vector2D] with view direction + */ +public data class Pose2D( + override val x: Double, + override val y: Double, + public val theta: Double +) : Vector2D { + public companion object { + public fun of(vector: Vector2D, theta: Double): Pose2D = Pose2D(vector.x, vector.y, theta) + } +} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt deleted file mode 100644 index 8a1d086fc..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Segment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -public interface Segment { - public val length: Double -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt deleted file mode 100644 index 444025d83..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Straight.kt +++ /dev/null @@ -1,18 +0,0 @@ -package space.kscience.kmath.trajectory.segments - -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.dubins.theta -import kotlin.math.PI -import kotlin.math.atan2 - -public data class Straight( - internal val start: Vector2D, - internal val end: Vector2D -) : Segment { - override val length: Double - get() = start.distanceTo(end) - - internal val theta: Double - get() = theta(atan2(end.x - start.x, end.y - start.y)) -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt new file mode 100644 index 000000000..453eef47f --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt @@ -0,0 +1,89 @@ +package space.kscience.kmath.trajectory.segments + +import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo +import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.circumference +import space.kscience.kmath.trajectory.dubins.theta +import kotlin.math.PI +import kotlin.math.atan2 + +public interface Trajectory { + public val length: Double +} + +/** + * Straight path segment. The order of start and end defines the direction + */ +public data class StraightSegment( + internal val start: Vector2D, + internal val end: Vector2D, +) : Trajectory { + override val length: Double get() = start.distanceTo(end) + + internal val theta: Double get() = theta(atan2(end.x - start.x, end.y - start.y)) +} + +/** + * An arc segment + */ +public data class ArcSegment( + public val circle: Circle2D, + public val start: Pose2D, + public val end: Pose2D, +) : Trajectory { + + public enum class Direction { + LEFT, RIGHT + } + + override val length: Double by lazy { + val angle: Double = theta( + if (direction == Direction.LEFT) { + start.theta - end.theta + } else { + end.theta - start.theta + } + ) + val proportion = angle / (2 * PI) + circle.circumference * proportion + } + + internal val direction: Direction by lazy { + if (start.y < circle.center.y) { + if (start.theta > PI) Direction.RIGHT else Direction.LEFT + } else if (start.y > circle.center.y) { + if (start.theta < PI) Direction.RIGHT else Direction.LEFT + } else { + if (start.theta == 0.0) { + if (start.x < circle.center.x) Direction.RIGHT else Direction.LEFT + } else { + if (start.x > circle.center.x) Direction.RIGHT else Direction.LEFT + } + } + } + + public companion object { + public fun of(center: Vector2D, start: Vector2D, end: Vector2D, direction: Direction): ArcSegment { + fun calculatePose( + vector: Vector2D, + theta: Double, + direction: Direction, + ): Pose2D = Pose2D.of( + vector, + when (direction) { + Direction.LEFT -> theta(theta - PI / 2) + Direction.RIGHT -> theta(theta + PI / 2) + } + ) + + val s1 = StraightSegment(center, start) + val s2 = StraightSegment(center, end) + val pose1 = calculatePose(start, s1.theta, direction) + val pose2 = calculatePose(end, s2.theta, direction) + return ArcSegment(Circle2D(center, s1.length), pose1, pose2) + } + } + +} + diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt deleted file mode 100644 index 946dd8c6e..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Circle.kt +++ /dev/null @@ -1,11 +0,0 @@ -package space.kscience.kmath.trajectory.segments.components - -import space.kscience.kmath.geometry.Vector2D -import kotlin.math.PI - -public open class Circle( - internal val center: Vector2D, - internal val radius: Double -) { - internal val circumference = radius * 2 * PI -} diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt deleted file mode 100644 index c49da3187..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/components/Pose2D.kt +++ /dev/null @@ -1,13 +0,0 @@ -package space.kscience.kmath.trajectory.segments.components - -import space.kscience.kmath.geometry.Vector2D - -public data class Pose2D( - override val x: Double, - override val y: Double, - public val theta: Double -) : Vector2D { - internal companion object { - internal fun of(vector: Vector2D, theta: Double) = Pose2D(vector.x, vector.y, theta) - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 92b2f1df9..4f8fda826 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,8 +1,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin @@ -14,12 +14,12 @@ fun Double.radiansToDegrees() = this * 180 / PI fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta fun Pose2D.equalsFloat(other: Pose2D) = x.equalFloat(other.x) && y.equalFloat(other.y) && theta.equalFloat(other.theta) -fun Straight.inverse() = Straight(end, start) -fun Straight.shift(shift: Int, width: Double): Straight { +fun StraightSegment.inverse() = StraightSegment(end, start) +fun StraightSegment.shift(shift: Int, width: Double): StraightSegment { val dX = width * sin(inverse().theta) val dY = width * sin(theta) - return Straight( + return StraightSegment( Vector2D(start.x - dX * shift, start.y - dY * shift), Vector2D(end.x - dX * shift, end.y - dY * shift) ) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 47e6ac2ef..9069f6dd2 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -10,9 +10,9 @@ import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.equalFloat import space.kscience.kmath.trajectory.equalsFloat import space.kscience.kmath.trajectory.inverse -import space.kscience.kmath.trajectory.segments.Arc -import space.kscience.kmath.trajectory.segments.Straight -import space.kscience.kmath.trajectory.segments.components.Pose2D +import space.kscience.kmath.trajectory.segments.ArcSegment +import space.kscience.kmath.trajectory.segments.Pose2D +import space.kscience.kmath.trajectory.segments.StraightSegment import space.kscience.kmath.trajectory.shift import kotlin.test.Test import kotlin.test.assertNotNull @@ -23,7 +23,7 @@ class DubinsTests { @Test fun dubinsTest() { - val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) val lineP1 = straight.shift(1, 10.0).inverse() val start = Pose2D.of(straight.end, straight.theta) @@ -52,12 +52,12 @@ class DubinsTests { assertTrue(end.equalsFloat(path.c.end)) // Not working, theta double precision inaccuracy - if (path.b is Arc) { - val b = path.b as Arc + if (path.b is ArcSegment) { + val b = path.b as ArcSegment assertTrue(path.a.end.equalsFloat(b.start)) assertTrue(path.c.start.equalsFloat(b.end)) - } else if (path.b is Straight) { - val b = path.b as Straight + } else if (path.b is StraightSegment) { + val b = path.b as StraightSegment assertTrue(path.a.end.equalsFloat(Pose2D.of(b.start, b.theta))) assertTrue(path.c.start.equalsFloat(Pose2D.of(b.end, b.theta))) } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index 5b4ae6d7a..aa8778315 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -1,8 +1,9 @@ package space.kscience.kmath.trajectory.segments +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.circumference import space.kscience.kmath.trajectory.radiansToDegrees -import space.kscience.kmath.trajectory.segments.components.Circle import kotlin.test.Test import kotlin.test.assertEquals @@ -10,8 +11,8 @@ class ArcTests { @Test fun arcTest() { - val circle = Circle(Vector2D(0.0, 0.0), 2.0) - val arc = Arc.of(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), Arc.Direction.RIGHT) + val circle = Circle2D(Vector2D(0.0, 0.0), 2.0) + val arc = ArcSegment.of(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), ArcSegment.Direction.RIGHT) assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.start.theta.radiansToDegrees()) assertEquals(90.0, arc.end.theta.radiansToDegrees()) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt similarity index 74% rename from kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt rename to kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt index 6f28885e0..5170c1db5 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/components/CircleTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt @@ -3,9 +3,11 @@ * 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.trajectory.segments.components +package space.kscience.kmath.trajectory.segments +import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.circumference import space.kscience.kmath.trajectory.maxFloatDelta import kotlin.test.Test import kotlin.test.assertEquals @@ -17,7 +19,7 @@ class CircleTests { val center = Vector2D(0.0, 0.0) val radius = 2.0 val expectedCircumference = 12.56637 - val circle = Circle(center, radius) + val circle = Circle2D(center, radius) assertEquals(expectedCircumference, circle.circumference, maxFloatDelta) } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index e8184e178..afc473d79 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -12,21 +12,21 @@ class LineTests { @Test fun lineTest() { - val straight = Straight(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), straight.length) assertEquals(45.0, straight.theta.radiansToDegrees()) } @Test fun lineAngleTest() { - val zero = Vector2D(0.0, 0.0) - val north = Straight(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) + //val zero = Vector2D(0.0, 0.0) + val north = StraightSegment(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) assertEquals(0.0, north.theta.radiansToDegrees()) - val east = Straight(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) + val east = StraightSegment(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) assertEquals(90.0, east.theta.radiansToDegrees()) - val south = Straight(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) + val south = StraightSegment(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) assertEquals(180.0, south.theta.radiansToDegrees()) - val west = Straight(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) + val west = StraightSegment(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) assertEquals(270.0, west.theta.radiansToDegrees()) } } From c2025ee1c9f1323b446f992a8f80b302bcd46774 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Wed, 27 Jul 2022 14:31:55 +0300 Subject: [PATCH 155/174] Remove Polynomial interface, fix consequent platform clashes. Add invariance. --- .../kmath/functions/LabeledPolynomial.kt | 4 +- .../kmath/functions/ListPolynomial.kt | 4 +- .../kmath/functions/NumberedPolynomial.kt | 4 +- .../kscience/kmath/functions/Polynomial.kt | 41 ++++-- .../kmath/functions/RationalFunction.kt | 130 ++++++++++++++++-- 5 files changed, 160 insertions(+), 23 deletions(-) diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index e2320114b..6a4d1409f 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -19,7 +19,7 @@ import kotlin.math.max * * @param C the type of constants. */ -public data class LabeledPolynomial +public data class LabeledPolynomial @PublishedApi internal constructor( /** @@ -63,7 +63,7 @@ internal constructor( * @usesMathJax */ public val coefficients: Map, C> -) : Polynomial { +) { override fun toString(): String = "LabeledPolynomial$coefficients" } diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index d0e58c0d6..6ab660b63 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -19,7 +19,7 @@ import kotlin.math.min * * @param C the type of constants. */ -public data class ListPolynomial( +public data class ListPolynomial( /** * List that contains coefficients of the polynomial. * @@ -48,7 +48,7 @@ public data class ListPolynomial( * @usesMathJax */ public val coefficients: List -) : Polynomial { +) { override fun toString(): String = "ListPolynomial$coefficients" } diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index d2fc5ffa1..267bbd91d 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -18,7 +18,7 @@ import kotlin.math.max * * @param C the type of constants. */ -public data class NumberedPolynomial +public data class NumberedPolynomial @PublishedApi internal constructor( /** @@ -47,7 +47,7 @@ internal constructor( * @usesMathJax */ public val coefficients: Map, C> -) : Polynomial { +) { override fun toString(): String = "NumberedPolynomial$coefficients" } diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index 66308a7bc..6a11eb1bd 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -11,11 +11,6 @@ import kotlin.js.JsName import kotlin.jvm.JvmName -/** - * Abstraction of polynomials. - */ -public interface Polynomial - /** * Abstraction of ring of polynomials of type [P] over ring of constants of type [C]. * @@ -23,24 +18,27 @@ public interface Polynomial * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface PolynomialSpace> : Ring

{ +public interface PolynomialSpace : Ring

{ /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public operator fun C.plus(other: Int): C /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public operator fun C.minus(other: Int): C /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public operator fun C.times(other: Int): C /** @@ -48,18 +46,21 @@ public interface PolynomialSpace> : Ring

{ * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public operator fun Int.plus(other: C): C /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public operator fun Int.minus(other: C): C /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public operator fun Int.times(other: C): C /** @@ -167,27 +168,33 @@ public interface PolynomialSpace> : Ring

{ /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusConstantPolynomial") public operator fun C.plus(other: P): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusConstantPolynomial") public operator fun C.minus(other: P): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesConstantPolynomial") public operator fun C.times(other: P): P /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusPolynomialConstant") public operator fun P.plus(other: C): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusPolynomialConstant") public operator fun P.minus(other: C): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesPolynomialConstant") public operator fun P.times(other: C): P /** @@ -252,7 +259,7 @@ public interface PolynomialSpace> : Ring

{ * @param A the type of algebraic structure (precisely, of ring) provided for constants. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface PolynomialSpaceOverRing, out A: Ring> : PolynomialSpace { +public interface PolynomialSpaceOverRing> : PolynomialSpace { /** * Underlying ring of constants. Its operations on constants are inherited by local operations on constants. @@ -264,18 +271,21 @@ public interface PolynomialSpaceOverRing, out A: Ring> : * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** @@ -283,18 +293,21 @@ public interface PolynomialSpaceOverRing, out A: Ring> : * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** @@ -341,69 +354,81 @@ public interface PolynomialSpaceOverRing, out A: Ring> : * @param P the type of polynomials. */ @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 -public interface MultivariatePolynomialSpace>: PolynomialSpace { +public interface MultivariatePolynomialSpace: PolynomialSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("plusVariableInt") + @JsName("plusVariableInt") public operator fun V.plus(other: Int): P /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("minusVariableInt") + @JsName("minusVariableInt") public operator fun V.minus(other: Int): P /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("timesVariableInt") + @JsName("timesVariableInt") public operator fun V.times(other: Int): P /** * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusIntVariable") + @JsName("plusIntVariable") public operator fun Int.plus(other: V): P /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusIntVariable") + @JsName("minusIntVariable") public operator fun Int.minus(other: V): P /** * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesIntVariable") + @JsName("timesIntVariable") public operator fun Int.times(other: V): P /** * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("plusVariableConstant") + @JsName("plusVariableConstant") public operator fun V.plus(other: C): P /** * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("minusVariableConstant") + @JsName("minusVariableConstant") public operator fun V.minus(other: C): P /** * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("timesVariableConstant") + @JsName("timesVariableConstant") public operator fun V.times(other: C): P /** * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusConstantVariable") + @JsName("plusConstantVariable") public operator fun C.plus(other: V): P /** * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusConstantVariable") + @JsName("minusConstantVariable") public operator fun C.minus(other: V): P /** * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesConstantVariable") + @JsName("timesConstantVariable") public operator fun C.times(other: V): P /** diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index da91c8d61..3c1548516 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -14,7 +14,7 @@ import kotlin.jvm.JvmName /** * Abstraction of rational function. */ -public interface RationalFunction> { +public interface RationalFunction { public val numerator: P public val denominator: P public operator fun component1(): P = numerator @@ -30,24 +30,27 @@ public interface RationalFunction> { * @param R the type of rational functions. */ @Suppress("INAPPLICABLE_JVM_NAME", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") // FIXME: Waiting for KT-31420 -public interface RationalFunctionSpace, R: RationalFunction> : Ring { +public interface RationalFunctionSpace> : Ring { /** * Returns sum of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public operator fun C.plus(other: Int): C /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public operator fun C.minus(other: Int): C /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public operator fun C.times(other: Int): C /** @@ -55,18 +58,21 @@ public interface RationalFunctionSpace, R: RationalFunction< * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public operator fun Int.plus(other: C): C /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public operator fun Int.minus(other: C): C /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public operator fun Int.times(other: C): C /** @@ -83,18 +89,21 @@ public interface RationalFunctionSpace, R: RationalFunction< * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ + @JvmName("plusPolynomialInt") public operator fun P.plus(other: Int): P /** * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ + @JvmName("minusPolynomialInt") public operator fun P.minus(other: Int): P /** * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesPolynomialInt") public operator fun P.times(other: Int): P /** @@ -102,18 +111,21 @@ public interface RationalFunctionSpace, R: RationalFunction< * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ + @JvmName("plusIntPolynomial") public operator fun Int.plus(other: P): P /** * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ + @JvmName("minusIntPolynomial") public operator fun Int.minus(other: P): P /** * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntPolynomial") public operator fun Int.times(other: P): P /** @@ -235,27 +247,33 @@ public interface RationalFunctionSpace, R: RationalFunction< /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusConstantPolynomial") public operator fun C.plus(other: P): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusConstantPolynomial") public operator fun C.minus(other: P): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesConstantPolynomial") public operator fun C.times(other: P): P /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusPolynomialConstant") public operator fun P.plus(other: C): P /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusPolynomialConstant") public operator fun P.minus(other: C): P /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesPolynomialConstant") public operator fun P.times(other: C): P /** @@ -270,30 +288,37 @@ public interface RationalFunctionSpace, R: RationalFunction< /** * Returns the same polynomial. */ + @JvmName("unaryPlusPolynomial") public operator fun P.unaryPlus(): P = this /** * Returns negation of the polynomial. */ + @JvmName("unaryMinusPolynomial") public operator fun P.unaryMinus(): P /** * Returns sum of the polynomials. */ + @JvmName("plusPolynomialPolynomial") public operator fun P.plus(other: P): P /** * Returns difference of the polynomials. */ + @JvmName("minusPolynomialPolynomial") public operator fun P.minus(other: P): P /** * Returns product of the polynomials. */ + @JvmName("timesPolynomialPolynomial") public operator fun P.times(other: P): P /** * Returns quotient of the polynomials as rational function. */ + @JvmName("divPolynomialPolynomial") public operator fun P.div(other: P): R /** * Raises [arg] to the integer power [exponent]. */ + @JvmName("powerPolynomial") public fun power(arg: P, exponent: UInt) : P /** @@ -308,87 +333,107 @@ public interface RationalFunctionSpace, R: RationalFunction< /** * Returns sum of the constant represented as a rational function and the rational function. */ + @JvmName("plusConstantRational") public operator fun C.plus(other: R): R /** * Returns difference between the constant represented as a polynomial and the rational function. */ + @JvmName("minusConstantRational") public operator fun C.minus(other: R): R /** * Returns product of the constant represented as a polynomial and the rational function. */ + @JvmName("timesConstantRational") public operator fun C.times(other: R): R /** * Returns quotient of the constant represented as a polynomial and the rational function. */ + @JvmName("divConstantRational") public operator fun C.div(other: R): R /** * Returns sum of the rational function and the constant represented as a rational function. */ + @JvmName("plusRationalConstant") public operator fun R.plus(other: C): R /** * Returns difference between the rational function and the constant represented as a rational function. */ + @JvmName("minusRationalConstant") public operator fun R.minus(other: C): R /** * Returns product of the rational function and the constant represented as a rational function. */ + @JvmName("timesRationalConstant") public operator fun R.times(other: C): R /** * Returns quotient of the rational function and the constant represented as a rational function. */ + @JvmName("divRationalConstant") public operator fun R.div(other: C): R /** * Converts the constant [value] to rational function. */ + @JvmName("numberConstant") public fun number(value: C): R = one * value /** * Converts the constant to rational function. */ + @JvmName("asRationalFunctionConstant") public fun C.asRationalFunction(): R = number(this) /** * Returns sum of the polynomial represented as a rational function and the rational function. */ + @JvmName("plusPolynomialRational") public operator fun P.plus(other: R): R /** * Returns difference between the polynomial represented as a polynomial and the rational function. */ + @JvmName("minusPolynomialRational") public operator fun P.minus(other: R): R /** * Returns product of the polynomial represented as a polynomial and the rational function. */ + @JvmName("timesPolynomialRational") public operator fun P.times(other: R): R /** * Returns quotient of the polynomial represented as a polynomial and the rational function. */ + @JvmName("divPolynomialRational") public operator fun P.div(other: R): R /** * Returns sum of the rational function and the polynomial represented as a rational function. */ + @JvmName("plusRationalPolynomial") public operator fun R.plus(other: P): R /** * Returns difference between the rational function and the polynomial represented as a rational function. */ + @JvmName("minusRationalPolynomial") public operator fun R.minus(other: P): R /** * Returns product of the rational function and the polynomial represented as a rational function. */ + @JvmName("timesRationalPolynomial") public operator fun R.times(other: P): R /** * Returns quotient of the rational function and the polynomial represented as a rational function. */ + @JvmName("divRationalPolynomial") public operator fun R.div(other: P): R /** * Converts the polynomial [value] to rational function. */ + @JvmName("numberPolynomial") public fun number(value: P): R = one * value /** * Converts the polynomial to rational function. */ + @JvmName("asRationalFunctionPolynomial") public fun P.asRationalFunction(): R = number(this) /** @@ -462,7 +507,7 @@ public interface RationalFunctionSpace, R: RationalFunction< @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionSpaceOverRing< C, - P: Polynomial, + P, R: RationalFunction, out A: Ring > : RationalFunctionSpace { @@ -477,18 +522,21 @@ public interface RationalFunctionSpaceOverRing< * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public override operator fun C.plus(other: Int): C = ring { addMultipliedByDoubling(this@plus, one, other) } /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public override operator fun C.minus(other: Int): C = ring { addMultipliedByDoubling(this@minus, one, -other) } /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public override operator fun C.times(other: Int): C = ring { multiplyByDoubling(this@times, other) } /** @@ -496,18 +544,21 @@ public interface RationalFunctionSpaceOverRing< * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public override operator fun Int.plus(other: C): C = ring { addMultipliedByDoubling(other, one, this@plus) } /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public override operator fun Int.minus(other: C): C = ring { addMultipliedByDoubling(-other, one, this@minus) } /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public override operator fun Int.times(other: C): C = ring { multiplyByDoubling(other, this@times) } /** @@ -564,7 +615,7 @@ public interface RationalFunctionSpaceOverRing< @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public interface RationalFunctionSpaceOverPolynomialSpace< C, - P: Polynomial, + P, R: RationalFunction, out AP: PolynomialSpace, > : RationalFunctionSpace { @@ -579,18 +630,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [other] copies of unit of underlying ring to [this]. */ + @JvmName("plusConstantInt") public override operator fun C.plus(other: Int): C = polynomialRing { this@plus + other } /** * Returns difference between the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to subtraction [other] copies of unit of underlying ring from [this]. */ + @JvmName("minusConstantInt") public override operator fun C.minus(other: Int): C = polynomialRing { this@minus - other } /** * Returns product of the constant and the integer represented as a constant (member of underlying ring). * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesConstantInt") public override operator fun C.times(other: Int): C = polynomialRing { this@times * other } /** @@ -598,18 +652,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [this] copies of unit of underlying ring to [other]. */ + @JvmName("plusIntConstant") public override operator fun Int.plus(other: C): C = polynomialRing { this@plus + other } /** * Returns difference between the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to subtraction [this] copies of unit of underlying ring from [other]. */ + @JvmName("minusIntConstant") public override operator fun Int.minus(other: C): C = polynomialRing { this@minus - other } /** * Returns product of the integer represented as a constant (member of underlying ring) and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntConstant") public override operator fun Int.times(other: C): C = polynomialRing { this@times * other } /** @@ -626,18 +683,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [other] copies of unit polynomial to [this]. */ + @JvmName("plusPolynomialInt") public override operator fun P.plus(other: Int): P = polynomialRing { this@plus + other } /** * Returns difference between the constant and the integer represented as a polynomial. * * The operation is equivalent to subtraction [other] copies of unit polynomial from [this]. */ + @JvmName("minusPolynomialInt") public override operator fun P.minus(other: Int): P = polynomialRing { this@minus - other } /** * Returns product of the constant and the integer represented as a polynomial. * * The operation is equivalent to sum of [other] copies of [this]. */ + @JvmName("timesPolynomialInt") public override operator fun P.times(other: Int): P = polynomialRing { this@times * other } /** @@ -645,18 +705,21 @@ public interface RationalFunctionSpaceOverPolynomialSpace< * * The operation is equivalent to adding [this] copies of unit polynomial to [other]. */ + @JvmName("plusIntPolynomial") public override operator fun Int.plus(other: P): P = polynomialRing { this@plus + other } /** * Returns difference between the integer represented as a polynomial and the constant. * * The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. */ + @JvmName("minusIntPolynomial") public override operator fun Int.minus(other: P): P = polynomialRing { this@minus - other } /** * Returns product of the integer represented as a polynomial and the constant. * * The operation is equivalent to sum of [this] copies of [other]. */ + @JvmName("timesIntPolynomial") public override operator fun Int.times(other: P): P = polynomialRing { this@times * other } /** @@ -711,27 +774,33 @@ public interface RationalFunctionSpaceOverPolynomialSpace< /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusConstantPolynomial") public override operator fun C.plus(other: P): P = polynomialRing { this@plus + other } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusConstantPolynomial") public override operator fun C.minus(other: P): P = polynomialRing { this@minus - other } /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesConstantPolynomial") public override operator fun C.times(other: P): P = polynomialRing { this@times * other } /** * Returns sum of the constant represented as a polynomial and the polynomial. */ + @JvmName("plusPolynomialConstant") public override operator fun P.plus(other: C): P = polynomialRing { this@plus + other } /** * Returns difference between the constant represented as a polynomial and the polynomial. */ + @JvmName("minusPolynomialConstant") public override operator fun P.minus(other: C): P = polynomialRing { this@minus - other } /** * Returns product of the constant represented as a polynomial and the polynomial. */ + @JvmName("timesPolynomialConstant") public override operator fun P.times(other: C): P = polynomialRing { this@times * other } /** @@ -746,26 +815,32 @@ public interface RationalFunctionSpaceOverPolynomialSpace< /** * Returns the same polynomial. */ + @JvmName("unaryPlusPolynomial") public override operator fun P.unaryPlus(): P = polynomialRing { +this@unaryPlus } /** * Returns negation of the polynomial. */ + @JvmName("unaryMinusPolynomial") public override operator fun P.unaryMinus(): P = polynomialRing { -this@unaryMinus } /** * Returns sum of the polynomials. */ + @JvmName("plusPolynomialPolynomial") public override operator fun P.plus(other: P): P = polynomialRing { this@plus + other } /** * Returns difference of the polynomials. */ + @JvmName("minusPolynomialPolynomial") public override operator fun P.minus(other: P): P = polynomialRing { this@minus - other } /** * Returns product of the polynomials. */ + @JvmName("timesPolynomialPolynomial") public override operator fun P.times(other: P): P = polynomialRing { this@times * other } /** * Raises [arg] to the integer power [exponent]. */ + @JvmName("powerPolynomial") public override fun power(arg: P, exponent: UInt) : P = polynomialRing { power(arg, exponent) } /** @@ -796,7 +871,7 @@ public interface RationalFunctionSpaceOverPolynomialSpace< @Suppress("INAPPLICABLE_JVM_NAME") // FIXME: Waiting for KT-31420 public abstract class PolynomialSpaceOfFractions< C, - P: Polynomial, + P, R: RationalFunction, > : RationalFunctionSpace { @@ -897,11 +972,13 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the polynomials as rational function. */ + @JvmName("divPolynomialPolynomial") public override operator fun P.div(other: P): R = constructRationalFunction(this, other) /** * Returns sum of the constant represented as a rational function and the rational function. */ + @JvmName("plusConstantRational") public override operator fun C.plus(other: R): R = constructRationalFunction( other.denominator * this + other.numerator, @@ -910,6 +987,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the constant represented as a polynomial and the rational function. */ + @JvmName("minusConstantRational") public override operator fun C.minus(other: R): R = constructRationalFunction( other.denominator * this - other.numerator, @@ -918,6 +996,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the constant represented as a polynomial and the rational function. */ + @JvmName("timesConstantRational") public override operator fun C.times(other: R): R = constructRationalFunction( this * other.numerator, @@ -926,6 +1005,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the constant represented as a polynomial and the rational function. */ + @JvmName("divConstantRational") public override operator fun C.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -935,6 +1015,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns sum of the constant represented as a rational function and the rational function. */ + @JvmName("plusRationalConstant") public override operator fun R.plus(other: C): R = constructRationalFunction( numerator + denominator * other, @@ -943,6 +1024,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the constant represented as a rational function and the rational function. */ + @JvmName("minusRationalConstant") public override operator fun R.minus(other: C): R = constructRationalFunction( numerator - denominator * other, @@ -951,6 +1033,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the constant represented as a rational function and the rational function. */ + @JvmName("timesRationalConstant") public override operator fun R.times(other: C): R = constructRationalFunction( numerator * other, @@ -959,6 +1042,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the rational function and the constant represented as a rational function. */ + @JvmName("divRationalConstant") public override operator fun R.div(other: C): R = constructRationalFunction( numerator, @@ -968,11 +1052,13 @@ public abstract class PolynomialSpaceOfFractions< /** * Converts the constant [value] to rational function. */ + @JvmName("numberConstant") public override fun number(value: C): R = constructRationalFunction(polynomialNumber(value)) /** * Returns sum of the polynomial represented as a rational function and the rational function. */ + @JvmName("plusPolynomialRational") public override operator fun P.plus(other: R): R = constructRationalFunction( other.denominator * this + other.numerator, @@ -981,6 +1067,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the polynomial represented as a polynomial and the rational function. */ + @JvmName("minusPolynomialRational") public override operator fun P.minus(other: R): R = constructRationalFunction( other.denominator * this - other.numerator, @@ -989,6 +1076,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the polynomial represented as a polynomial and the rational function. */ + @JvmName("timesPolynomialRational") public override operator fun P.times(other: R): R = constructRationalFunction( this * other.numerator, @@ -997,6 +1085,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the polynomial represented as a polynomial and the rational function. */ + @JvmName("divPolynomialRational") public override operator fun P.div(other: R): R = constructRationalFunction( this * other.denominator, @@ -1006,6 +1095,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns sum of the polynomial represented as a rational function and the rational function. */ + @JvmName("plusRationalPolynomial") public override operator fun R.plus(other: P): R = constructRationalFunction( numerator + denominator * other, @@ -1014,6 +1104,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns difference between the polynomial represented as a rational function and the rational function. */ + @JvmName("minusRationalPolynomial") public override operator fun R.minus(other: P): R = constructRationalFunction( numerator - denominator * other, @@ -1022,6 +1113,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns product of the polynomial represented as a rational function and the rational function. */ + @JvmName("timesRationalPolynomial") public override operator fun R.times(other: P): R = constructRationalFunction( numerator * other, @@ -1030,6 +1122,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Returns quotient of the rational function and the polynomial represented as a rational function. */ + @JvmName("divRationalPolynomial") public override operator fun R.div(other: P): R = constructRationalFunction( numerator, @@ -1039,6 +1132,7 @@ public abstract class PolynomialSpaceOfFractions< /** * Converts the polynomial [value] to rational function. */ + @JvmName("numberPolynomial") public override fun number(value: P): R = constructRationalFunction(value) /** @@ -1110,97 +1204,114 @@ public abstract class PolynomialSpaceOfFractions< public interface MultivariateRationalFunctionSpace< C, V, - P: Polynomial, + P, R: RationalFunction >: RationalFunctionSpace { /** * Returns sum of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("plusVariableInt") + @JsName("plusVariableInt") public operator fun V.plus(other: Int): P /** * Returns difference between the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("minusVariableInt") + @JsName("minusVariableInt") public operator fun V.minus(other: Int): P /** * Returns product of the variable represented as a monic monomial and the integer represented as a constant polynomial. */ @JvmName("timesVariableInt") + @JsName("timesVariableInt") public operator fun V.times(other: Int): P /** * Returns sum of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusIntVariable") + @JsName("plusIntVariable") public operator fun Int.plus(other: V): P /** * Returns difference between the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusIntVariable") + @JsName("minusIntVariable") public operator fun Int.minus(other: V): P /** * Returns product of the integer represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesIntVariable") + @JsName("timesIntVariable") public operator fun Int.times(other: V): P /** * Returns sum of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("plusVariableConstant") + @JsName("plusVariableConstant") public operator fun V.plus(other: C): P /** * Returns difference between the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("minusVariableConstant") + @JsName("minusVariableConstant") public operator fun V.minus(other: C): P /** * Returns product of the variable represented as a monic monomial and the constant represented as a constant polynomial. */ @JvmName("timesVariableConstant") + @JsName("timesVariableConstant") public operator fun V.times(other: C): P /** * Returns sum of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("plusConstantVariable") + @JsName("plusConstantVariable") public operator fun C.plus(other: V): P /** * Returns difference between the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("minusConstantVariable") + @JsName("minusConstantVariable") public operator fun C.minus(other: V): P /** * Returns product of the constant represented as a constant polynomial and the variable represented as a monic monomial. */ @JvmName("timesConstantVariable") + @JsName("timesConstantVariable") public operator fun C.times(other: V): P /** * Represents the variable as a monic monomial. */ @JvmName("unaryPlusVariable") + @JsName("unaryPlusVariable") public operator fun V.unaryPlus(): P /** * Returns negation of representation of the variable as a monic monomial. */ @JvmName("unaryMinusVariable") + @JsName("unaryMinusVariable") public operator fun V.unaryMinus(): P /** * Returns sum of the variables represented as monic monomials. */ @JvmName("plusVariableVariable") + @JsName("plusVariableVariable") public operator fun V.plus(other: V): P /** * Returns difference between the variables represented as monic monomials. */ @JvmName("minusVariableVariable") + @JsName("minusVariableVariable") public operator fun V.minus(other: V): P /** * Returns product of the variables represented as monic monomials. */ @JvmName("timesVariableVariable") + @JsName("timesVariableVariable") public operator fun V.times(other: V): P /** @@ -1218,11 +1329,13 @@ public interface MultivariateRationalFunctionSpace< * Represents the [variable] as a rational function. */ @JvmName("numberVariable") + @JsName("numberVariable") public fun number(variable: V): R = number(polynomialNumber(variable)) /** * Represents the variable as a rational function. */ @JvmName("asRationalFunctionVariable") + @JsName("asRationalFunctionVariable") public fun V.asRationalFunction(): R = number(this) /** @@ -1339,7 +1452,7 @@ public interface MultivariateRationalFunctionSpace< public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpace< C, V, - P: Polynomial, + P, R: RationalFunction, out AP: MultivariatePolynomialSpace, > : RationalFunctionSpaceOverPolynomialSpace, MultivariateRationalFunctionSpace { @@ -1516,7 +1629,7 @@ public interface MultivariateRationalFunctionSpaceOverMultivariatePolynomialSpac public abstract class MultivariatePolynomialSpaceOfFractions< C, V, - P: Polynomial, + P, R: RationalFunction, > : MultivariateRationalFunctionSpace, PolynomialSpaceOfFractions() { /** @@ -1568,7 +1681,6 @@ public abstract class MultivariatePolynomialSpaceOfFractions< /** * Returns product of the rational function and the variable represented as a rational function. */ - @JvmName("timesRationalVariable") public override operator fun R.times(other: V): R = constructRationalFunction( numerator * other, From 137ddb3ade4f57ee11d2fb05defaa68829d93925 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 29 Jul 2022 14:12:44 +0300 Subject: [PATCH 156/174] Code simplification for Dubins path --- .../trajectory/{dubins => }/DubinsPath.kt | 75 ++++++++++++++++--- .../space/kscience/kmath/trajectory/Pose2D.kt | 33 ++++++++ .../trajectory/{segments => }/Trajectory.kt | 17 +++-- .../kmath/trajectory/TrajectoryCost.kt | 14 ++++ .../trajectory/dubins/trajectoryFunctions.kt | 72 ------------------ .../space/kscience/kmath/trajectory/route.kt | 16 ++++ .../kmath/trajectory/segments/Pose2D.kt | 21 ------ .../space/kscience/kmath/trajectory/Math.kt | 2 - .../kmath/trajectory/dubins/DubinsTests.kt | 16 ++-- .../kmath/trajectory/segments/ArcTests.kt | 1 + .../kmath/trajectory/segments/LineTests.kt | 1 + 11 files changed, 146 insertions(+), 122 deletions(-) rename kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/{dubins => }/DubinsPath.kt (67%) create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt rename kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/{segments => }/Trajectory.kt (85%) create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt create mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt delete mode 100644 kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt similarity index 67% rename from kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt rename to kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index f510e3572..134342b33 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -3,24 +3,79 @@ * 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.trajectory.dubins +package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.ArcSegment -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment -import space.kscience.kmath.trajectory.segments.Trajectory +import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos import kotlin.math.sin +internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first + +internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second + +internal fun Pose2D.getTangentCircles(radius: Double): Pair { + val dX = radius * cos(theta) + val dY = radius * sin(theta) + return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) +} + +internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, ArcSegment.Direction.LEFT) + +internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, + ArcSegment.Direction.RIGHT +) + +private fun outerTangent(a: Circle2D, b: Circle2D, side: ArcSegment.Direction): StraightSegment { + val centers = StraightSegment(a.center, b.center) + val p1 = when (side) { + ArcSegment.Direction.LEFT -> Vector2D( + a.center.x - a.radius * cos(centers.theta), + a.center.y + a.radius * sin(centers.theta) + ) + ArcSegment.Direction.RIGHT -> Vector2D( + a.center.x + a.radius * cos(centers.theta), + a.center.y - a.radius * sin(centers.theta) + ) + } + return StraightSegment( + p1, + Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) + ) +} + +internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, ArcSegment.Direction.LEFT) + +internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = + innerTangent(base, direction, ArcSegment.Direction.RIGHT) + +private fun innerTangent(base: Circle2D, direction: Circle2D, side: ArcSegment.Direction): StraightSegment? { + val centers = StraightSegment(base.center, direction.center) + if (centers.length < base.radius * 2) return null + val angle = theta( + when (side) { + ArcSegment.Direction.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) + ArcSegment.Direction.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) + } + ) + val dX = base.radius * sin(angle) + val dY = base.radius * cos(angle) + val p1 = Vector2D(base.center.x + dX, base.center.y + dY) + val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) + return StraightSegment(p1, p2) +} + +internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) + public class DubinsPath( public val a: ArcSegment, public val b: Trajectory, public val c: ArcSegment, -) : Trajectory { +) : CompositeTrajectory(listOf(a,b,c)) { public val type: TYPE = TYPE.valueOf( arrayOf( @@ -30,8 +85,6 @@ public class DubinsPath( ).toCharArray().concatToString() ) - override val length: Double get() = a.length + b.length + c.length - public enum class TYPE { RLR, LRL, RSR, LSL, RSL, LSR } @@ -119,7 +172,7 @@ public class DubinsPath( val c1 = start.getRightCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val s = rightInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null + if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.RIGHT) val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.LEFT) @@ -130,11 +183,11 @@ public class DubinsPath( val c1 = start.getLeftCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val s = leftInnerTangent(c1, c2) - if (c1.center.distanceTo(c2.center) < turningRadius * 2 || s == null) return null + if (s == null || c1.center.distanceTo(c2.center) < turningRadius * 2) return null val a1 = ArcSegment.of(c1.center, start, s.start, ArcSegment.Direction.LEFT) val a3 = ArcSegment.of(c2.center, s.end, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, s, a3) } } -} +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt new file mode 100644 index 000000000..1f7c4a52e --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt @@ -0,0 +1,33 @@ +/* + * 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.trajectory + +import space.kscience.kmath.geometry.Vector +import space.kscience.kmath.geometry.Vector2D +import kotlin.math.atan2 + +/** + * Combination of [Vector] and its view angle + */ +public interface Pose2D: Vector2D{ + public val coordinate: Vector2D + public val theta: Double +} + +public class PhaseVector2D( + override val coordinate: Vector2D, + public val velocity: Vector2D +): Pose2D, Vector2D by coordinate{ + override val theta: Double get() = atan2(velocity.y, velocity.x) +} + +internal class Pose2DImpl( + override val coordinate: Vector2D, + override val theta: Double +) : Pose2D, Vector2D by coordinate + + +public fun Pose2D(coordinate: Vector2D, theta: Double): Pose2D = Pose2DImpl(coordinate, theta) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt similarity index 85% rename from kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt rename to kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt index 453eef47f..2e97d43b0 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Trajectory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt @@ -1,14 +1,18 @@ -package space.kscience.kmath.trajectory.segments +/* + * 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.trajectory import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.circumference -import space.kscience.kmath.trajectory.dubins.theta import kotlin.math.PI import kotlin.math.atan2 -public interface Trajectory { +public sealed interface Trajectory { public val length: Double } @@ -69,7 +73,7 @@ public data class ArcSegment( vector: Vector2D, theta: Double, direction: Direction, - ): Pose2D = Pose2D.of( + ): Pose2D = Pose2D( vector, when (direction) { Direction.LEFT -> theta(theta - PI / 2) @@ -84,6 +88,9 @@ public data class ArcSegment( return ArcSegment(Circle2D(center, s1.length), pose1, pose2) } } - +} + +public open class CompositeTrajectory(public val segments: Collection) : Trajectory { + override val length: Double get() = segments.sumOf { it.length } } diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt new file mode 100644 index 000000000..170851c43 --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt @@ -0,0 +1,14 @@ +/* + * 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.trajectory + +public fun interface TrajectoryCost { + public fun estimate(trajectory: Trajectory): Double + + public companion object{ + public val length: TrajectoryCost = TrajectoryCost { it.length } + } +} \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt deleted file mode 100644 index 18384d349..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/dubins/trajectoryFunctions.kt +++ /dev/null @@ -1,72 +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.trajectory.dubins - -import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment -import kotlin.math.PI -import kotlin.math.acos -import kotlin.math.cos -import kotlin.math.sin - -private enum class SIDE { - LEFT, RIGHT -} - -internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles(radius).first -internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second -internal fun Pose2D.getTangentCircles(radius: Double): Pair { - val dX = radius * cos(theta) - val dY = radius * sin(theta) - return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) -} - -internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.LEFT) -internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, SIDE.RIGHT) - -private fun outerTangent(a: Circle2D, b: Circle2D, side: SIDE): StraightSegment { - val centers = StraightSegment(a.center, b.center) - val p1 = when (side) { - SIDE.LEFT -> Vector2D( - a.center.x - a.radius * cos(centers.theta), - a.center.y + a.radius * sin(centers.theta) - ) - SIDE.RIGHT -> Vector2D( - a.center.x + a.radius * cos(centers.theta), - a.center.y - a.radius * sin(centers.theta) - ) - } - return StraightSegment( - p1, - Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) - ) -} - -internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = - innerTangent(base, direction, SIDE.LEFT) - -internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = - innerTangent(base, direction, SIDE.RIGHT) - -private fun innerTangent(base: Circle2D, direction: Circle2D, side: SIDE): StraightSegment? { - val centers = StraightSegment(base.center, direction.center) - if (centers.length < base.radius * 2) return null - val angle = theta( - when (side) { - SIDE.LEFT -> centers.theta + acos(base.radius * 2 / centers.length) - SIDE.RIGHT -> centers.theta - acos(base.radius * 2 / centers.length) - } - ) - val dX = base.radius * sin(angle) - val dY = base.radius * cos(angle) - val p1 = Vector2D(base.center.x + dX, base.center.y + dY) - val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) - return StraightSegment(p1, p2) -} - -internal fun theta(theta: Double): Double = (theta + (2 * PI)) % (2 * PI) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt new file mode 100644 index 000000000..f67ab124d --- /dev/null +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt @@ -0,0 +1,16 @@ +/* + * 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.trajectory + +public fun interface MaxCurvature { + public fun compute(startPoint: PhaseVector2D): Double +} + +public fun DubinsPath.Companion.shortest( + start: PhaseVector2D, + end: PhaseVector2D, + computer: MaxCurvature, +): DubinsPath = shortest(start, end, computer.compute(start)) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt deleted file mode 100644 index 3df34c107..000000000 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/segments/Pose2D.kt +++ /dev/null @@ -1,21 +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.trajectory.segments - -import space.kscience.kmath.geometry.Vector2D - -/** - * A [Vector2D] with view direction - */ -public data class Pose2D( - override val x: Double, - override val y: Double, - public val theta: Double -) : Vector2D { - public companion object { - public fun of(vector: Vector2D, theta: Double): Pose2D = Pose2D(vector.x, vector.y, theta) - } -} diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 4f8fda826..7ee68bd92 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,8 +1,6 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 9069f6dd2..09375a400 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -7,13 +7,7 @@ package space.kscience.kmath.trajectory.dubins import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo import space.kscience.kmath.geometry.Vector2D -import space.kscience.kmath.trajectory.equalFloat -import space.kscience.kmath.trajectory.equalsFloat -import space.kscience.kmath.trajectory.inverse -import space.kscience.kmath.trajectory.segments.ArcSegment -import space.kscience.kmath.trajectory.segments.Pose2D -import space.kscience.kmath.trajectory.segments.StraightSegment -import space.kscience.kmath.trajectory.shift +import space.kscience.kmath.trajectory.* import kotlin.test.Test import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -26,8 +20,8 @@ class DubinsTests { val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) val lineP1 = straight.shift(1, 10.0).inverse() - val start = Pose2D.of(straight.end, straight.theta) - val end = Pose2D.of(lineP1.start, lineP1.theta) + val start = Pose2D(straight.end, straight.theta) + val end = Pose2D(lineP1.start, lineP1.theta) val radius = 2.0 val dubins = DubinsPath.all(start, end, radius) @@ -58,8 +52,8 @@ class DubinsTests { assertTrue(path.c.start.equalsFloat(b.end)) } else if (path.b is StraightSegment) { val b = path.b as StraightSegment - assertTrue(path.a.end.equalsFloat(Pose2D.of(b.start, b.theta))) - assertTrue(path.c.start.equalsFloat(Pose2D.of(b.end, b.theta))) + assertTrue(path.a.end.equalsFloat(Pose2D(b.start, b.theta))) + assertTrue(path.c.start.equalsFloat(Pose2D(b.end, b.theta))) } } } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index aa8778315..c66fa201b 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -3,6 +3,7 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Circle2D import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.circumference +import space.kscience.kmath.trajectory.ArcSegment import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index afc473d79..11eaa0fb3 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -2,6 +2,7 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.trajectory.StraightSegment import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.math.pow import kotlin.math.sqrt From 0e9072710fe43a17cedf780fb22331b27fb69589 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 29 Jul 2022 15:58:02 +0300 Subject: [PATCH 157/174] Kotlin 1.7.20-Beta --- CHANGELOG.md | 1 + benchmarks/build.gradle.kts | 2 +- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 4 ++-- buildSrc/settings.gradle.kts | 2 +- .../kscience/kmath/benchmarks/addBenchmarkProperties.kt | 2 +- examples/build.gradle.kts | 2 +- gradle.properties | 2 +- kmath-ast/build.gradle.kts | 4 ++-- kmath-commons/build.gradle.kts | 4 ++-- kmath-complex/build.gradle.kts | 6 +++--- kmath-core/build.gradle.kts | 6 +++--- kmath-coroutines/build.gradle.kts | 8 ++++---- kmath-dimensions/build.gradle.kts | 6 +++--- kmath-ejml/build.gradle.kts | 4 ++-- kmath-for-real/build.gradle.kts | 6 +++--- kmath-functions/build.gradle.kts | 6 +++--- kmath-geometry/build.gradle.kts | 6 +++--- kmath-histograms/build.gradle.kts | 6 +++--- kmath-jafama/build.gradle.kts | 4 ++-- kmath-jupyter/build.gradle.kts | 4 ++-- kmath-kotlingrad/build.gradle.kts | 4 ++-- kmath-memory/build.gradle.kts | 6 +++--- kmath-multik/build.gradle.kts | 4 ++-- kmath-nd4j/build.gradle.kts | 4 ++-- kmath-optimization/build.gradle.kts | 6 +++--- kmath-polynomial/build.gradle.kts | 6 +++--- kmath-stat/build.gradle.kts | 6 +++--- kmath-symja/build.gradle.kts | 4 ++-- kmath-tensorflow/build.gradle.kts | 4 ++-- kmath-tensors/build.gradle.kts | 6 +++--- kmath-trajectory/build.gradle.kts | 6 +++--- kmath-viktor/build.gradle.kts | 4 ++-- settings.gradle.kts | 2 +- test-utils/build.gradle.kts | 4 ++-- 35 files changed, 77 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4852f474a..66d83ec34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] ### Added +- 2D optimal trajectory computation in a separate module `kmath-trajectory` - Autodiff for generic algebra elements in core! - Algebra now has an obligatory `bufferFactory` (#477). diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 22712816d..e86990043 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -163,7 +163,7 @@ tasks.withType { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL } addBenchmarkProperties() diff --git a/build.gradle.kts b/build.gradle.kts index d8c591799..c57b29105 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("ru.mipt.npm.gradle.project") + id("space.kscience.gradle.project") id("org.jetbrains.kotlinx.kover") version "0.5.0" } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 20611e92d..9bf5d03d0 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - kotlin("jvm") version "1.7.0" + kotlin("jvm") version "1.7.20-Beta" `kotlin-dsl` `version-catalog` alias(npmlibs.plugins.kotlin.plugin.serialization) @@ -19,7 +19,7 @@ val kotlinVersion = npmlibs.versions.kotlin.asProvider().get() val benchmarksVersion = npmlibs.versions.kotlinx.benchmark.get() dependencies { - api("ru.mipt.npm:gradle-tools:$toolsVersion") + api("space.kscience:gradle-tools:$toolsVersion") api(npmlibs.atomicfu.gradle) //plugins form benchmarks api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index bce265510..403e0f52c 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -27,7 +27,7 @@ dependencyResolutionManagement { versionCatalogs { create("npmlibs") { - from("ru.mipt.npm:version-catalog:$toolsVersion") + from("space.kscience:version-catalog:$toolsVersion") } } } diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt index dc9327348..33d186bfc 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -9,7 +9,7 @@ import kotlinx.benchmark.gradle.BenchmarksExtension import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import org.gradle.api.Project -import ru.mipt.npm.gradle.KScienceReadmeExtension +import space.kscience.gradle.KScienceReadmeExtension import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index aa5c1f47a..cfa50815d 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -68,5 +68,5 @@ tasks.withType { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL } diff --git a/gradle.properties b/gradle.properties index 6b45ee49f..ca8c91191 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,4 +12,4 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.11.8-kotlin-1.7.10 +toolsVersion=0.12.0-kotlin-1.7.20-Beta diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index f49c2767a..c1333eba5 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } kotlin.js { @@ -61,7 +61,7 @@ if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1" } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 96c17a215..643307b48 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } description = "Commons math binding for kmath" @@ -16,5 +16,5 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index f0ce631a5..dbe96b153 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } kotlin.sourceSets { @@ -14,7 +14,7 @@ kotlin.sourceSets { readme { description = "Complex numbers and quaternions." - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 052924ce8..d055b5350 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.mpp") + id("space.kscience.gradle.native") } kotlin.sourceSets { @@ -26,7 +26,7 @@ kotlin.sourceSets { readme { description = "Core classes, algebra definitions, basic linear algebra" - maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT + maturity = space.kscience.gradle.Maturity.DEVELOPMENT propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index aa30c412b..104adf268 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } kotlin.sourceSets { @@ -17,11 +17,11 @@ kotlin.sourceSets { dependencies { api(project(":kmath-core")) api(project(":kmath-complex")) - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}") + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${space.kscience.gradle.KScienceVersions.coroutinesVersion}") } } } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts index 885f3c227..ee1950fa8 100644 --- a/kmath-dimensions/build.gradle.kts +++ b/kmath-dimensions/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } description = "A proof of concept module for adding type-safe dimensions to structures" @@ -21,5 +21,5 @@ kotlin.sourceSets { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts index 727d21e3a..d400d6600 100644 --- a/kmath-ejml/build.gradle.kts +++ b/kmath-ejml/build.gradle.kts @@ -2,7 +2,7 @@ import space.kscience.kmath.ejml.codegen.ejmlCodegen plugins { kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } dependencies { @@ -14,7 +14,7 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 18c2c50ad..6b6242c24 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } kotlin.sourceSets.commonMain { @@ -16,7 +16,7 @@ readme { All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. """.trimIndent() - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 337875ba4..c68102c2e 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } description = "Functions, integration and interpolation" @@ -19,7 +19,7 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature("piecewise", "src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt") { diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index bfe2e32a2..c9d8823bc 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } kotlin.sourceSets.commonMain { @@ -11,5 +11,5 @@ kotlin.sourceSets.commonMain { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 786086c9f..94d1f5fb7 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.mpp") + id("space.kscience.gradle.native") } //apply(plugin = "kotlinx-atomicfu") @@ -22,5 +22,5 @@ kotlin.sourceSets { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts index 925a2bc60..da77f469d 100644 --- a/kmath-jafama/build.gradle.kts +++ b/kmath-jafama/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("ru.mipt.npm.gradle.jvm") + id("space.kscience.gradle.jvm") } description = "Jafama integration module" @@ -14,7 +14,7 @@ repositories { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature("jafama-double", "src/main/kotlin/space/kscience/kmath/jafama/") { diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts index ca1a5485f..d92b6ca0d 100644 --- a/kmath-jupyter/build.gradle.kts +++ b/kmath-jupyter/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("ru.mipt.npm.gradle.jvm") + id("space.kscience.gradle.jvm") kotlin("jupyter.api") } @@ -14,7 +14,7 @@ kscience { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } kotlin.sourceSets.all { diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index 2f6d41bbb..a7f4ee37f 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } kotlin.sourceSets @@ -18,7 +18,7 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 2bd6dd723..55a7ff6aa 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -1,10 +1,10 @@ plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.mpp") + id("space.kscience.gradle.native") } readme { - maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT + maturity = space.kscience.gradle.Maturity.DEVELOPMENT description = """ An API and basic implementation for arranging objects in a continuous memory block. """.trimIndent() diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts index df2292f2e..0f31a183a 100644 --- a/kmath-multik/build.gradle.kts +++ b/kmath-multik/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("ru.mipt.npm.gradle.jvm") + id("space.kscience.gradle.jvm") } description = "JetBrains Multik connector" @@ -10,5 +10,5 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } \ No newline at end of file diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index 09264501f..11af7d6dc 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } description = "ND4J NDStructure implementation and according NDAlgebra classes" @@ -13,7 +13,7 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature(id = "nd4jarraystructure") { "NDStructure wrapper for INDArray" } feature(id = "nd4jarrayrings") { "Rings over Nd4jArrayStructure of Int and Long" } diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index 2e5bf6005..53f379830 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.mpp") + id("space.kscience.gradle.native") } kotlin.sourceSets { @@ -17,5 +17,5 @@ kotlin.sourceSets { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL } diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index 5e66f83ec..42b90a70e 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } description = "Polynomials, rational functions, and utilities" @@ -19,7 +19,7 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature("polynomial abstraction", "src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt") { diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index b458135b3..1d1831047 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.mpp") + id("space.kscience.gradle.native") } kotlin.sourceSets { @@ -20,5 +20,5 @@ kotlin.sourceSets { } readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = space.kscience.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts index 65c329d52..1984236ca 100644 --- a/kmath-symja/build.gradle.kts +++ b/kmath-symja/build.gradle.kts @@ -5,7 +5,7 @@ plugins { kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } description = "Symja integration module" @@ -38,5 +38,5 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts index 9380a7308..1e4ba12da 100644 --- a/kmath-tensorflow/build.gradle.kts +++ b/kmath-tensorflow/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("ru.mipt.npm.gradle.jvm") + id("space.kscience.gradle.jvm") } description = "Google tensorflow connector" @@ -11,5 +11,5 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE } \ No newline at end of file diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 66316d21d..b2a4c36bd 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } kotlin.sourceSets { @@ -22,7 +22,7 @@ kotlin.sourceSets { } readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts index db80be02a..f4dba25ab 100644 --- a/kmath-trajectory/build.gradle.kts +++ b/kmath-trajectory/build.gradle.kts @@ -1,7 +1,7 @@ plugins { kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.common") + id("space.kscience.gradle.native") } kotlin.sourceSets.commonMain { @@ -12,6 +12,6 @@ kotlin.sourceSets.commonMain { readme { description = "Path and trajectory optimization" - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + maturity = space.kscience.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) } diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts index 2e932b441..1b22e9c38 100644 --- a/kmath-viktor/build.gradle.kts +++ b/kmath-viktor/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("space.kscience.gradle.common") } description = "Binding for https://github.com/JetBrains-Research/viktor" @@ -11,5 +11,5 @@ dependencies { } readme { - maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT + maturity = space.kscience.gradle.Maturity.DEVELOPMENT } diff --git a/settings.gradle.kts b/settings.gradle.kts index 829e59144..f53232f44 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,7 +14,7 @@ dependencyResolutionManagement { versionCatalogs { create("npmlibs") { - from("ru.mipt.npm:version-catalog:$toolsVersion") + from("space.kscience:version-catalog:$toolsVersion") } } } diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts index 88c7ea9d0..49c4758e3 100644 --- a/test-utils/build.gradle.kts +++ b/test-utils/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") + id("space.kscience.gradle.mpp") + id("space.kscience.gradle.native") } kotlin.sourceSets { From 94562179354d5cf86d5894826ebee0afa88ca771 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 3 Aug 2022 17:29:01 +0300 Subject: [PATCH 158/174] Update multik algebra --- gradle.properties | 2 +- kmath-multik/build.gradle.kts | 2 +- .../kmath/multik/MultikDoubleAlgebra.kt | 4 + .../kmath/multik/MultikFloatAlgebra.kt | 22 ++++ .../kscience/kmath/multik/MultikIntAlgebra.kt | 20 ++++ .../kmath/multik/MultikLongAlgebra.kt | 22 ++++ .../kmath/multik/MultikShortAlgebra.kt | 20 ++++ .../kscience/kmath/multik/MultikTensor.kt | 40 +++++++ .../kmath/multik/MultikTensorAlgebra.kt | 102 +++++------------- 9 files changed, 154 insertions(+), 80 deletions(-) create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt create mode 100644 kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt diff --git a/gradle.properties b/gradle.properties index ca8c91191..b3e3f4cda 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ kotlin.code.style=official kotlin.jupyter.add.scanner=false kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true -//kotlin.incremental.js.ir=true +kotlin.incremental.js.ir=true org.gradle.configureondemand=true org.gradle.parallel=true diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts index 0f31a183a..ee31ead3c 100644 --- a/kmath-multik/build.gradle.kts +++ b/kmath-multik/build.gradle.kts @@ -6,7 +6,7 @@ description = "JetBrains Multik connector" dependencies { api(project(":kmath-tensors")) - api("org.jetbrains.kotlinx:multik-default:0.1.0") + api("org.jetbrains.kotlinx:multik-default:0.2.0") } readme { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index 0de2d8349..1d4665618 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -5,6 +5,8 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND @@ -54,6 +56,8 @@ public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra): MultikTensor = arg.map { atanh(it) } + + override fun scalar(value: Double): MultikTensor = Multik.ndarrayOf(value).wrap() } public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt new file mode 100644 index 000000000..8dd9b3f60 --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt @@ -0,0 +1,22 @@ +/* + * 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.multik + +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.ndarrayOf +import org.jetbrains.kotlinx.multik.ndarray.data.DataType +import space.kscience.kmath.operations.FloatField + +public object MultikFloatAlgebra : MultikDivisionTensorAlgebra() { + override val elementAlgebra: FloatField get() = FloatField + override val type: DataType get() = DataType.FloatDataType + + override fun scalar(value: Float): MultikTensor = Multik.ndarrayOf(value).wrap() +} + + +public val Float.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra +public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt new file mode 100644 index 000000000..b9e0125e8 --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt @@ -0,0 +1,20 @@ +/* + * 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.multik + +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.ndarrayOf +import org.jetbrains.kotlinx.multik.ndarray.data.DataType +import space.kscience.kmath.operations.IntRing + +public object MultikIntAlgebra : MultikTensorAlgebra() { + override val elementAlgebra: IntRing get() = IntRing + override val type: DataType get() = DataType.IntDataType + override fun scalar(value: Int): MultikTensor = Multik.ndarrayOf(value).wrap() +} + +public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra +public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt new file mode 100644 index 000000000..1f3dfb0e5 --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt @@ -0,0 +1,22 @@ +/* + * 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.multik + +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.ndarrayOf +import org.jetbrains.kotlinx.multik.ndarray.data.DataType +import space.kscience.kmath.operations.LongRing + +public object MultikLongAlgebra : MultikTensorAlgebra() { + override val elementAlgebra: LongRing get() = LongRing + override val type: DataType get() = DataType.LongDataType + + override fun scalar(value: Long): MultikTensor = Multik.ndarrayOf(value).wrap() +} + + +public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra +public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt new file mode 100644 index 000000000..b9746571d --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt @@ -0,0 +1,20 @@ +/* + * 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.multik + +import org.jetbrains.kotlinx.multik.api.Multik +import org.jetbrains.kotlinx.multik.api.ndarrayOf +import org.jetbrains.kotlinx.multik.ndarray.data.DataType +import space.kscience.kmath.operations.ShortRing + +public object MultikShortAlgebra : MultikTensorAlgebra() { + override val elementAlgebra: ShortRing get() = ShortRing + override val type: DataType get() = DataType.ShortDataType + override fun scalar(value: Short): MultikTensor = Multik.ndarrayOf(value).wrap() +} + +public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra +public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt new file mode 100644 index 000000000..7efe672b4 --- /dev/null +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt @@ -0,0 +1,40 @@ +/* + * 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.multik + +import org.jetbrains.kotlinx.multik.ndarray.data.* +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.Shape +import space.kscience.kmath.tensors.api.Tensor + +@JvmInline +public value class MultikTensor(public val array: MutableMultiArray) : Tensor { + override val shape: Shape get() = array.shape + + override fun get(index: IntArray): T = array[index] + + @PerformancePitfall + override fun elements(): Sequence> = + array.multiIndices.iterator().asSequence().map { it to get(it) } + + override fun set(index: IntArray, value: T) { + array[index] = value + } +} + + +internal fun MultiArray.asD1Array(): D1Array { + if (this is NDArray) + return this.asD1Array() + else throw ClassCastException("Cannot cast MultiArray to NDArray.") +} + + +internal fun MultiArray.asD2Array(): D2Array { + if (this is NDArray) + return this.asD2Array() + else throw ClassCastException("Cannot cast MultiArray to NDArray.") +} \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index 250ef7e7f..1cc1b9b6d 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -10,46 +10,16 @@ package space.kscience.kmath.multik import org.jetbrains.kotlinx.multik.api.* import org.jetbrains.kotlinx.multik.api.linalg.LinAlg import org.jetbrains.kotlinx.multik.api.math.Math +import org.jetbrains.kotlinx.multik.api.stat.Statistics import org.jetbrains.kotlinx.multik.ndarray.data.* import org.jetbrains.kotlinx.multik.ndarray.operations.* import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.mapInPlace +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra -@JvmInline -public value class MultikTensor(public val array: MutableMultiArray) : Tensor { - override val shape: Shape get() = array.shape - - override fun get(index: IntArray): T = array[index] - - @PerformancePitfall - override fun elements(): Sequence> = - array.multiIndices.iterator().asSequence().map { it to get(it) } - - override fun set(index: IntArray, value: T) { - array[index] = value - } -} - -private fun MultiArray.asD1Array(): D1Array { - if (this is NDArray) - return this.asD1Array() - else throw ClassCastException("Cannot cast MultiArray to NDArray.") -} - - -private fun MultiArray.asD2Array(): D2Array { - if (this is NDArray) - return this.asD2Array() - else throw ClassCastException("Cannot cast MultiArray to NDArray.") -} - public abstract class MultikTensorAlgebra> : TensorAlgebra where T : Number, T : Comparable { @@ -59,7 +29,6 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra protected val multikLinAl: LinAlg = mk.linalg protected val multikStat: Statistics = mk.stat - override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { val strides = DefaultStrides(shape) val memoryView = initMemoryView(strides.linearSize, type) @@ -240,11 +209,15 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun Tensor.viewAs(other: StructureND): MultikTensor = view(other.shape) + public abstract fun scalar(value: T): MultikTensor + override fun StructureND.dot(other: StructureND): MultikTensor = if (this.shape.size == 1 && other.shape.size == 1) { - Multik.ndarrayOf( - multikLinAl.linAlgEx.dotVV(asMultik().array.asD1Array(), other.asMultik().array.asD1Array()) - ).wrap() + scalar( + multikLinAl.linAlgEx.dotVV( + asMultik().array.asD1Array(), other.asMultik().array.asD1Array() + ) + ) } else if (this.shape.size == 2 && other.shape.size == 2) { multikLinAl.linAlgEx.dotMM(asMultik().array.asD2Array(), other.asMultik().array.asD2Array()).wrap() } else if (this.shape.size == 2 && other.shape.size == 1) { @@ -254,41 +227,46 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra } override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): MultikTensor { + TODO("Diagonal embedding not implemented") } - override fun StructureND.sum(): T = asMultik().array.reduceMultiIndexed { _: IntArray, acc: T, t: T -> - elementAlgebra.add(acc, t) - } + override fun StructureND.sum(): T = multikMath.sum(asMultik().array) override fun StructureND.sum(dim: Int, keepDim: Boolean): MultikTensor { - TODO("Not yet implemented") + if (keepDim) TODO("keepDim not implemented") + return multikMath.sumDN(asMultik().array, dim).wrap() } override fun StructureND.min(): T? = asMultik().array.min() override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + if (keepDim) TODO("keepDim not implemented") + return multikMath.minDN(asMultik().array, dim).wrap() } override fun StructureND.max(): T? = asMultik().array.max() override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + if (keepDim) TODO("keepDim not implemented") + return multikMath.maxDN(asMultik().array, dim).wrap() } override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") + if (keepDim) TODO("keepDim not implemented") + val res = multikMath.argMaxDN(asMultik().array, dim) + return with(MultikIntAlgebra) { res.wrap() } } } public abstract class MultikDivisionTensorAlgebra> : MultikTensorAlgebra(), TensorPartialDivisionAlgebra where T : Number, T : Comparable { - override fun T.div(arg: StructureND): MultikTensor = arg.map { elementAlgebra.divide(this@div, it) } + override fun T.div(arg: StructureND): MultikTensor = + Multik.ones(arg.shape, type).apply { divAssign(arg.asMultik().array) }.wrap() override fun StructureND.div(arg: T): MultikTensor = - asMultik().array.deepCopy().apply { divAssign(arg) }.wrap() + asMultik().array.div(arg).wrap() override fun StructureND.div(arg: StructureND): MultikTensor = asMultik().array.div(arg.asMultik().array).wrap() @@ -308,36 +286,4 @@ public abstract class MultikDivisionTensorAlgebra> mapInPlace { index, t -> elementAlgebra.divide(t, arg[index]) } } } -} - -public object MultikFloatAlgebra : MultikDivisionTensorAlgebra() { - override val elementAlgebra: FloatField get() = FloatField - override val type: DataType get() = DataType.FloatDataType -} - -public val Float.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra -public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra - -public object MultikShortAlgebra : MultikTensorAlgebra() { - override val elementAlgebra: ShortRing get() = ShortRing - override val type: DataType get() = DataType.ShortDataType -} - -public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra -public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra - -public object MultikIntAlgebra : MultikTensorAlgebra() { - override val elementAlgebra: IntRing get() = IntRing - override val type: DataType get() = DataType.IntDataType -} - -public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra -public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra - -public object MultikLongAlgebra : MultikTensorAlgebra() { - override val elementAlgebra: LongRing get() = LongRing - override val type: DataType get() = DataType.LongDataType -} - -public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra -public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file +} \ No newline at end of file From 5402ba47c90be0f24f4642dd78adb5ed208c4c08 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 3 Aug 2022 18:10:44 +0300 Subject: [PATCH 159/174] Restrict tensor dot ot vectors and matrices only. Introduce bdot to Double TensorAlgebra for broadcasting operations. --- CHANGELOG.md | 3 +- .../kmath/tensors/api/TensorAlgebra.kt | 11 +---- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 46 +++++++++++++++++-- .../core/TestDoubleLinearOpsAlgebra.kt | 12 ++--- .../tensors/core/TestDoubleTensorAlgebra.kt | 4 +- 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66d83ec34..03fb4cf8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,9 @@ - Algebra now has an obligatory `bufferFactory` (#477). ### Changed -- Kotlin 1.7 +- Kotlin 1.7.20 - `LazyStructure` `deffered` -> `async` to comply with coroutines code style +- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `bdot` operation is added to `DoubleTensorAlgebra`. ### Deprecated diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 86d4eaa4e..1b11dc54f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -213,16 +213,7 @@ public interface TensorAlgebra> : RingOpsND { * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, * the matrix-vector product is returned. * - * 5. If both arguments are at least 1-dimensional and at least one argument is N-dimensional (where N > 2), - * then a batched matrix multiply is returned. If the first argument is 1-dimensional, - * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. - * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix - * multiple and removed after. - * The non-matrix (i.e., batch) dimensions are broadcast (and thus must be broadcastable). - * For example, if `input` is a (j × 1 × n × n) tensor and `other` is a - * (k × n × n) tensor, out will be a (j × k × n × n) tensor. - * - * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html + * Otherwise, throw an exception. * * @param other tensor to be multiplied. * @return a mathematical product of two tensors. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index e9dc34748..af4150f5b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -381,7 +381,36 @@ public open class DoubleTensorAlgebra : override fun Tensor.viewAs(other: StructureND): DoubleTensor = tensor.view(other.shape) - override infix fun StructureND.dot(other: StructureND): DoubleTensor { + /** + * Broadcasting Matrix product of two tensors. + * + * The behavior depends on the dimensionality of the tensors as follows: + * 1. If both tensors are 1-dimensional, the dot product (scalar) is returned. + * + * 2. If both arguments are 2-dimensional, the matrix-matrix product is returned. + * + * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, + * a 1 is prepended to its dimension for the purpose of the matrix multiply. + * After the matrix multiply, depending on the implementation the prepended dimension might be removed. + * + * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, + * the matrix-vector product is returned. + * + * 5. If both arguments are at least 1-dimensional and at least one argument is N-dimensional (where N > 2), + * then a batched matrix multiply is returned. If the first argument is 1-dimensional, + * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. + * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix + * multiple and removed after. + * The non-matrix (i.e., batch) dimensions are broadcast (and thus must be broadcastable). + * For example, if `input` is a (j × 1 × n × n) tensor and `other` is a + * (k × n × n) tensor, out will be a (j × k × n × n) tensor. + * + * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html + * + * @param other tensor to be multiplied. + * @return a mathematical product of two tensors. + */ + public infix fun StructureND.bdot(other: StructureND): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) } @@ -430,6 +459,11 @@ public open class DoubleTensorAlgebra : } } + override fun StructureND.dot(other: StructureND): DoubleTensor { + return if (dimension in 0..2 && other.dimension in 0..2) bdot(other) + else error("Only vectors and matrices are allowed in non-broadcasting dot operation") + } + override fun diagonalEmbedding( diagonalEntries: Tensor, offset: Int, @@ -587,7 +621,8 @@ public open class DoubleTensorAlgebra : val resNumElements = resShape.reduce(Int::times) val init = foldFunction(DoubleArray(1) { 0.0 }) val resTensor = BufferedTensor(resShape, - MutableBuffer.auto(resNumElements) { init }, 0) + MutableBuffer.auto(resNumElements) { init }, 0 + ) for (index in resTensor.indices) { val prefix = index.take(dim).toIntArray() val suffix = index.takeLast(dimension - dim - 1).toIntArray() @@ -882,7 +917,8 @@ public open class DoubleTensorAlgebra : return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } - override fun StructureND.symEig(): Pair = symEigJacobi(maxIteration = 50, epsilon = 1e-15) + override fun StructureND.symEig(): Pair = + symEigJacobi(maxIteration = 50, epsilon = 1e-15) /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, @@ -909,7 +945,7 @@ public open class DoubleTensorAlgebra : val (u, s, v) = tensor.svd(epsilon) val shp = s.shape + intArrayOf(1) - val utv = u.transpose() dot v + val utv = u.transpose() bdot v val n = s.shape.last() for (matrix in utv.matrixSequence()) { matrix.as2D().cleanSym(n) @@ -951,7 +987,7 @@ public open class DoubleTensorAlgebra : private fun MutableStructure2D.jacobiHelper( maxIteration: Int, - epsilon: Double + epsilon: Double, ): Pair, Structure2D> { val n = this.shape[0] val A_ = this.copy() diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index e025d4b71..6ae7ae8ef 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -115,7 +115,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { assertTrue { q.shape contentEquals shape } assertTrue { r.shape contentEquals shape } - assertTrue((q dot r).eq(tensor)) + assertTrue((q bdot r).eq(tensor)) } @@ -136,17 +136,17 @@ internal class TestDoubleLinearOpsTensorAlgebra { assertTrue { l.shape contentEquals shape } assertTrue { u.shape contentEquals shape } - assertTrue((p dot tensor).eq(l dot u)) + assertTrue((p bdot tensor).eq(l bdot u)) } @Test fun testCholesky() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 5), 0) - val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( + val sigma = (tensor bdot tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) ) val low = sigma.cholesky() - val sigmChol = low dot low.transpose() + val sigmChol = low bdot low.transpose() assertTrue(sigma.eq(sigmChol)) } @@ -171,7 +171,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { fun testBatchedSVD() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() - val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) + val tensorSVD = tensorU bdot (diagonalEmbedding(tensorS) bdot tensorV.transpose()) assertTrue(tensor.eq(tensorSVD)) } @@ -180,7 +180,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() - val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) + val tensorSigmaCalc = tensorV bdot (diagonalEmbedding(tensorS) bdot tensorV.transpose()) assertTrue(tensorSigma.eq(tensorSigmaCalc)) } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 205ae2fee..2f3c8e2de 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -114,7 +114,7 @@ internal class TestDoubleTensorAlgebra { assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(140.0, 320.0)) assertTrue(res12.shape contentEquals intArrayOf(2)) - val res32 = tensor3.dot(tensor2) + val res32 = tensor3.bdot(tensor2) assertTrue(res32.mutableBuffer.array() contentEquals doubleArrayOf(-140.0)) assertTrue(res32.shape contentEquals intArrayOf(1, 1)) @@ -126,7 +126,7 @@ internal class TestDoubleTensorAlgebra { assertTrue(res11.mutableBuffer.array() contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) assertTrue(res11.shape contentEquals intArrayOf(2, 2)) - val res45 = tensor4.dot(tensor5) + val res45 = tensor4.bdot(tensor5) assertTrue(res45.mutableBuffer.array() contentEquals doubleArrayOf( 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 From ee0d44e12e557b9b997b180ccfdb50d61bb90051 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 3 Aug 2022 18:20:46 +0300 Subject: [PATCH 160/174] rename bdot to matmul --- CHANGELOG.md | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 8 +++++--- .../kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 12 ++++++------ .../kmath/tensors/core/TestDoubleTensorAlgebra.kt | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03fb4cf8c..f5ed80597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Changed - Kotlin 1.7.20 - `LazyStructure` `deffered` -> `async` to comply with coroutines code style -- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `bdot` operation is added to `DoubleTensorAlgebra`. +- Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added to `DoubleTensorAlgebra`. ### Deprecated diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index af4150f5b..63193fe4c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -9,6 +9,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.MutableBuffer @@ -410,7 +411,8 @@ public open class DoubleTensorAlgebra : * @param other tensor to be multiplied. * @return a mathematical product of two tensors. */ - public infix fun StructureND.bdot(other: StructureND): DoubleTensor { + @UnstableKMathAPI + public infix fun StructureND.matmul(other: StructureND): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) } @@ -460,7 +462,7 @@ public open class DoubleTensorAlgebra : } override fun StructureND.dot(other: StructureND): DoubleTensor { - return if (dimension in 0..2 && other.dimension in 0..2) bdot(other) + return if (dimension in 0..2 && other.dimension in 0..2) matmul(other) else error("Only vectors and matrices are allowed in non-broadcasting dot operation") } @@ -945,7 +947,7 @@ public open class DoubleTensorAlgebra : val (u, s, v) = tensor.svd(epsilon) val shp = s.shape + intArrayOf(1) - val utv = u.transpose() bdot v + val utv = u.transpose() matmul v val n = s.shape.last() for (matrix in utv.matrixSequence()) { matrix.as2D().cleanSym(n) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 6ae7ae8ef..98ee9e3cb 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -115,7 +115,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { assertTrue { q.shape contentEquals shape } assertTrue { r.shape contentEquals shape } - assertTrue((q bdot r).eq(tensor)) + assertTrue((q matmul r).eq(tensor)) } @@ -136,17 +136,17 @@ internal class TestDoubleLinearOpsTensorAlgebra { assertTrue { l.shape contentEquals shape } assertTrue { u.shape contentEquals shape } - assertTrue((p bdot tensor).eq(l bdot u)) + assertTrue((p matmul tensor).eq(l matmul u)) } @Test fun testCholesky() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 5), 0) - val sigma = (tensor bdot tensor.transpose()) + diagonalEmbedding( + val sigma = (tensor matmul tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) ) val low = sigma.cholesky() - val sigmChol = low bdot low.transpose() + val sigmChol = low matmul low.transpose() assertTrue(sigma.eq(sigmChol)) } @@ -171,7 +171,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { fun testBatchedSVD() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() - val tensorSVD = tensorU bdot (diagonalEmbedding(tensorS) bdot tensorV.transpose()) + val tensorSVD = tensorU matmul (diagonalEmbedding(tensorS) matmul tensorV.transpose()) assertTrue(tensor.eq(tensorSVD)) } @@ -180,7 +180,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() - val tensorSigmaCalc = tensorV bdot (diagonalEmbedding(tensorS) bdot tensorV.transpose()) + val tensorSigmaCalc = tensorV matmul (diagonalEmbedding(tensorS) matmul tensorV.transpose()) assertTrue(tensorSigma.eq(tensorSigmaCalc)) } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 2f3c8e2de..bca6e65d0 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -114,7 +114,7 @@ internal class TestDoubleTensorAlgebra { assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(140.0, 320.0)) assertTrue(res12.shape contentEquals intArrayOf(2)) - val res32 = tensor3.bdot(tensor2) + val res32 = tensor3.matmul(tensor2) assertTrue(res32.mutableBuffer.array() contentEquals doubleArrayOf(-140.0)) assertTrue(res32.shape contentEquals intArrayOf(1, 1)) @@ -126,7 +126,7 @@ internal class TestDoubleTensorAlgebra { assertTrue(res11.mutableBuffer.array() contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) assertTrue(res11.shape contentEquals intArrayOf(2, 2)) - val res45 = tensor4.bdot(tensor5) + val res45 = tensor4.matmul(tensor5) assertTrue(res45.mutableBuffer.array() contentEquals doubleArrayOf( 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 From a8182fad23417f4302ea77ccdeba3b931e50a471 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 4 Aug 2022 09:54:59 +0300 Subject: [PATCH 161/174] Multik went MPP --- CHANGELOG.md | 1 + benchmarks/build.gradle.kts | 10 ++++++--- .../kscience/kmath/benchmarks/DotBenchmark.kt | 3 +-- .../kmath/benchmarks/NDFieldBenchmark.kt | 6 ++---- .../kscience/kmath/benchmarks/globals.kt | 11 ++++++++++ build.gradle.kts | 2 ++ examples/build.gradle.kts | 3 +++ .../space/kscience/kmath/tensors/multik.kt | 9 +++++--- kmath-multik/build.gradle.kts | 21 +++++++++++++++---- .../kmath/multik/MultikDoubleAlgebra.kt | 9 +++++--- .../kmath/multik/MultikFloatAlgebra.kt | 9 +++++--- .../kscience/kmath/multik/MultikIntAlgebra.kt | 9 +++++--- .../kmath/multik/MultikLongAlgebra.kt | 9 +++++--- .../kmath/multik/MultikShortAlgebra.kt | 9 +++++--- .../kscience/kmath/multik/MultikTensor.kt | 1 + .../kmath/multik/MultikTensorAlgebra.kt | 18 +++++++++------- .../kscience/kmath/multik/MultikNDTest.kt | 16 +++++++------- 17 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt (87%) rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt (62%) rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt (63%) rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt (63%) rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt (62%) rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikTensor.kt (97%) rename kmath-multik/src/{main => commonMain}/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt (94%) rename kmath-multik/src/{test => commonTest}/kotlin/space/kscience/kmath/multik/MultikNDTest.kt (72%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5ed80597..acec30836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Kotlin 1.7.20 - `LazyStructure` `deffered` -> `async` to comply with coroutines code style - Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added to `DoubleTensorAlgebra`. +- Multik went MPP ### Deprecated diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index e86990043..9c8dc613a 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -1,5 +1,6 @@ @file:Suppress("UNUSED_VARIABLE") +import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile import space.kscience.kmath.benchmarks.addBenchmarkProperties plugins { @@ -15,6 +16,8 @@ repositories { mavenCentral() } +val multikVersion: String by rootProject.extra + kotlin { jvm() @@ -39,7 +42,9 @@ kotlin { implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) implementation(project(":kmath-tensors")) - implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.2") + implementation(project(":kmath-multik")) + implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") + implementation(npmlibs.kotlinx.benchmark.runtime) } } @@ -51,7 +56,6 @@ kotlin { implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) implementation(project(":kmath-jafama")) - implementation(project(":kmath-multik")) implementation(projects.kmath.kmathTensorflow) implementation("org.tensorflow:tensorflow-core-platform:0.4.0") implementation("org.nd4j:nd4j-native:1.0.0-M1") @@ -155,7 +159,7 @@ kotlin.sourceSets.all { } } -tasks.withType { +tasks.withType { kotlinOptions { jvmTarget = "11" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy" diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 7ceecb5ab..d7ead6dd8 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -13,7 +13,6 @@ import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM import space.kscience.kmath.linear.invoke import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensorflow.produceWithTF @@ -78,7 +77,7 @@ internal class DotBenchmark { } @Benchmark - fun multikDot(blackhole: Blackhole) = with(DoubleField.multikAlgebra) { + fun multikDot(blackhole: Blackhole) = with(multikAlgebra) { blackhole.consume(matrix1 dot matrix2) } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index 89673acd4..eb5e1da47 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ones import org.jetbrains.kotlinx.multik.ndarray.data.DN import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.nd.BufferedFieldOpsND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.ndAlgebra @@ -43,7 +42,7 @@ internal class NDFieldBenchmark { } @Benchmark - fun multikAdd(blackhole: Blackhole) = with(multikField) { + fun multikAdd(blackhole: Blackhole) = with(multikAlgebra) { var res: StructureND = one(shape) repeat(n) { res += 1.0 } blackhole.consume(res) @@ -71,7 +70,7 @@ internal class NDFieldBenchmark { } @Benchmark - fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikAlgebra) { + fun multikInPlaceAdd(blackhole: Blackhole) = with(multikAlgebra) { val res = Multik.ones(shape, DataType.DoubleDataType).wrap() repeat(n) { res += 1.0 } blackhole.consume(res) @@ -91,7 +90,6 @@ internal class NDFieldBenchmark { private val specializedField = DoubleField.ndAlgebra private val genericField = BufferedFieldOpsND(DoubleField) private val nd4jField = DoubleField.nd4j - private val multikField = DoubleField.multikAlgebra private val viktorField = DoubleField.viktorAlgebra } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt new file mode 100644 index 000000000..9f235c56e --- /dev/null +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt @@ -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.benchmarks + +import org.jetbrains.kotlinx.multik.default.DefaultEngine +import space.kscience.kmath.multik.MultikDoubleAlgebra + +val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index c57b29105..b6e5b0748 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -74,3 +74,5 @@ ksciencePublish { } apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") + +val multikVersion by extra("0.2.0") diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index cfa50815d..1d224bace 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -8,6 +8,8 @@ repositories { maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") } +val multikVersion: String by rootProject.extra + dependencies { implementation(project(":kmath-ast")) implementation(project(":kmath-kotlingrad")) @@ -30,6 +32,7 @@ dependencies { implementation(project(":kmath-jafama")) //multik implementation(project(":kmath-multik")) + implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") implementation("org.nd4j:nd4j-native:1.0.0-beta7") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index f2d1f0b41..7cf1c5120 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -7,11 +7,14 @@ package space.kscience.kmath.tensors import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarray -import space.kscience.kmath.multik.multikAlgebra +import org.jetbrains.kotlinx.multik.default.DefaultEngine +import space.kscience.kmath.multik.MultikDoubleAlgebra import space.kscience.kmath.nd.one -import space.kscience.kmath.operations.DoubleField -fun main(): Unit = with(DoubleField.multikAlgebra) { + +val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) + +fun main(): Unit = with(multikAlgebra) { val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() one(a.shape) - a + b * 3.0 diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts index ee31ead3c..39c03ab9b 100644 --- a/kmath-multik/build.gradle.kts +++ b/kmath-multik/build.gradle.kts @@ -1,12 +1,25 @@ plugins { - id("space.kscience.gradle.jvm") + id("space.kscience.gradle.mpp") } description = "JetBrains Multik connector" -dependencies { - api(project(":kmath-tensors")) - api("org.jetbrains.kotlinx:multik-default:0.2.0") +val multikVersion: String by rootProject.extra + +kotlin{ + sourceSets{ + commonMain{ + dependencies{ + api(project(":kmath-tensors")) + api("org.jetbrains.kotlinx:multik-core:$multikVersion") + } + } + commonTest{ + dependencies{ + api("org.jetbrains.kotlinx:multik-default:$multikVersion") + } + } + } } readme { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt similarity index 87% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index 1d4665618..dcc1623cc 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Engine import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType @@ -14,7 +15,9 @@ import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExponentialOperations import space.kscience.kmath.operations.TrigonometricOperations -public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra(), +public class MultikDoubleAlgebra( + multikEngine: Engine +) : MultikDivisionTensorAlgebra(multikEngine), TrigonometricOperations>, ExponentialOperations> { override val elementAlgebra: DoubleField get() = DoubleField override val type: DataType get() = DataType.DoubleDataType @@ -60,6 +63,6 @@ public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra = Multik.ndarrayOf(value).wrap() } -public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra -public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra +//public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra +//public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt similarity index 62% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt index 8dd9b3f60..db251b552 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt @@ -5,12 +5,15 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Engine import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType import space.kscience.kmath.operations.FloatField -public object MultikFloatAlgebra : MultikDivisionTensorAlgebra() { +public class MultikFloatAlgebra( + multikEngine: Engine +) : MultikDivisionTensorAlgebra(multikEngine) { override val elementAlgebra: FloatField get() = FloatField override val type: DataType get() = DataType.FloatDataType @@ -18,5 +21,5 @@ public object MultikFloatAlgebra : MultikDivisionTensorAlgebra get() = MultikFloatAlgebra -public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra \ No newline at end of file +//public val Float.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra +//public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt similarity index 63% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt index b9e0125e8..517845939 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt @@ -5,16 +5,19 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Engine import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType import space.kscience.kmath.operations.IntRing -public object MultikIntAlgebra : MultikTensorAlgebra() { +public class MultikIntAlgebra( + multikEngine: Engine +) : MultikTensorAlgebra(multikEngine) { override val elementAlgebra: IntRing get() = IntRing override val type: DataType get() = DataType.IntDataType override fun scalar(value: Int): MultikTensor = Multik.ndarrayOf(value).wrap() } -public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra -public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra \ No newline at end of file +//public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra +//public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt similarity index 63% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt index 1f3dfb0e5..9c6c1af54 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt @@ -5,12 +5,15 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Engine import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType import space.kscience.kmath.operations.LongRing -public object MultikLongAlgebra : MultikTensorAlgebra() { +public class MultikLongAlgebra( + multikEngine: Engine +) : MultikTensorAlgebra(multikEngine) { override val elementAlgebra: LongRing get() = LongRing override val type: DataType get() = DataType.LongDataType @@ -18,5 +21,5 @@ public object MultikLongAlgebra : MultikTensorAlgebra() { } -public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra -public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file +//public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra +//public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt similarity index 62% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt index b9746571d..5288351b2 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt @@ -5,16 +5,19 @@ package space.kscience.kmath.multik +import org.jetbrains.kotlinx.multik.api.Engine import org.jetbrains.kotlinx.multik.api.Multik import org.jetbrains.kotlinx.multik.api.ndarrayOf import org.jetbrains.kotlinx.multik.ndarray.data.DataType import space.kscience.kmath.operations.ShortRing -public object MultikShortAlgebra : MultikTensorAlgebra() { +public class MultikShortAlgebra( + multikEngine: Engine +) : MultikTensorAlgebra(multikEngine) { override val elementAlgebra: ShortRing get() = ShortRing override val type: DataType get() = DataType.ShortDataType override fun scalar(value: Short): MultikTensor = Multik.ndarrayOf(value).wrap() } -public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra -public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra \ No newline at end of file +//public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra +//public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt similarity index 97% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt index 7efe672b4..3ab4b0e3d 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensor.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlinx.multik.ndarray.data.* import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Shape import space.kscience.kmath.tensors.api.Tensor +import kotlin.jvm.JvmInline @JvmInline public value class MultikTensor(public val array: MutableMultiArray) : Tensor { diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt similarity index 94% rename from kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt rename to kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index 1cc1b9b6d..f9768ea39 100644 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -20,14 +20,15 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra -public abstract class MultikTensorAlgebra> : TensorAlgebra - where T : Number, T : Comparable { +public abstract class MultikTensorAlgebra>( + private val multikEngine: Engine, +) : TensorAlgebra where T : Number, T : Comparable { public abstract val type: DataType - protected val multikMath: Math = mk.math - protected val multikLinAl: LinAlg = mk.linalg - protected val multikStat: Statistics = mk.stat + protected val multikMath: Math = multikEngine.getMath() + protected val multikLinAl: LinAlg = multikEngine.getLinAlg() + protected val multikStat: Statistics = multikEngine.getStatistics() override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { val strides = DefaultStrides(shape) @@ -255,12 +256,13 @@ public abstract class MultikTensorAlgebra> : TensorAlgebra override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { if (keepDim) TODO("keepDim not implemented") val res = multikMath.argMaxDN(asMultik().array, dim) - return with(MultikIntAlgebra) { res.wrap() } + return with(MultikIntAlgebra(multikEngine)) { res.wrap() } } } -public abstract class MultikDivisionTensorAlgebra> - : MultikTensorAlgebra(), TensorPartialDivisionAlgebra where T : Number, T : Comparable { +public abstract class MultikDivisionTensorAlgebra>( + multikEngine: Engine, +) : MultikTensorAlgebra(multikEngine), TensorPartialDivisionAlgebra where T : Number, T : Comparable { override fun T.div(arg: StructureND): MultikTensor = Multik.ones(arg.shape, type).apply { divAssign(arg.asMultik().array) }.wrap() diff --git a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt similarity index 72% rename from kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt rename to kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index 72c43d8e6..8bc43eef2 100644 --- a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -5,33 +5,35 @@ package space.kscience.kmath.multik -import org.junit.jupiter.api.Test +import org.jetbrains.kotlinx.multik.default.DefaultEngine import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.tensorAlgebra +import kotlin.test.Test import kotlin.test.assertTrue internal class MultikNDTest { + val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) + @Test - fun basicAlgebra(): Unit = DoubleField.multikAlgebra{ - one(2,2) + 1.0 + fun basicAlgebra(): Unit = with(multikAlgebra) { + one(2, 2) + 1.0 } @Test - fun dotResult(){ + fun dotResult() { val dim = 100 val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) - val multikResult = with(DoubleField.multikAlgebra){ + val multikResult = with(multikAlgebra) { tensor1 dot tensor2 } - val defaultResult = with(DoubleField.tensorAlgebra){ + val defaultResult = with(DoubleField.tensorAlgebra) { tensor1 dot tensor2 } From b6d2eb3b1b3ef37df5b02dfe5c4ef18b1e72ef6e Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 19 Aug 2022 15:19:01 +0300 Subject: [PATCH 162/174] Replace main `mipt-npm` appearances with `SciProgCentre`. Now link in "Documentation site (WIP)" works. --- README.md | 6 +++--- build.gradle.kts | 2 +- docs/templates/README-TEMPLATE.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b9d36df50..03e803180 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) -![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) +![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) [![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) @@ -11,7 +11,7 @@ analog to Python's NumPy library. Later we found that kotlin is much more flexib architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. -[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) +[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/) ## Publications and talks @@ -325,4 +325,4 @@ Gradle `6.0+` is required for multiplatform artifacts. The project requires a lot of additional work. The most important thing we need is a feedback about what features are required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues marked with -[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file +[waiting for a hero](https://github.com/SciProgCentre/kmath/labels/waiting%20for%20a%20hero) label. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index b6e5b0748..d20d7f4ca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ subprojects { localDirectory.set(kotlinDir) remoteUrl.set( - java.net.URL("https://github.com/mipt-npm/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") + java.net.URL("https://github.com/SciProgCentre/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") ) } diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index 1633f3ff1..d7d5a806d 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -1,6 +1,6 @@ [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) -![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) +![Gradle build](https://github.com/SciProgCentre/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) [![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) @@ -11,7 +11,7 @@ analog to Python's NumPy library. Later we found that kotlin is much more flexib architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. -[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) +[Documentation site (**WIP**)](https://SciProgCentre.github.io/kmath/) ## Publications and talks From efe14f50bf9c8aa8465d189b35acbdb5f5bba754 Mon Sep 17 00:00:00 2001 From: Gleb Minaev <43728100+lounres@users.noreply.github.com> Date: Fri, 19 Aug 2022 15:59:13 +0300 Subject: [PATCH 163/174] #472: Update copyright. --- .idea/copyright/kmath.xml | 11 ++++++----- .idea/copyright/profiles_settings.xml | 2 +- .../benchmarks/ExpressionsInterpretersBenchmark.kt | 2 +- .../space/kscience/kmath/benchmarks/ArrayBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/BigIntBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/BufferBenchmark.kt | 2 +- .../space/kscience/kmath/benchmarks/DotBenchmark.kt | 2 +- .../benchmarks/ExpressionsInterpretersBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/JafamaBenchmark.kt | 2 +- .../kmath/benchmarks/MatrixInverseBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/NDFieldBenchmark.kt | 2 +- .../kmath/benchmarks/TensorAlgebraBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/ViktorBenchmark.kt | 2 +- .../kscience/kmath/benchmarks/ViktorLogBenchmark.kt | 2 +- .../kotlin/space/kscience/kmath/benchmarks/globals.kt | 2 +- .../space/kscience/kmath/benchmarks/JmhReport.kt | 2 +- .../kmath/benchmarks/addBenchmarkProperties.kt | 2 +- .../space/kscience/kmath/ejml/codegen/ejmlCodegen.kt | 2 +- docs/images/KM.svg | 2 +- docs/images/KM_mono.svg | 2 +- docs/images/KMath.svg | 2 +- docs/images/KMath_mono.svg | 2 +- .../kotlin/space/kscience/kmath/ast/astRendering.kt | 2 +- .../kotlin/space/kscience/kmath/ast/expressions.kt | 2 +- .../space/kscience/kmath/ast/kotlingradSupport.kt | 2 +- .../kotlin/space/kscience/kmath/ast/symjaSupport.kt | 2 +- .../kotlin/space/kscience/kmath/fit/chiSquared.kt | 2 +- .../main/kotlin/space/kscience/kmath/fit/qowFit.kt | 2 +- .../space/kscience/kmath/functions/integrate.kt | 2 +- .../space/kscience/kmath/functions/interpolate.kt | 2 +- .../kscience/kmath/functions/interpolateSquare.kt | 2 +- .../kscience/kmath/functions/matrixIntegration.kt | 2 +- .../space/kscience/kmath/functions/polynomials.kt | 2 +- .../kotlin/space/kscience/kmath/jafama/JafamaDemo.kt | 2 +- .../space/kscience/kmath/linear/dotPerformance.kt | 2 +- .../kotlin/space/kscience/kmath/linear/gradient.kt | 2 +- .../space/kscience/kmath/operations/BigIntDemo.kt | 2 +- .../space/kscience/kmath/operations/complexDemo.kt | 2 +- .../kscience/kmath/operations/mixedNDOperations.kt | 2 +- .../kscience/kmath/stat/DistributionBenchmark.kt | 2 +- .../space/kscience/kmath/stat/DistributionDemo.kt | 2 +- .../space/kscience/kmath/structures/ComplexND.kt | 2 +- .../kotlin/space/kscience/kmath/structures/NDField.kt | 2 +- .../kscience/kmath/structures/StreamDoubleFieldND.kt | 2 +- .../kmath/structures/StructureReadBenchmark.kt | 2 +- .../kmath/structures/StructureWriteBenchmark.kt | 2 +- .../kotlin/space/kscience/kmath/structures/buffers.kt | 2 +- .../kscience/kmath/structures/typeSafeDimensions.kt | 2 +- .../kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt | 2 +- .../main/kotlin/space/kscience/kmath/tensors/PCA.kt | 2 +- .../kscience/kmath/tensors/dataSetNormalization.kt | 2 +- .../kmath/tensors/linearSystemSolvingWithLUP.kt | 2 +- .../kotlin/space/kscience/kmath/tensors/multik.kt | 2 +- .../space/kscience/kmath/tensors/neuralNetwork.kt | 2 +- .../kotlin/space/kscience/kmath/ast/TypedMst.kt | 2 +- .../space/kscience/kmath/ast/evaluateConstants.kt | 2 +- .../kotlin/space/kscience/kmath/ast/parser.kt | 2 +- .../kmath/ast/rendering/LatexSyntaxRenderer.kt | 2 +- .../kmath/ast/rendering/MathMLSyntaxRenderer.kt | 2 +- .../kscience/kmath/ast/rendering/MathRenderer.kt | 2 +- .../space/kscience/kmath/ast/rendering/MathSyntax.kt | 2 +- .../kscience/kmath/ast/rendering/SyntaxRenderer.kt | 2 +- .../space/kscience/kmath/ast/rendering/features.kt | 2 +- .../kmath/ast/rendering/multiplatformToString.kt | 2 +- .../space/kscience/kmath/ast/rendering/phases.kt | 2 +- .../ast/TestCompilerConsistencyWithInterpreter.kt | 2 +- .../kscience/kmath/ast/TestCompilerOperations.kt | 2 +- .../space/kscience/kmath/ast/TestCompilerVariables.kt | 2 +- .../kotlin/space/kscience/kmath/ast/TestFolding.kt | 2 +- .../kotlin/space/kscience/kmath/ast/TestParser.kt | 2 +- .../space/kscience/kmath/ast/TestParserPrecedence.kt | 2 +- .../kscience/kmath/ast/rendering/TestFeatures.kt | 2 +- .../space/kscience/kmath/ast/rendering/TestLatex.kt | 2 +- .../space/kscience/kmath/ast/rendering/TestMathML.kt | 2 +- .../space/kscience/kmath/ast/rendering/TestStages.kt | 2 +- .../space/kscience/kmath/ast/rendering/TestUtils.kt | 2 +- .../kotlin/space/kscience/kmath/ast/utils.kt | 2 +- .../kmath/ast/rendering/multiplatformToString.kt | 2 +- .../kotlin/space/kscience/kmath/estree/estree.kt | 2 +- .../kscience/kmath/estree/internal/ESTreeBuilder.kt | 2 +- .../estree/internal/astring/astring.typealises.kt | 2 +- .../space/kscience/kmath/internal/astring/astring.kt | 2 +- .../kmath/internal/astring/astring.typealises.kt | 2 +- .../space/kscience/kmath/internal/base64/base64.kt | 2 +- .../kmath/internal/binaryen/index.binaryen.kt | 2 +- .../internal/binaryen/index.binaryen.typealiases.kt | 2 +- .../space/kscience/kmath/internal/emitter/emitter.kt | 2 +- .../kmath/internal/estree/estree.extensions.kt | 2 +- .../space/kscience/kmath/internal/estree/estree.kt | 2 +- .../space/kscience/kmath/internal/stream/stream.kt | 2 +- .../kmath/internal/tsstdlib/lib.es2015.iterable.kt | 2 +- .../space/kscience/kmath/internal/tsstdlib/lib.es5.kt | 2 +- .../webassembly/lib.dom.WebAssembly.module_dukat.kt | 2 +- .../webassembly/nonDeclarations.WebAssembly.kt | 2 +- .../space/kscience/kmath/wasm/internal/WasmBuilder.kt | 2 +- .../kmath/wasm/internal/f64StandardFunctions.kt | 2 +- .../jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt | 2 +- .../jsTest/kotlin/space/kscience/kmath/ast/utils.kt | 2 +- .../space/kscience/kmath/wasm/TestWasmSpecific.kt | 2 +- .../jvmMain/kotlin/space/kscience/kmath/asm/asm.kt | 2 +- .../space/kscience/kmath/asm/internal/AsmBuilder.kt | 2 +- .../kscience/kmath/asm/internal/GenericAsmBuilder.kt | 2 +- .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 2 +- .../space/kscience/kmath/asm/internal/codegenUtils.kt | 2 +- .../kscience/kmath/asm/internal/mapIntrinsics.kt | 2 +- .../kmath/ast/rendering/multiplatformToString.kt | 2 +- .../jvmTest/kotlin/space/kscience/kmath/ast/utils.kt | 2 +- .../expressions/DerivativeStructureExpression.kt | 2 +- .../commons/integration/CMGaussRuleIntegrator.kt | 2 +- .../kmath/commons/integration/CMIntegrator.kt | 2 +- .../space/kscience/kmath/commons/linear/CMMatrix.kt | 2 +- .../space/kscience/kmath/commons/linear/CMSolver.kt | 2 +- .../kmath/commons/optimization/CMOptimizer.kt | 2 +- .../kmath/commons/random/CMRandomGeneratorWrapper.kt | 2 +- .../kmath/commons/transform/Transformations.kt | 2 +- .../expressions/DerivativeStructureExpressionTest.kt | 2 +- .../kmath/commons/integration/IntegrationTest.kt | 2 +- .../kmath/commons/optimization/OptimizeTest.kt | 2 +- .../kotlin/space/kscience/kmath/complex/Complex.kt | 2 +- .../space/kscience/kmath/complex/ComplexFieldND.kt | 2 +- .../kotlin/space/kscience/kmath/complex/Quaternion.kt | 2 +- .../kscience/kmath/complex/ComplexBufferSpecTest.kt | 2 +- .../space/kscience/kmath/complex/ComplexFieldTest.kt | 2 +- .../space/kscience/kmath/complex/ComplexTest.kt | 2 +- .../kmath/complex/ExpressionFieldForComplexTest.kt | 2 +- .../space/kscience/kmath/complex/QuaternionTest.kt | 2 +- .../kotlin/space/kscience/kmath/data/ColumnarData.kt | 2 +- .../space/kscience/kmath/data/XYColumnarData.kt | 2 +- .../space/kscience/kmath/data/XYErrorColumnarData.kt | 2 +- .../space/kscience/kmath/data/XYZColumnarData.kt | 2 +- .../kotlin/space/kscience/kmath/domains/Domain.kt | 2 +- .../kotlin/space/kscience/kmath/domains/Domain1D.kt | 2 +- .../space/kscience/kmath/domains/DoubleDomain.kt | 2 +- .../space/kscience/kmath/domains/HyperSquareDomain.kt | 2 +- .../kscience/kmath/domains/UnconstrainedDomain.kt | 2 +- .../space/kscience/kmath/expressions/DSAlgebra.kt | 4 ++-- .../space/kscience/kmath/expressions/DSCompiler.kt | 4 ++-- .../kmath/expressions/DifferentiableExpression.kt | 2 +- .../space/kscience/kmath/expressions/Expression.kt | 2 +- .../kmath/expressions/FunctionalExpressionAlgebra.kt | 2 +- .../kotlin/space/kscience/kmath/expressions/MST.kt | 2 +- .../space/kscience/kmath/expressions/MstAlgebra.kt | 2 +- .../kscience/kmath/expressions/SimpleAutoDiff.kt | 2 +- .../kotlin/space/kscience/kmath/expressions/Symbol.kt | 2 +- .../space/kscience/kmath/expressions/SymbolIndexer.kt | 2 +- .../kscience/kmath/expressions/specialExpressions.kt | 2 +- .../kscience/kmath/linear/BufferedLinearSpace.kt | 2 +- .../space/kscience/kmath/linear/DoubleLinearSpace.kt | 2 +- .../space/kscience/kmath/linear/LinearSolver.kt | 2 +- .../kotlin/space/kscience/kmath/linear/LinearSpace.kt | 2 +- .../space/kscience/kmath/linear/LupDecomposition.kt | 2 +- .../space/kscience/kmath/linear/MatrixBuilder.kt | 2 +- .../space/kscience/kmath/linear/MatrixFeatures.kt | 2 +- .../space/kscience/kmath/linear/MatrixWrapper.kt | 2 +- .../space/kscience/kmath/linear/VirtualMatrix.kt | 2 +- .../kotlin/space/kscience/kmath/misc/Featured.kt | 2 +- .../kotlin/space/kscience/kmath/misc/annotations.kt | 2 +- .../kotlin/space/kscience/kmath/misc/cumulative.kt | 2 +- .../kotlin/space/kscience/kmath/misc/logging.kt | 2 +- .../kotlin/space/kscience/kmath/misc/numbers.kt | 2 +- .../kotlin/space/kscience/kmath/misc/sorting.kt | 4 ++-- .../kotlin/space/kscience/kmath/nd/AlgebraND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/BufferND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/DoubleFieldND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/Shape.kt | 2 +- .../kotlin/space/kscience/kmath/nd/ShapeIndexer.kt | 2 +- .../kotlin/space/kscience/kmath/nd/ShortRingND.kt | 2 +- .../kotlin/space/kscience/kmath/nd/Structure1D.kt | 2 +- .../kotlin/space/kscience/kmath/nd/Structure2D.kt | 2 +- .../kotlin/space/kscience/kmath/nd/StructureND.kt | 2 +- .../space/kscience/kmath/nd/VirtualStructureND.kt | 2 +- .../space/kscience/kmath/nd/algebraNDExtentions.kt | 2 +- .../kotlin/space/kscience/kmath/nd/operationsND.kt | 2 +- .../kotlin/space/kscience/kmath/operations/Algebra.kt | 2 +- .../kotlin/space/kscience/kmath/operations/BigInt.kt | 2 +- .../space/kscience/kmath/operations/BufferAlgebra.kt | 2 +- .../kscience/kmath/operations/DoubleBufferField.kt | 2 +- .../kscience/kmath/operations/DoubleBufferOps.kt | 2 +- .../space/kscience/kmath/operations/LogicAlgebra.kt | 2 +- .../space/kscience/kmath/operations/NumericAlgebra.kt | 2 +- .../kscience/kmath/operations/OptionalOperations.kt | 2 +- .../kscience/kmath/operations/algebraExtensions.kt | 2 +- .../kscience/kmath/operations/bufferOperation.kt | 2 +- .../kotlin/space/kscience/kmath/operations/numbers.kt | 2 +- .../space/kscience/kmath/structures/ArrayBuffer.kt | 2 +- .../kotlin/space/kscience/kmath/structures/Buffer.kt | 2 +- .../kscience/kmath/structures/BufferAccessor2D.kt | 2 +- .../space/kscience/kmath/structures/ByteBuffer.kt | 2 +- .../space/kscience/kmath/structures/DoubleBuffer.kt | 2 +- .../space/kscience/kmath/structures/FlaggedBuffer.kt | 2 +- .../space/kscience/kmath/structures/FloatBuffer.kt | 2 +- .../space/kscience/kmath/structures/IntBuffer.kt | 2 +- .../space/kscience/kmath/structures/ListBuffer.kt | 2 +- .../space/kscience/kmath/structures/LongBuffer.kt | 2 +- .../space/kscience/kmath/structures/MemoryBuffer.kt | 2 +- .../space/kscience/kmath/structures/MutableBuffer.kt | 2 +- .../space/kscience/kmath/structures/ShortBuffer.kt | 2 +- .../kotlin/space/kscience/kmath/expressions/DSTest.kt | 4 ++-- .../kscience/kmath/expressions/ExpressionFieldTest.kt | 2 +- .../space/kscience/kmath/expressions/InterpretTest.kt | 2 +- .../kscience/kmath/expressions/SimpleAutoDiffTest.kt | 2 +- .../space/kscience/kmath/linear/DoubleLUSolverTest.kt | 2 +- .../kotlin/space/kscience/kmath/linear/MatrixTest.kt | 2 +- .../space/kscience/kmath/misc/CumulativeKtTest.kt | 2 +- .../kotlin/space/kscience/kmath/misc/PermSortTest.kt | 4 ++-- .../space/kscience/kmath/nd/NdOperationsTest.kt | 2 +- .../kscience/kmath/operations/BigIntAlgebraTest.kt | 2 +- .../kmath/operations/BigIntConstructorTest.kt | 2 +- .../kmath/operations/BigIntConversionsTest.kt | 2 +- .../kscience/kmath/operations/BigIntOperationsTest.kt | 2 +- .../kscience/kmath/operations/DoubleFieldTest.kt | 2 +- .../space/kscience/kmath/structures/NDFieldTest.kt | 2 +- .../kscience/kmath/structures/NumberNDFieldTest.kt | 2 +- .../kotlin/space/kscience/kmath/misc/numbers.kt | 2 +- .../space/kscience/kmath/operations/isInteger.kt | 2 +- .../kotlin/space/kscience/kmath/misc/numbersJVM.kt | 2 +- .../space/kscience/kmath/operations/BigNumbers.kt | 2 +- .../space/kscience/kmath/operations/isInteger.kt | 2 +- .../kotlin/space/kscience/kmath/misc/numbers.kt | 2 +- .../space/kscience/kmath/operations/isInteger.kt | 2 +- .../space/kscience/kmath/chains/BlockingChain.kt | 2 +- .../kscience/kmath/chains/BlockingDoubleChain.kt | 2 +- .../space/kscience/kmath/chains/BlockingIntChain.kt | 2 +- .../kotlin/space/kscience/kmath/chains/Chain.kt | 2 +- .../kotlin/space/kscience/kmath/chains/flowExtra.kt | 2 +- .../kscience/kmath/coroutines/coroutinesExtra.kt | 2 +- .../space/kscience/kmath/streaming/BufferFlow.kt | 2 +- .../space/kscience/kmath/streaming/RingBuffer.kt | 2 +- .../kotlin/space/kscience/kmath/chains/ChainExt.kt | 2 +- .../kscience/kmath/structures/LazyStructureND.kt | 2 +- .../space/kscience/kmath/streaming/BufferFlowTest.kt | 2 +- .../space/kscience/kmath/streaming/RingBufferTest.kt | 2 +- .../space/kscience/kmath/dimensions/Dimension.kt | 2 +- .../space/kscience/kmath/dimensions/Wrappers.kt | 2 +- .../space/kscience/dimensions/DMatrixContextTest.kt | 2 +- .../space/kscience/kmath/dimensions/Dimension.kt | 2 +- .../space/kscience/kmath/dimensions/Dimension.kt | 2 +- .../space/kscience/kmath/dimensions/Dimension.kt | 2 +- .../space/kscience/kmath/ejml/EjmlLinearSpace.kt | 2 +- .../kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt | 2 +- .../kotlin/space/kscience/kmath/ejml/EjmlVector.kt | 2 +- .../kotlin/space/kscience/kmath/ejml/_generated.kt | 4 ++-- .../space/kscience/kmath/ejml/EjmlMatrixTest.kt | 2 +- .../space/kscience/kmath/ejml/EjmlVectorTest.kt | 2 +- .../kotlin/space/kscience/kmath/real/DoubleVector.kt | 2 +- .../kotlin/space/kscience/kmath/real/RealMatrix.kt | 2 +- .../kotlin/space/kscience/kmath/real/dot.kt | 2 +- .../kotlin/space/kscience/kmath/real/grids.kt | 2 +- .../kotlin/space/kscience/kmath/real/realND.kt | 2 +- .../space/kscience/kmath/real/DoubleMatrixTest.kt | 2 +- .../space/kscience/kmath/real/DoubleVectorTest.kt | 2 +- .../kotlin/space/kscience/kmath/real/GridTest.kt | 2 +- .../space/kscience/kmath/functions/Piecewise.kt | 2 +- .../space/kscience/kmath/functions/Polynomial.kt | 2 +- .../space/kscience/kmath/functions/functionTypes.kt | 2 +- .../kmath/functions/polynomialConstructors.kt | 2 +- .../space/kscience/kmath/functions/polynomialUtil.kt | 2 +- .../kscience/kmath/integration/GaussIntegrator.kt | 2 +- .../kmath/integration/GaussIntegratorRuleFactory.kt | 2 +- .../space/kscience/kmath/integration/Integrand.kt | 2 +- .../space/kscience/kmath/integration/Integrator.kt | 2 +- .../kmath/integration/MultivariateIntegrand.kt | 2 +- .../kscience/kmath/integration/SimpsonIntegrator.kt | 2 +- .../kscience/kmath/integration/SplineIntegrator.kt | 2 +- .../kscience/kmath/integration/UnivariateIntegrand.kt | 2 +- .../kscience/kmath/interpolation/Interpolator.kt | 2 +- .../kmath/interpolation/LinearInterpolator.kt | 2 +- .../kmath/interpolation/SplineInterpolator.kt | 2 +- .../space/kscience/kmath/functions/PolynomialTest.kt | 2 +- .../kscience/kmath/functions/PolynomialUtilTest.kt | 2 +- .../kscience/kmath/functions/testUtils/IntModulo.kt | 2 +- .../kmath/functions/testUtils/IntModuloUtils.kt | 2 +- .../kscience/kmath/functions/testUtils/Rational.kt | 2 +- .../space/kscience/kmath/functions/testUtils/misc.kt | 2 +- .../kscience/kmath/integration/GaussIntegralTest.kt | 2 +- .../kscience/kmath/integration/SimpsonIntegralTest.kt | 2 +- .../kscience/kmath/integration/SplineIntegralTest.kt | 2 +- .../kmath/interpolation/LinearInterpolatorTest.kt | 2 +- .../kmath/interpolation/SplineInterpolatorTest.kt | 2 +- .../kotlin/space/kscience/kmath/geometry/Circle2D.kt | 2 +- .../space/kscience/kmath/geometry/Euclidean2DSpace.kt | 2 +- .../space/kscience/kmath/geometry/Euclidean3DSpace.kt | 2 +- .../space/kscience/kmath/geometry/GeometrySpace.kt | 2 +- .../kotlin/space/kscience/kmath/geometry/Line.kt | 2 +- .../space/kscience/kmath/geometry/ReferenceFrame.kt | 2 +- .../space/kscience/kmath/geometry/projections.kt | 2 +- .../space/kscience/kmath/geometry/rotations3D.kt | 2 +- .../kscience/kmath/geometry/Euclidean2DSpaceTest.kt | 2 +- .../kscience/kmath/geometry/Euclidean3DSpaceTest.kt | 2 +- .../kscience/kmath/geometry/ProjectionAlongTest.kt | 2 +- .../kscience/kmath/geometry/ProjectionOntoLineTest.kt | 2 +- .../space/kscience/kmath/geometry/RotationTest.kt | 2 +- .../space/kscience/kmath/geometry/Vector2DTest.kt | 2 +- .../space/kscience/kmath/geometry/Vector3DTest.kt | 2 +- .../kotlin/space/kscience/kmath/geometry/testUtils.kt | 2 +- .../kotlin/space/kscience/kmath/histogram/Counter.kt | 2 +- .../space/kscience/kmath/histogram/Histogram.kt | 2 +- .../space/kscience/kmath/histogram/Histogram1D.kt | 2 +- .../space/kscience/kmath/histogram/HistogramND.kt | 2 +- .../kscience/kmath/histogram/UniformHistogram1D.kt | 2 +- .../kmath/histogram/UniformHistogramGroupND.kt | 2 +- .../kmath/histogram/MultivariateHistogramTest.kt | 2 +- .../kmath/histogram/UniformHistogram1DTest.kt | 2 +- .../kscience/kmath/histogram/TreeHistogramGroup.kt | 2 +- .../kscience/kmath/histogram/TreeHistogramTest.kt | 2 +- .../kotlin/space/kscience/kmath/jafama/KMathJafama.kt | 2 +- .../space/kscience/kmath/jupyter/KMathJupyter.kt | 2 +- .../space/kscience/kmath/kotlingrad/KMathNumber.kt | 2 +- .../kscience/kmath/kotlingrad/KotlingradExpression.kt | 2 +- .../kscience/kmath/kotlingrad/scalarsAdapters.kt | 2 +- .../space/kscience/kmath/kotlingrad/AdaptingTests.kt | 2 +- .../kotlin/space/kscience/kmath/memory/Memory.kt | 2 +- .../kotlin/space/kscience/kmath/memory/MemorySpec.kt | 2 +- .../space/kscience/kmath/memory/DataViewMemory.kt | 2 +- .../space/kscience/kmath/memory/ByteBufferMemory.kt | 2 +- .../space/kscience/kmath/memory/NativeMemory.kt | 2 +- .../kscience/kmath/multik/MultikDoubleAlgebra.kt | 2 +- .../space/kscience/kmath/multik/MultikFloatAlgebra.kt | 2 +- .../space/kscience/kmath/multik/MultikIntAlgebra.kt | 2 +- .../space/kscience/kmath/multik/MultikLongAlgebra.kt | 2 +- .../space/kscience/kmath/multik/MultikShortAlgebra.kt | 2 +- .../space/kscience/kmath/multik/MultikTensor.kt | 2 +- .../kscience/kmath/multik/MultikTensorAlgebra.kt | 2 +- .../space/kscience/kmath/multik/MultikNDTest.kt | 2 +- .../space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 2 +- .../space/kscience/kmath/nd4j/Nd4jArrayIterator.kt | 2 +- .../space/kscience/kmath/nd4j/Nd4jArrayStructure.kt | 2 +- .../space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 2 +- .../main/kotlin/space/kscience/kmath/nd4j/arrays.kt | 2 +- .../space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt | 2 +- .../kscience/kmath/nd4j/Nd4jArrayStructureTest.kt | 2 +- .../kmath/optimization/FunctionOptimization.kt | 2 +- .../kmath/optimization/OptimizationBuilder.kt | 2 +- .../kmath/optimization/OptimizationProblem.kt | 2 +- .../space/kscience/kmath/optimization/Optimizer.kt | 2 +- .../space/kscience/kmath/optimization/QowOptimizer.kt | 2 +- .../kotlin/space/kscience/kmath/optimization/XYFit.kt | 2 +- .../kscience/kmath/optimization/logLikelihood.kt | 2 +- .../kscience/kmath/functions/LabeledPolynomial.kt | 2 +- .../kmath/functions/LabeledRationalFunction.kt | 2 +- .../space/kscience/kmath/functions/ListPolynomial.kt | 2 +- .../kscience/kmath/functions/ListRationalFunction.kt | 2 +- .../kscience/kmath/functions/NumberedPolynomial.kt | 2 +- .../kmath/functions/NumberedRationalFunction.kt | 2 +- .../space/kscience/kmath/functions/Polynomial.kt | 2 +- .../kscience/kmath/functions/RationalFunction.kt | 2 +- .../space/kscience/kmath/functions/algebraicStub.kt | 2 +- .../space/kscience/kmath/functions/collectionUtils.kt | 2 +- .../kscience/kmath/functions/labeledConstructors.kt | 2 +- .../space/kscience/kmath/functions/labeledUtil.kt | 2 +- .../kscience/kmath/functions/listConstructors.kt | 2 +- .../kotlin/space/kscience/kmath/functions/listUtil.kt | 2 +- .../kotlin/space/kscience/kmath/functions/misc.kt | 2 +- .../kscience/kmath/functions/numberedConstructors.kt | 2 +- .../space/kscience/kmath/functions/numberedUtil.kt | 2 +- .../kscience/kmath/functions/AlgebraicStubTest.kt | 2 +- .../kmath/functions/LabeledConstructorsTest.kt | 2 +- .../kscience/kmath/functions/LabeledPolynomialTest.kt | 2 +- .../kmath/functions/LabeledPolynomialUtilTest.kt | 2 +- .../kscience/kmath/functions/ListPolynomialTest.kt | 2 +- .../kmath/functions/ListPolynomialUtilTest.kt | 2 +- .../kmath/functions/NumberedConstructorsTest.kt | 2 +- .../kmath/functions/NumberedPolynomialTest.kt | 2 +- .../kmath/functions/NumberedPolynomialUtilTest.kt | 2 +- .../kscience/kmath/functions/testUtils/BufferUtils.kt | 2 +- .../kscience/kmath/functions/testUtils/IntModulo.kt | 2 +- .../kmath/functions/testUtils/IntModuloUtils.kt | 2 +- .../kscience/kmath/functions/testUtils/NTMisc.kt | 2 +- .../kscience/kmath/functions/testUtils/Rational.kt | 2 +- .../kscience/kmath/functions/testUtils/assertion.kt | 2 +- .../space/kscience/kmath/functions/testUtils/misc.kt | 2 +- .../kscience/kmath/distributions/Distribution.kt | 2 +- .../kmath/distributions/FactorizedDistribution.kt | 2 +- .../kmath/distributions/NormalDistribution.kt | 2 +- .../space/kscience/kmath/internal/InternalErf.kt | 2 +- .../space/kscience/kmath/internal/InternalGamma.kt | 2 +- .../space/kscience/kmath/internal/InternalUtils.kt | 2 +- .../kmath/samplers/AhrensDieterExponentialSampler.kt | 2 +- .../AhrensDieterMarsagliaTsangGammaSampler.kt | 2 +- .../kmath/samplers/AliasMethodDiscreteSampler.kt | 2 +- .../space/kscience/kmath/samplers/BoxMullerSampler.kt | 2 +- .../space/kscience/kmath/samplers/GaussianSampler.kt | 2 +- .../kmath/samplers/KempSmallMeanPoissonSampler.kt | 2 +- .../samplers/MarsagliaNormalizedGaussianSampler.kt | 2 +- .../kmath/samplers/NormalizedGaussianSampler.kt | 2 +- .../space/kscience/kmath/samplers/PoissonSampler.kt | 2 +- .../samplers/ZigguratNormalizedGaussianSampler.kt | 2 +- .../kotlin/space/kscience/kmath/stat/MCScope.kt | 2 +- .../kotlin/space/kscience/kmath/stat/Mean.kt | 2 +- .../kotlin/space/kscience/kmath/stat/Median.kt | 2 +- .../kotlin/space/kscience/kmath/stat/RandomChain.kt | 2 +- .../space/kscience/kmath/stat/RandomGenerator.kt | 2 +- .../kotlin/space/kscience/kmath/stat/Sampler.kt | 2 +- .../space/kscience/kmath/stat/SamplerAlgebra.kt | 2 +- .../kotlin/space/kscience/kmath/stat/Statistic.kt | 2 +- .../space/kscience/kmath/stat/UniformDistribution.kt | 2 +- .../space/kscience/kmath/stat/ValueAndErrorField.kt | 2 +- .../kscience/kmath/stat/RandomSourceGenerator.kt | 2 +- .../kscience/kmath/stat/CommonsDistributionsTest.kt | 2 +- .../kotlin/space/kscience/kmath/stat/MCScopeTest.kt | 2 +- .../kotlin/space/kscience/kmath/stat/SamplerTest.kt | 2 +- .../kotlin/space/kscience/kmath/stat/StatisticTest.kt | 2 +- .../space/kscience/kmath/symja/SymjaExpression.kt | 2 +- .../kotlin/space/kscience/kmath/symja/adapters.kt | 2 +- .../kmath/tensorflow/DoubleTensorFlowAlgebra.kt | 5 +++++ .../kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt | 5 +++++ .../kscience/kmath/tensorflow/TensorFlowAlgebra.kt | 5 +++++ .../space/kscience/kmath/tensorflow/tfOperations.kt | 2 +- .../kscience/kmath/tensorflow/DoubleTensorFlowOps.kt | 5 +++++ .../kmath/tensors/api/AnalyticTensorAlgebra.kt | 2 +- .../kmath/tensors/api/LinearOpsTensorAlgebra.kt | 2 +- .../kotlin/space/kscience/kmath/tensors/api/Tensor.kt | 2 +- .../space/kscience/kmath/tensors/api/TensorAlgebra.kt | 2 +- .../kmath/tensors/api/TensorPartialDivisionAlgebra.kt | 2 +- .../tensors/core/BroadcastDoubleTensorAlgebra.kt | 2 +- .../kscience/kmath/tensors/core/BufferedTensor.kt | 2 +- .../space/kscience/kmath/tensors/core/DoubleTensor.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- .../space/kscience/kmath/tensors/core/IntTensor.kt | 2 +- .../kmath/tensors/core/TensorLinearStructure.kt | 2 +- .../kmath/tensors/core/internal/broadcastUtils.kt | 2 +- .../kscience/kmath/tensors/core/internal/checks.kt | 2 +- .../kscience/kmath/tensors/core/internal/linUtils.kt | 2 +- .../kmath/tensors/core/internal/tensorCastsUtils.kt | 2 +- .../kscience/kmath/tensors/core/internal/utils.kt | 2 +- .../kmath/tensors/core/tensorAlgebraExtensions.kt | 2 +- .../space/kscience/kmath/tensors/core/tensorCasts.kt | 2 +- .../kscience/kmath/tensors/core/TestBroadcasting.kt | 2 +- .../tensors/core/TestDoubleAnalyticTensorAlgebra.kt | 2 +- .../kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 2 +- .../kscience/kmath/tensors/core/TestDoubleTensor.kt | 2 +- .../kmath/tensors/core/TestDoubleTensorAlgebra.kt | 2 +- .../space/kscience/kmath/trajectory/DubinsPath.kt | 2 +- .../kotlin/space/kscience/kmath/trajectory/Pose2D.kt | 2 +- .../space/kscience/kmath/trajectory/Trajectory.kt | 2 +- .../space/kscience/kmath/trajectory/TrajectoryCost.kt | 2 +- .../kotlin/space/kscience/kmath/trajectory/route.kt | 2 +- .../kotlin/space/kscience/kmath/trajectory/Math.kt | 5 +++++ .../kscience/kmath/trajectory/dubins/DubinsTests.kt | 2 +- .../kscience/kmath/trajectory/segments/ArcTests.kt | 5 +++++ .../kscience/kmath/trajectory/segments/CircleTests.kt | 2 +- .../kscience/kmath/trajectory/segments/LineTests.kt | 5 +++++ .../space/kscience/kmath/viktor/ViktorBuffer.kt | 2 +- .../space/kscience/kmath/viktor/ViktorFieldOpsND.kt | 2 +- .../space/kscience/kmath/viktor/ViktorStructureND.kt | 2 +- test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt | 2 +- test-utils/src/commonMain/kotlin/FieldVerifier.kt | 2 +- test-utils/src/commonMain/kotlin/RingVerifier.kt | 2 +- test-utils/src/commonMain/kotlin/SpaceVerifier.kt | 2 +- test-utils/src/commonMain/kotlin/asserts.kt | 2 +- 451 files changed, 490 insertions(+), 454 deletions(-) diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml index 17e44e4d0..840e0c87c 100644 --- a/.idea/copyright/kmath.xml +++ b/.idea/copyright/kmath.xml @@ -1,6 +1,7 @@ - - - + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index b538bdf41..1c10bd6f5 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,5 +1,5 @@ - + diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index 126a2e648..fd1b4307a 100644 --- a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt index ff933997f..abfc8cbf2 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt index 188a48ca7..19795b9eb 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt index 39819d407..41b9005e4 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index d7ead6dd8..7cbe83113 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index db3524e67..4df5f372f 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index 5d4eee7c0..041f7e92a 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt index 4ff687aac..f7aac8199 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index eb5e1da47..141d0433b 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt index 38e064e53..3ed7163b3 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index 0e92a703e..25ce8410a 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index 7bb0b876e..ea417e564 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt index 9f235c56e..f6d278d83 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/globals.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt index eaa0f59d8..62cf44915 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt index 33d186bfc..5c6a2ac83 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt index 7c23d8ea0..183510232 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/docs/images/KM.svg b/docs/images/KM.svg index 6f80e4d08..55a4339b1 100644 --- a/docs/images/KM.svg +++ b/docs/images/KM.svg @@ -1,6 +1,6 @@ diff --git a/docs/images/KM_mono.svg b/docs/images/KM_mono.svg index 8f8e470b2..f1194f887 100644 --- a/docs/images/KM_mono.svg +++ b/docs/images/KM_mono.svg @@ -1,6 +1,6 @@ diff --git a/docs/images/KMath.svg b/docs/images/KMath.svg index f751d8eb9..509a184bc 100644 --- a/docs/images/KMath.svg +++ b/docs/images/KMath.svg @@ -1,6 +1,6 @@ diff --git a/docs/images/KMath_mono.svg b/docs/images/KMath_mono.svg index 8ca6c5e84..e781979e2 100644 --- a/docs/images/KMath_mono.svg +++ b/docs/images/KMath_mono.svg @@ -1,6 +1,6 @@ diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt index c4f263f97..e85bab8d8 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index 907f1bbe4..cacb6683e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt index dec3bfb81..b443e639d 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt index 7e09faeff..92ee1781b 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt index 63e57bd8c..e32b97136 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt index d52976671..73fca8a38 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt index 59eaba5bd..28169f15a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt index 8dbc7b7a4..b4ce6ad2d 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt index a50df0931..7bcd96990 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt index 4f99aeb47..1b578626d 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt index c65ca589d..8228983e2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/polynomials.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt index 9c3d0fdbe..52451e9f3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt index a2d7d7c27..d9c3281f2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt index a01ea7fe2..52ed8f05f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt index 51f439612..2447d06ed 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt index 285b8d000..77cfca4ae 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt index 62c9c8076..8fc6e1b06 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt index 8e3cdf86f..bdbf42797 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt index 15654971f..3de9b6f34 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index d55f3df09..86d7c0d89 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index d6ff1dceb..48d14cb4c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index 548fb16c1..aed0a7868 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt index de36c664d..a64ac7280 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt index dea7095a8..ce5301a7b 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt index 889ea99bd..2ac0dc6a4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt index c28b566b9..1ba0e3503 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index b42602988..f7c5bb4b7 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index aced0cf7d..c4d0ed93e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt index a436ae1c3..6d72fd623 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt index f465fc424..a08fe4106 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt index 7cf1c5120..67e0631e7 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt index 5c41ab0f1..cbc83c336 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt index 8a8b8797d..6458dc123 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt index 71fb154c9..e411cd251 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt index 012a6e65f..2c9a2a9ad 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt index 2df3d3cc7..13806703c 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt index 8b5819b84..bd941745b 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt index fdef35ebd..dd8ed3457 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt index ee23ab408..14df5ad8d 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt index 362c07d72..e19a9722e 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index 90f78a152..c1a895015 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 291399cee..dce99cc5a 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt index c0271fbb5..f42237ba6 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt index 1edb5923e..3400db0f8 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt index be8a92f3e..bf56b80a6 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index 93ef97b0f..f23d36240 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt index 954a0f330..95b804455 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt index d0c3a789e..d3c203903 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt index 42cf5ce58..4b3631663 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt index a40c785b9..7b5ec5765 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt index 43f31baba..66c0ae1ae 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt index 145055494..8bc014c54 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt index 09ec127c7..306538d5d 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt index bf87b6fd0..79f178eef 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt index ec7436188..fe035c69f 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 521907d2c..f6411334c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt index 240acf1d7..853f5f983 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 16a59d273..1517cdef2 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt index eb5c1e3dd..2434788ec 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt index cca2d83af..cc4360f8d 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt index 93b4f6ce6..a17726c9d 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt index 86e0cede7..8ea699837 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt index 42b6ac7d8..d907a12c9 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt index 523b13b40..eebfeb6ef 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt index 1f7b09af8..a2a04da79 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt index 5b1ce914e..2dd2c08cd 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt index b62b8c06c..bf4a25367 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt index 52be5530f..ced165a3a 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt index 9c012e3a3..2c0dc9de1 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt index 0cd395f2c..f20e2d865 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt index 90690abed..873a5e1d2 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt index c5023c384..ba86e977b 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt index 878919d8d..d29fbde55 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt index 21a88b5d0..d60f24247 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt index f9540f9db..6a20da799 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt index 0d896c6f6..c6b241e5c 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt index 8ae5fcb36..0a85d5f24 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt index 73b9c97a7..59a26af7d 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index a76b47ecc..e1fd455fd 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt index 6cf3d8721..acae45d87 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt index 01bad83e5..d50318cd1 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index 9e880f4fc..b3ccfdc0c 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt index 3a5ef74f7..6459f4dcf 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 556adbe7d..ec66be830 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt index 47f1cc476..9f0fb33ab 100644 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 82694d95a..6d756b15f 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt index e0a2f4931..263463d37 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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.commons.integration diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt index 257429fa7..4839518e6 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index aa7e0a638..e95c9115d 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index 9bb5deffd..19799aab3 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt index 11eb6fba8..46baa7d50 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:OptIn(UnstableKMathAPI::class) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 194be6002..c7a23ebc4 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index 40168971e..2243dc5d9 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt index 56252ab34..40ba9fc7d 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt index c5573fef1..308f504af 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt index 0977dc247..b1b7b3ed7 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt index f56fb0f6e..5804e47c1 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt index 65943f421..42914ed5b 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 0305bfc88..aa5806932 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt index 17a077ea7..ca3f8f43f 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt index cbaaa815b..e11f1c1ea 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt index 7ad7f883d..1a35d1dd8 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt index 4279471d4..767406e0b 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt index fd4df736c..fd0fd46a7 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt index e06b774fd..d09228e96 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt index 2fce772cc..a3c3a2eda 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt index 8ddd6406f..dd0e35bc8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt index e99ae0698..3dc1bb99b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt index b5a84cf6c..eecdcebad 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt index 3d531349c..10755e633 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt index ee1bebde0..b0803f3e1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt index 485416a69..7d5843a97 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt index 32a5fc56c..e8b867fac 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index c55e41bb2..fa8bf5e58 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -1,6 +1,6 @@ /* - * 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 file. + * Copyright 2018-2022 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.expressions diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt index b5b2988a3..6ab9b3d44 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt @@ -1,6 +1,6 @@ /* - * 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 file. + * Copyright 2018-2022 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.expressions diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index 12b7df0ea..7c8a957c7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt index 5ba32f190..9c769caa0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 68cc8e791..1054d1aa1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt index 18226119b..9705a3f03 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt index 4bd2a6c53..a75940cca 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt index ac8c44446..f00e6d3f3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt index 8ab2bec31..c57ce69ab 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt index bf37e9615..e5f92efc9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt index 907ce4004..8cfa1b353 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt index 8f7569699..361d59be1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt index 4e6debc60..e2f81d84e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt index fae9e7c91..af9ebb463 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index d437070c9..757752115 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt index fb57f2343..0ee7c8828 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt index 029612bc5..d0105e4cd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt index b70e9d8a9..ce7acdcba 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt index b1812f49d..feea26b40 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt index fb2b1e547..eb5e20856 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt index 29b7caec6..a752a8339 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index 60fa81cd8..f7b486850 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt index ee7f1d8be..6ccb487c3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt index 9dfc564c3..c7886469f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt index f879a06d5..77ef07ea8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt index dc5421136..daf5e1eff 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt @@ -1,6 +1,6 @@ /* - * 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 file. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index ad291cf7f..101f90160 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt index 8c5eef3d0..4025ba548 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index 8175bd65e..5484ce545 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt index d01a8ee95..7f8d3c55d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt index d682d5e69..c5d04c9de 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Shape.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt index 29701425f..2dce407ca 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt index 8152adaa5..ea37da7a3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index 4ccb15eef..2a258a7f4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index a2fd83474..d8fd2031c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index e14b8bf9d..0fed49f40 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt index 7e86ea73d..579a0d7c8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/VirtualStructureND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt index 53f946fbd..1b7bd20db 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt index c9624dc4e..5814e2f9c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/operationsND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index a93b4365e..a7a5bc5fd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 9b6911f73..8730ff163 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index a256fe7d1..3af77856c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt index f2f7326aa..449730e7a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt index 669c0a390..811926c23 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt index 9037525e1..5cf98c7d5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt index d0405c705..5c2747686 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index 709506fc4..c24394add 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt index 539440de9..efadfb3cc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt index 46abc0266..3d25d8750 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index c108aa729..16088a825 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt index 3528b0460..8e81dd941 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 5757848fe..2f9f8a8e0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index 4d04a5235..07355d396 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt index e7bf2b47c..2be17c5e4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ByteBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index f4388a477..e39c22158 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt index b3c537280..d99e02996 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt index e7e98fc71..8666ca675 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index 35b722e2b..8477fc13b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt index 65d9dc77d..fbc9a489b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt index c69f4646d..9d6f1b2a7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt index 1dadaf7d4..80d5033c4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt index 429c1a64b..709ebd680 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt index 20691511b..7dbb2b58e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt index b6581e503..f46f3023d 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/DSTest.kt @@ -1,6 +1,6 @@ /* - * 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 file. + * Copyright 2018-2022 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:OptIn(UnstableKMathAPI::class) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt index 80c5943cf..def9f91a6 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt index 156334b2e..6f207eab3 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt index 201890933..1618296be 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt index 70e010f2e..25e29f3d6 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt index 25d187bf0..fe5ea3642 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt index e5f3f337f..811f2e87f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt index 4a724ac5f..4f3469ea2 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt @@ -1,6 +1,6 @@ /* - * 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 file. + * Copyright 2018-2022 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.misc diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt index 25b062b44..e909a2aea 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/nd/NdOperationsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt index 0527f5252..f4f7b1a51 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt index eec3dc3bf..786c68c70 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt index 85f368f3e..36f00dc75 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt index 26d6af224..8a6116605 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt index 76171fedd..688daa7fe 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index b7b89d107..566145621 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt index d33eb5112..62c4811e8 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt index 68a3c995b..e52ea9298 100644 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt index 24b81322e..3103f5168 100644 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt index 5ba0dbc9b..3780ea1ae 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index 6e22c2381..584748bd7 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt index b2f9b957b..9868daddf 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt index 68a3c995b..e52ea9298 100644 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt index b2f9b957b..9868daddf 100644 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt index 87aebff61..2e9a15eed 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt index 25e20291e..797d2db4a 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt index ac0327d0b..a481156f2 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt index 994255e38..ed0283630 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt index 7bf54d50f..77d4203c5 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt index 1f17efe49..3f06693b0 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt index 4d4493aa4..00c874751 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt index abe1c9df9..2ac8c1eb4 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt index dd6e39071..a62bcc6b8 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt index 2b9265843..786d32190 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt index 9b67f7253..c448168e3 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt index 305b97e5d..a6d7f006c 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index e57c22834..14677319c 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index f04536f04..b93114804 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt index 59260fe73..e2793855b 100644 --- a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 610e8b4c0..1ae484228 100644 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index e6d8b3b35..24cfb14e8 100644 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 64edbe935..f5f749c8a 100644 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt index 32030dfe3..beb79fc0e 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt index 27fd3fc53..1d70c0e7d 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt index 37995c27e..c4fae9951 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt index aac327a84..5426055b3 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -1,6 +1,6 @@ /* - * 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 file. + * Copyright 2018-2022 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. */ /* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index af6284e5e..e3bff8987 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt index 9592bfa6c..7d3ea314b 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt index 7b9740c35..e607786fb 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt index 671e272ab..c44b1dff0 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index dc5c58be0..0c18602f1 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt index 1926ef02c..6403cf509 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt index 52362f4b4..2c06b76b7 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt index 4a0e8de1d..89e55c6d4 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt index e77b96c12..a25091ac2 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt index 8fed8d10e..31be9a452 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 16af7f555..a9f51f7b0 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ 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 1f9bab52c..af84f47f2 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 @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt index 0e814993c..c2f95f040 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt index 2da9ea6f5..4e9791a87 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/polynomialConstructors.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ 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 c9377a6c1..5effe566a 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 @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt index 9785d7744..603f0503a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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.integration diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt index 778d85e66..4cfed8efe 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index 05e2e5c55..40fe78898 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt index 1cf15b42f..18c46b83b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index 96b81aaa6..53a563086 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt index 7815757aa..7e4ff0f8b 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index eb88d9ae0..9a8f475c8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt index 6fd75e6e6..af8c858fa 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 2266092a3..52e8991b1 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index 34d7bcf41..49d7fd1ca 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index afcb33bd4..a63142be4 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 7e0c6cdf2..3051cdd8d 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt index 9d0fe4cc3..c1b1008ae 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialUtilTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index ef601c941..3b7409e82 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 730a455bf..ffab2157c 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 19cb77df5..0a3d00e96 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt index ff67f19d8..61b50f128 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt index 9f48a15ea..32fc08ae4 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt index 9f2d71554..188f8d15f 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index afeba0be4..4a15e96c3 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt index 1143036d4..c0ca6c484 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index 4c7d816d4..851a8ab7d 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index 8623335b9..585843278 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index a83cb3ac7..d79c6c40e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index c1fc74bf1..173ed5688 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt index d4245c744..4ea2aefdf 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index 85bfcdd8f..ee16a7698 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt index a7a28b596..21045e94e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt index 6ffc43739..6950abbdc 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/projections.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt index 67c3666ed..fbe7ae8ee 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt index 6b5f474bc..73edc0fc2 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt index 0bc91e77e..6e1fa9943 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt index dfb65a57c..b57a31a75 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt index 076025110..02f386158 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt index 89b69d0f2..3ebe9c4b9 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt index 5e45b4870..211fd4ed0 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt index 55bab4775..315a70374 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt index 0f957529d..2a8c0c3c8 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt index fe3278026..43ed24c70 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt index 12edafd81..a4ae6d935 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt index 710e4478b..f9ca6a486 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt index 68b24db5d..2cefb33a5 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/HistogramND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt index e13928394..3c687d2df 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt index 1ead049e6..36e994bcf 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogramGroupND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt index ca7c2f324..717f9d7a1 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt index 09bf3939d..fd107f5e8 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt index 6bec01f9b..a7d34ff71 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramGroup.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt index 2c56a88a7..77dc189ee 100644 --- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt +++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 91d952a76..f9b8287b4 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt index 504ad693e..85797134f 100644 --- a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt +++ b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt index f7858e172..cd35e0c42 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index 31b8a9286..110572140 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt index 37ce40cab..dd75a704c 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index 570d7dd7f..042777c8a 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt index e8e51e9e2..006d57c5f 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt index 1ee1cf4e2..19bc3bae4 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt index 6153743fc..40ba84c10 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt index aef68fd80..84f7ea412 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt index 5146d9689..b224383e4 100644 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt index dcc1623cc..989ebcd5d 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt index db251b552..ee194ae24 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikFloatAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt index 517845939..05b240787 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikIntAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt index 9c6c1af54..e713e556e 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikLongAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt index 5288351b2..6e5ca5882 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikShortAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt index 3ab4b0e3d..38d61e982 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index f9768ea39..c6266c985 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index 8bc43eef2..8ad220221 100644 --- a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt index e29a3f467..f359b9115 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt index d4cad8996..fedad26e0 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt index 2a0fdc86c..0a7d15e20 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index ceb384f0d..5ecfe30d6 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt index 3ca756600..401c57a7b 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt index 9d30c2027..9f1022fd9 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt index 30d01338f..d1ad746fe 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index 02602b068..07146625c 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt index 416d0195d..d1ceccf1a 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index b42be4035..db154be42 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt index 78385a99b..41dcbf770 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index babbaf6cd..669860934 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index 07fea3126..d2182e91f 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:OptIn(UnstableKMathAPI::class) diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt index b4cb2f1cf..e0eeb339c 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt index 6a4d1409f..662e8ca74 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledPolynomial.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt index e4f2b6c37..185782f22 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/LabeledRationalFunction.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt index 6ab660b63..3753a93c4 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListPolynomial.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt index b744afc51..c2fa6b2ec 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/ListRationalFunction.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt index 267bbd91d..eaf5befb1 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedPolynomial.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt index 0f3c1ced9..4109338fd 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/NumberedRationalFunction.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index 6a11eb1bd..7140ba70e 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt index 3c1548516..766d9ce98 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/RationalFunction.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt index b40aa4775..80bf6ec53 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/algebraicStub.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt index c9146a493..e294f3533 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/collectionUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index d74c0e1fb..9cb0ebb3f 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt index a37a1fe39..188240bf7 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt index e95361724..30b1e2fe4 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listConstructors.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt index 4f3f6d88e..e7c11f5ea 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/listUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt index 76f1c294e..0a251b3b7 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/misc.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt index ce49088ae..df4afbd12 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedConstructors.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt index 9f29cf31a..88424d23c 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/numberedUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt index 487cd9ee1..9dd2bb743 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/AlgebraicStubTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt index 80476050b..054f0dc4c 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledConstructorsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt index bde1386da..bb30f7742 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt index 6243818b4..637981b66 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/LabeledPolynomialUtilTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt index e7d8dfd8c..5f7e1a95b 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt index 339643d02..48ea89a46 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/ListPolynomialUtilTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt index 1815749ce..ad6240fb9 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedConstructorsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt index ec2e34520..c2f86198c 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt index 82f1e561a..e5d1ddf48 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/NumberedPolynomialUtilTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt index 3297733b1..ab912a464 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/BufferUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt index 5bac4cd73..a037dcd18 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModulo.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt index 33fd03aa0..615523873 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/IntModuloUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt index ff67f19d8..61b50f128 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/NTMisc.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt index 19cb77df5..0a3d00e96 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/Rational.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt index 4ef87f736..c70c229ca 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/assertion.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt index 93c3f8ea5..66e46c902 100644 --- a/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt +++ b/kmath-polynomial/src/commonTest/kotlin/space/kscience/kmath/functions/testUtils/misc.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index 8dbcb3367..cf2fd5b08 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt index 1218f13c5..14f49a35f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt index cfc6eba04..8a249c340 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt index 25668446c..bb2bfdd09 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt index 63db1c56f..1ef2ec02c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt index 71fd15fe6..a80407773 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt index 77d29981f..d861fddae 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt index 993215d41..912bb0fa3 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt index 5390a2e09..34d1131b4 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt index b3c014553..60a8491f2 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt index 9219df43e..4a4bfdfeb 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt index 0105731c4..145946b14 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt index 0a68e5c88..a8d289d47 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt index 83f87e832..3f6797881 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index f0f94900e..83480b4ba 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt index b534fdc14..2cd561468 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt index 0e06fa162..37e6ea13b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index aff7d03d9..fb14a95be 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt index c587277f9..87046cd46 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt index d4bc36b5b..ac7977659 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt index f280a78aa..94b2bfbea 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 1c88922ac..66ade8119 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index 1f442c09b..1e34fa434 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index 43cd5b402..d7638ff81 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt index 20cc0e802..fa51bb521 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt index 5949213e7..38cd5f900 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/ValueAndErrorField.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index 202a1c8dd..2da9a9e21 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt index 19c01e099..802f3ac24 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt index cca645809..889274c86 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt index 1dbbf591b..7b76fb4b6 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt index 9eb84899c..0db22fef4 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt index 3067b5efb..0f8014913 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt index 30c37c799..92f2474b8 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index ad7a978a0..fa7050d2a 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.tensorflow import org.tensorflow.Graph diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt index 084a445e0..01c8054b3 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.tensorflow import org.tensorflow.Graph diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index 7185b84d6..c6eaa7266 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.tensorflow diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt index f67c333ce..a0a2ddc80 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt index 308469eed..21340a8db 100644 --- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt +++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.tensorflow import org.junit.jupiter.api.Test diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 3ed34ae5e..587096500 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 0bddc3f9c..07dfd1597 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt index 482bb5244..b328fbeec 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 1b11dc54f..dbc42f7c7 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 9c492cda1..33effb2d2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index e412ab5bb..e5739359e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 73a89502c..98e6ab430 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt index 8e5116336..e8239caf4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 63193fe4c..53115d5e5 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt index e3d7c3d35..ccff9606e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt index 19eefc2f8..3de1c9b1a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt index 9d37423e5..ab97903e4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index a2d445b45..5db311db4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index aba6167ce..49d67c205 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index a5cdb2f47..dad4368c1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt index 85cc91b1d..8a96d516f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt index d8e8df31e..5904e574e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 5dc8114dd..968efa468 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 6788ae792..67d5f9a96 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 1e21379b4..c777273f3 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 98ee9e3cb..5b226bd5d 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index d808637c7..5e5ef95be 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index bca6e65d0..28c327973 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 134342b33..98beed646 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt index 1f7c4a52e..901ba5c67 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt index 2e97d43b0..620a5fcc1 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt index 170851c43..3782a9a32 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/TrajectoryCost.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt index f67ab124d..2e8e43be9 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/route.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 7ee68bd92..cc342de75 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.trajectory import space.kscience.kmath.geometry.Vector2D diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 09375a400..6ea48dae6 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index c66fa201b..ce8c6c7a5 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.trajectory.segments import space.kscience.kmath.geometry.Circle2D diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt index 5170c1db5..eff843ae0 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index 11eaa0fb3..c1a13f4d9 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -1,3 +1,8 @@ +/* + * Copyright 2018-2022 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.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index 4eedcb5ee..90d5ad9a9 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt index cecbc35b8..493af54c9 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt index 25ca3a10e..c9749d41a 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt b/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt index ddd8fc3ea..261e74f5a 100644 --- a/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt +++ b/test-utils/src/commonMain/kotlin/AlgebraicVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/test-utils/src/commonMain/kotlin/FieldVerifier.kt b/test-utils/src/commonMain/kotlin/FieldVerifier.kt index f4ca7506b..a03ca0a27 100644 --- a/test-utils/src/commonMain/kotlin/FieldVerifier.kt +++ b/test-utils/src/commonMain/kotlin/FieldVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/test-utils/src/commonMain/kotlin/RingVerifier.kt b/test-utils/src/commonMain/kotlin/RingVerifier.kt index 14606cb2c..c40075d93 100644 --- a/test-utils/src/commonMain/kotlin/RingVerifier.kt +++ b/test-utils/src/commonMain/kotlin/RingVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/test-utils/src/commonMain/kotlin/SpaceVerifier.kt b/test-utils/src/commonMain/kotlin/SpaceVerifier.kt index d761a3775..01c02997b 100644 --- a/test-utils/src/commonMain/kotlin/SpaceVerifier.kt +++ b/test-utils/src/commonMain/kotlin/SpaceVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ diff --git a/test-utils/src/commonMain/kotlin/asserts.kt b/test-utils/src/commonMain/kotlin/asserts.kt index 8e7d1ae23..8ddce517c 100644 --- a/test-utils/src/commonMain/kotlin/asserts.kt +++ b/test-utils/src/commonMain/kotlin/asserts.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 KMath contributors. + * Copyright 2018-2022 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. */ From 6111c673eec9c96448711fd8b62f6708b16aee64 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 21 Aug 2022 11:39:17 +0300 Subject: [PATCH 164/174] Type-safe angles --- .../space/kscience/kmath/geometry/angles.kt | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt new file mode 100644 index 000000000..e7b0afcda --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/angles.kt @@ -0,0 +1,79 @@ +/* + * 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.geometry + +import kotlin.jvm.JvmInline +import kotlin.math.PI + +public sealed interface Angle { + public fun toRadians(): Radians + public fun toDegrees(): Degrees + + public operator fun plus(other: Angle): Angle + public operator fun minus(other: Angle): Angle + + public operator fun times(other: Number): Angle + public operator fun div(other: Number): Angle + public operator fun unaryMinus(): Angle +} + +/** + * Type safe radians + */ +@JvmInline +public value class Radians(public val value: Double) : Angle { + override fun toRadians(): Radians = this + override fun toDegrees(): Degrees = Degrees(value * 180 / PI) + + public override fun plus(other: Angle): Radians = Radians(value + other.toRadians().value) + public override fun minus(other: Angle): Radians = Radians(value - other.toRadians().value) + + public override fun times(other: Number): Radians = Radians(value + other.toDouble()) + public override fun div(other: Number): Radians = Radians(value / other.toDouble()) + public override fun unaryMinus(): Radians = Radians(-value) +} + +public fun sin(angle: Angle): Double = kotlin.math.sin(angle.toRadians().value) +public fun cos(angle: Angle): Double = kotlin.math.cos(angle.toRadians().value) +public fun tan(angle: Angle): Double = kotlin.math.tan(angle.toRadians().value) + +public val Number.radians: Radians get() = Radians(toDouble()) + +/** + * Type safe degrees + */ +@JvmInline +public value class Degrees(public val value: Double) : Angle { + override fun toRadians(): Radians = Radians(value * PI / 180) + override fun toDegrees(): Degrees = this + + public override fun plus(other: Angle): Degrees = Degrees(value + other.toDegrees().value) + public override fun minus(other: Angle): Degrees = Degrees(value - other.toDegrees().value) + + public override fun times(other: Number): Degrees = Degrees(value + other.toDouble()) + public override fun div(other: Number): Degrees = Degrees(value / other.toDouble()) + public override fun unaryMinus(): Degrees = Degrees(-value) +} + +public val Number.degrees: Degrees get() = Degrees(toDouble()) + +/** + * A holder class for Pi representation in radians and degrees + */ +public object Pi { + public val radians: Radians = Radians(PI) + public val degrees: Degrees = radians.toDegrees() +} + +public object PiTimes2 { + public val radians: Radians = Radians(2 * PI) + public val degrees: Degrees = radians.toDegrees() +} + +public object PiDiv2 { + public val radians: Radians = Radians(PI / 2) + public val degrees: Degrees = radians.toDegrees() +} \ No newline at end of file From 5af0c91f0a7fca7b7b64039a5574c92a54071e9b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 21 Aug 2022 11:39:41 +0300 Subject: [PATCH 165/174] Misc --- build.gradle.kts | 2 +- kmath-polynomial/build.gradle.kts | 6 +++--- .../kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index b6e5b0748..28349f1b9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-1" + version = "0.3.1-dev-2" } subprojects { diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index 42b90a70e..c6946878c 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -1,7 +1,7 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") + // Disable native target to avoid CI crashes +// id("space.kscience.gradle.native") } description = "Polynomials, rational functions, and utilities" diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index e412ab5bb..292357a71 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -5,7 +5,6 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.tensors.api.Tensor @@ -18,8 +17,6 @@ import space.kscience.kmath.tensors.core.internal.tensor * Basic linear algebra operations implemented with broadcasting. * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html */ - -@PerformancePitfall public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun StructureND.plus(arg: StructureND): DoubleTensor { @@ -102,6 +99,5 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { * Compute a value using broadcast double tensor algebra */ @UnstableKMathAPI -@PerformancePitfall public fun DoubleTensorAlgebra.withBroadcast(block: BroadcastDoubleTensorAlgebra.() -> R): R = BroadcastDoubleTensorAlgebra.block() \ No newline at end of file From 978de59b7a412a64309e03d879a9fc053ae6c177 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 21 Aug 2022 11:40:02 +0300 Subject: [PATCH 166/174] Add rotations converter to Quaternions --- .../kscience/kmath/complex/Quaternion.kt | 5 + .../kmath/geometry/Euclidean3DSpace.kt | 12 +- .../kscience/kmath/geometry/rotations3D.kt | 105 ++++++++++++++++-- .../kscience/kmath/geometry/RotationTest.kt | 21 +++- .../kmath/functions/labeledConstructors.kt | 16 +-- 5 files changed, 139 insertions(+), 20 deletions(-) diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 0305bfc88..643bff696 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -117,6 +117,11 @@ public val Quaternion.reciprocal: Quaternion return Quaternion(w / norm2, -x / norm2, -y / norm2, -z / norm2) } + +//TODO consider adding a-priory normalized quaternions +/** + * Produce a normalized version of this quaternion + */ public fun Quaternion.normalized(): Quaternion = with(QuaternionField){ this@normalized / norm(this@normalized) } /** diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index c1fc74bf1..3bfd265b6 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -27,8 +27,9 @@ public interface Vector3D : Point, Vector { override operator fun iterator(): Iterator = listOf(x, y, z).iterator() } -@Suppress("FunctionName") -public fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) +public operator fun Vector3D.component1(): Double = x +public operator fun Vector3D.component2(): Double = y +public operator fun Vector3D.component3(): Double = z public fun Buffer.asVector3D(): Vector3D = object : Vector3D { init { @@ -51,6 +52,9 @@ private data class Vector3DImpl( override val z: Double, ) : Vector3D + +public fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) + public object Euclidean3DSpace : GeometrySpace, ScaleOperations { override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } @@ -67,4 +71,8 @@ public object Euclidean3DSpace : GeometrySpace, ScaleOperations Quaternion): Vector3D = rotate(vector, QuaternionField.composition()) @@ -113,4 +121,87 @@ public fun Quaternion.Companion.fromRotationMatrix(matrix: Matrix): Quat z = 0.25 * s, ) } +} + +public enum class RotationOrder { + // proper Euler + XZX, + XYX, + YXY, + YZY, + ZYZ, + ZXZ, + + //Tait–Bryan + XZY, + XYZ, + YXZ, + YZX, + ZYX, + ZXY +} + +/** + * Based on https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js + */ +public fun Quaternion.Companion.fromEuler( + a: Angle, + b: Angle, + c: Angle, + rotationOrder: RotationOrder, +): Quaternion { + val c1 = cos (a / 2) + val c2 = cos (b / 2) + val c3 = cos (c / 2) + + val s1 = sin (a / 2) + val s2 = sin (b / 2) + val s3 = sin (c / 2) + + return when (rotationOrder) { + + RotationOrder.XYZ -> Quaternion( + c1 * c2 * c3 - s1 * s2 * s3, + s1 * c2 * c3 + c1 * s2 * s3, + c1 * s2 * c3 - s1 * c2 * s3, + c1 * c2 * s3 + s1 * s2 * c3 + ) + + RotationOrder.YXZ -> Quaternion( + c1 * c2 * c3 + s1 * s2 * s3, + s1 * c2 * c3 + c1 * s2 * s3, + c1 * s2 * c3 - s1 * c2 * s3, + c1 * c2 * s3 - s1 * s2 * c3 + ) + + RotationOrder.ZXY -> Quaternion( + c1 * c2 * c3 - s1 * s2 * s3, + s1 * c2 * c3 - c1 * s2 * s3, + c1 * s2 * c3 + s1 * c2 * s3, + c1 * c2 * s3 + s1 * s2 * c3 + ) + + + RotationOrder.ZYX -> Quaternion( + c1 * c2 * c3 + s1 * s2 * s3, + s1 * c2 * c3 - c1 * s2 * s3, + c1 * s2 * c3 + s1 * c2 * s3, + c1 * c2 * s3 - s1 * s2 * c3 + ) + + RotationOrder.YZX -> Quaternion( + c1 * c2 * c3 - s1 * s2 * s3, + s1 * c2 * c3 + c1 * s2 * s3, + c1 * s2 * c3 + s1 * c2 * s3, + c1 * c2 * s3 - s1 * s2 * c3 + ) + + RotationOrder.XZY -> Quaternion( + c1 * c2 * c3 + s1 * s2 * s3, + s1 * c2 * c3 - c1 * s2 * s3, + c1 * s2 * c3 - s1 * c2 * s3, + c1 * c2 * s3 + s1 * s2 * c3 + ) + else -> TODO("Proper Euler rotation orders are not supported yet") + } } \ No newline at end of file diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt index 89b69d0f2..033055c19 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -7,24 +7,25 @@ package space.kscience.kmath.geometry import space.kscience.kmath.complex.Quaternion import space.kscience.kmath.complex.normalized +import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.testutils.assertBufferEquals import kotlin.test.Test class RotationTest { @Test - fun rotations() = with(Euclidean3DSpace) { + fun differentRotations() = with(Euclidean3DSpace) { val vector = Vector3D(1.0, 1.0, 1.0) val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() val rotatedByQ = rotate(vector, q) val matrix = q.toRotationMatrix() - val rotatedByM = rotate(vector,matrix) + val rotatedByM = rotate(vector, matrix) assertBufferEquals(rotatedByQ, rotatedByM, 1e-4) } @Test - fun rotationConversion() { + fun matrixConversion() { val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() @@ -32,4 +33,18 @@ class RotationTest { assertBufferEquals(q, Quaternion.fromRotationMatrix(matrix)) } + + @Test + fun fromRotation() { + val q = Quaternion.fromRotation(0.3.radians, Vector3D(1.0, 1.0, 1.0)) + + assertBufferEquals(DoubleBuffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q) + } + + @Test + fun fromEuler() { + val q = Quaternion.fromEuler(0.1.radians, 0.2.radians, 0.3.radians, RotationOrder.ZXY) + + assertBufferEquals(DoubleBuffer(0.9818562, 0.0342708, 0.1060205, 0.1534393), q) + } } \ No newline at end of file diff --git a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt index d74c0e1fb..082b133a0 100644 --- a/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt +++ b/kmath-polynomial/src/commonMain/kotlin/space/kscience/kmath/functions/labeledConstructors.kt @@ -470,7 +470,7 @@ public class DSL2LabeledPolynomialBuilder( } private inline fun submit(signature: Map, lazyCoefficient: Ring.() -> C) { - submit(signature, lazyCoefficient, { it + lazyCoefficient() }) + submit(signature, lazyCoefficient) { it + lazyCoefficient() } } private fun submit(signature: Map, coefficient: C) { @@ -478,9 +478,9 @@ public class DSL2LabeledPolynomialBuilder( } // TODO: `@submit` will be resolved differently. Change it to `@C`. - private fun C.submit() = submit(emptyMap(), { this@submit }) + private fun C.submitSelf() = submit(emptyMap()) { this@submitSelf } - private fun Symbol.submit() = submit(mapOf(this to 1u), { one }) + private fun Symbol.submit() = submit(mapOf(this to 1u)) { one } private fun Term.submit(): Submit { submit(signature, coefficient) @@ -490,7 +490,7 @@ public class DSL2LabeledPolynomialBuilder( public object Submit public operator fun C.unaryPlus(): Submit { - submit() + submitSelf() return Submit } @@ -500,12 +500,12 @@ public class DSL2LabeledPolynomialBuilder( } public operator fun C.plus(other: C): Submit { - submit(emptyMap(), { this@plus + other }) + submit(emptyMap()) { this@plus + other } return Submit } public operator fun C.minus(other: C): Submit { - submit(emptyMap(), { this@minus - other }) + submit(emptyMap()) { this@minus - other } return Submit } @@ -541,7 +541,7 @@ public class DSL2LabeledPolynomialBuilder( public operator fun Symbol.plus(other: C): Submit { this.submit() - other.submit() + other.submitSelf() return Submit } @@ -599,7 +599,7 @@ public class DSL2LabeledPolynomialBuilder( public operator fun Term.plus(other: C): Submit { this.submit() - other.submit() + other.submitSelf() return Submit } From ec77cd1fc324df8cfba80272186e3e3c40184522 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 21 Aug 2022 19:17:38 +0300 Subject: [PATCH 167/174] Geometry overhaul --- kmath-dimensions/build.gradle.kts | 3 +- kmath-geometry/build.gradle.kts | 7 +- .../space/kscience/kmath/geometry/Circle2D.kt | 2 +- .../kmath/geometry/Euclidean2DSpace.kt | 61 ++++++++++----- .../kmath/geometry/Euclidean3DSpace.kt | 76 ++++++++++--------- .../kscience/kmath/geometry/GeometrySpace.kt | 3 +- .../space/kscience/kmath/geometry/Line.kt | 9 ++- .../kscience/kmath/geometry/rotations3D.kt | 14 ++-- .../kmath/geometry/Euclidean2DSpaceTest.kt | 40 +++++----- .../kmath/geometry/Euclidean3DSpaceTest.kt | 50 ++++++------ .../kmath/geometry/ProjectionAlongTest.kt | 20 ++--- .../kmath/geometry/ProjectionOntoLineTest.kt | 46 +++++------ .../kscience/kmath/geometry/RotationTest.kt | 4 +- .../kscience/kmath/geometry/Vector2DTest.kt | 2 +- .../kscience/kmath/geometry/Vector3DTest.kt | 2 +- .../kscience/kmath/geometry/testUtils.kt | 4 +- .../kscience/kmath/geometry/lineExtensions.kt | 20 +++++ .../kscience/kmath/trajectory/DubinsPath.kt | 36 ++++----- .../space/kscience/kmath/trajectory/Pose2D.kt | 18 ++--- .../kscience/kmath/trajectory/Trajectory.kt | 10 +-- .../space/kscience/kmath/trajectory/Math.kt | 8 +- .../kmath/trajectory/dubins/DubinsTests.kt | 7 +- .../kmath/trajectory/segments/ArcTests.kt | 8 +- .../kmath/trajectory/segments/CircleTests.kt | 4 +- .../kmath/trajectory/segments/LineTests.kt | 15 ++-- 25 files changed, 260 insertions(+), 209 deletions(-) create mode 100644 kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts index ee1950fa8..1c042ab70 100644 --- a/kmath-dimensions/build.gradle.kts +++ b/kmath-dimensions/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") + id("space.kscience.gradle.mpp") id("space.kscience.gradle.native") } diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index c9d8823bc..c2057bcbe 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") + id("space.kscience.gradle.mpp") id("space.kscience.gradle.native") } @@ -10,6 +9,10 @@ kotlin.sourceSets.commonMain { } } +kscience { + withContextReceivers() +} + readme { maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index 8623335b9..c665ae6bb 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -11,7 +11,7 @@ import kotlin.math.PI * A circle in 2D space */ public class Circle2D( - public val center: Vector2D, + public val center: DoubleVector2D, public val radius: Double ) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index a83cb3ac7..f622bbb76 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -6,45 +6,64 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point +import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke +import kotlin.math.pow import kotlin.math.sqrt -public interface Vector2D : Point, Vector { - public val x: Double - public val y: Double +public interface Vector2D : Point, Vector { + public val x: T + public val y: T override val size: Int get() = 2 - override operator fun get(index: Int): Double = when (index) { + override operator fun get(index: Int): T = when (index) { 0 -> x 1 -> y else -> error("Accessing outside of point bounds") } - override operator fun iterator(): Iterator = listOf(x, y).iterator() + override operator fun iterator(): Iterator = iterator { + yield(x) + yield(y) + } } -public val Vector2D.r: Double - get() = Euclidean2DSpace { norm() } -public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y) +public operator fun Vector2D.component1(): T = x +public operator fun Vector2D.component2(): T = y + +public typealias DoubleVector2D = Vector2D + +public val Vector2D.r: Double get() = Euclidean2DSpace.norm(this) -private data class Vector2DImpl( - override val x: Double, - override val y: Double, -) : Vector2D /** * 2D Euclidean space */ -public object Euclidean2DSpace : GeometrySpace, ScaleOperations { - override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) } +public object Euclidean2DSpace : GeometrySpace, + ScaleOperations, + Norm { - public fun Vector2D.norm(): Double = sqrt(x * x + y * y) - override fun Vector2D.unaryMinus(): Vector2D = Vector2D(-x, -y) + private data class Vector2DImpl( + override val x: Double, + override val y: Double, + ) : DoubleVector2D - override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm() - override fun add(left: Vector2D, right: Vector2D): Vector2D = Vector2D(left.x + right.x, left.y + right.y) - override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value) - override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y + public fun vector(x: Number, y: Number): DoubleVector2D = Vector2DImpl(x.toDouble(), y.toDouble()) + + override val zero: DoubleVector2D by lazy { vector(0.0, 0.0) } + + override fun norm(arg: DoubleVector2D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2)) + + override fun DoubleVector2D.unaryMinus(): DoubleVector2D = vector(-x, -y) + + override fun DoubleVector2D.distanceTo(other: DoubleVector2D): Double = norm(this - other) + override fun add(left: DoubleVector2D, right: DoubleVector2D): DoubleVector2D = + vector(left.x + right.x, left.y + right.y) + + override fun scale(a: DoubleVector2D, value: Double): DoubleVector2D = vector(a.x * value, a.y * value) + override fun DoubleVector2D.dot(other: DoubleVector2D): Double = x * other.x + y * other.y + + public val xAxis: DoubleVector2D = vector(1.0, 0.0) + public val yAxis: DoubleVector2D = vector(0.0, 1.0) } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index 3bfd265b6..93be2df52 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -6,73 +6,79 @@ package space.kscience.kmath.geometry import space.kscience.kmath.linear.Point +import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer +import kotlin.math.pow import kotlin.math.sqrt -public interface Vector3D : Point, Vector { - public val x: Double - public val y: Double - public val z: Double +public interface Vector3D : Point, Vector { + public val x: T + public val y: T + public val z: T override val size: Int get() = 3 - override operator fun get(index: Int): Double = when (index) { + override operator fun get(index: Int): T = when (index) { 0 -> x 1 -> y 2 -> z else -> error("Accessing outside of point bounds") } - override operator fun iterator(): Iterator = listOf(x, y, z).iterator() + override operator fun iterator(): Iterator = listOf(x, y, z).iterator() } -public operator fun Vector3D.component1(): Double = x -public operator fun Vector3D.component2(): Double = y -public operator fun Vector3D.component3(): Double = z +public operator fun Vector3D.component1(): T = x +public operator fun Vector3D.component2(): T = y +public operator fun Vector3D.component3(): T = z -public fun Buffer.asVector3D(): Vector3D = object : Vector3D { +public fun Buffer.asVector3D(): Vector3D = object : Vector3D { init { require(this@asVector3D.size == 3) { "Buffer of size 3 is required for Vector3D" } } - override val x: Double get() = this@asVector3D[0] - override val y: Double get() = this@asVector3D[1] - override val z: Double get() = this@asVector3D[2] + override val x: T get() = this@asVector3D[0] + override val y: T get() = this@asVector3D[1] + override val z: T get() = this@asVector3D[2] override fun toString(): String = this@asVector3D.toString() - } -public val Vector3D.r: Double get() = Euclidean3DSpace { norm() } +public typealias DoubleVector3D = Vector3D -private data class Vector3DImpl( - override val x: Double, - override val y: Double, - override val z: Double, -) : Vector3D +public val DoubleVector3D.r: Double get() = Euclidean3DSpace.norm(this) +public object Euclidean3DSpace : GeometrySpace, ScaleOperations, + Norm { + private data class Vector3DImpl( + override val x: Double, + override val y: Double, + override val z: Double, + ) : DoubleVector3D -public fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) + public fun vector(x: Number, y: Number, z: Number): DoubleVector3D = + Vector3DImpl(x.toDouble(), y.toDouble(), z.toDouble()) -public object Euclidean3DSpace : GeometrySpace, ScaleOperations { - override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } + override val zero: DoubleVector3D by lazy { vector(0.0, 0.0, 0.0) } - public fun Vector3D.norm(): Double = sqrt(x * x + y * y + z * z) - override fun Vector3D.unaryMinus(): Vector3D = Vector3D(-x, -y, -z) + override fun norm(arg: DoubleVector3D): Double = sqrt(arg.x.pow(2) + arg.y.pow(2) + arg.z.pow(2)) - override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() + public fun DoubleVector3D.norm(): Double = norm(this) - override fun add(left: Vector3D, right: Vector3D): Vector3D = - Vector3D(left.x + right.x, left.y + right.y, left.z + right.z) + override fun DoubleVector3D.unaryMinus(): DoubleVector3D = vector(-x, -y, -z) - override fun scale(a: Vector3D, value: Double): Vector3D = - Vector3D(a.x * value, a.y * value, a.z * value) + override fun DoubleVector3D.distanceTo(other: DoubleVector3D): Double = (this - other).norm() - override fun Vector3D.dot(other: Vector3D): Double = + override fun add(left: DoubleVector3D, right: DoubleVector3D): DoubleVector3D = + vector(left.x + right.x, left.y + right.y, left.z + right.z) + + override fun scale(a: DoubleVector3D, value: Double): DoubleVector3D = + vector(a.x * value, a.y * value, a.z * value) + + override fun DoubleVector3D.dot(other: DoubleVector3D): Double = x * other.x + y * other.y + z * other.z - public val xAxis: Vector3D = Vector3D(1.0, 0.0, 0.0) - public val yAxis: Vector3D = Vector3D(0.0, 1.0, 0.0) - public val zAxis: Vector3D = Vector3D(0.0, 0.0, 1.0) + public val xAxis: DoubleVector3D = vector(1.0, 0.0, 0.0) + public val yAxis: DoubleVector3D = vector(0.0, 1.0, 0.0) + public val zAxis: DoubleVector3D = vector(0.0, 0.0, 1.0) } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt index d4245c744..b06ff9989 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt @@ -6,11 +6,12 @@ package space.kscience.kmath.geometry import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.ScaleOperations public interface Vector -public interface GeometrySpace : Group, ScaleOperations { +public interface GeometrySpace : Group, ScaleOperations, Norm { /** * L2 distance */ diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index 85bfcdd8f..2251af600 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -11,5 +11,10 @@ package space.kscience.kmath.geometry */ public data class Line(val base: V, val direction: V) -public typealias Line2D = Line -public typealias Line3D = Line +public typealias Line2D = Line +public typealias Line3D = Line + +/** + * A directed line segment between [begin] and [end] + */ +public data class LineSegment(val begin: V, val end: V) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt index c0d90463a..2500c78d6 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/rotations3D.kt @@ -15,7 +15,7 @@ import space.kscience.kmath.operations.DoubleField import kotlin.math.pow import kotlin.math.sqrt -internal fun Vector3D.toQuaternion(): Quaternion = Quaternion(0.0, x, y, z) +internal fun DoubleVector3D.toQuaternion(): Quaternion = Quaternion(0.0, x, y, z) /** * Angle in radians denoted by this quaternion rotation @@ -25,7 +25,7 @@ public val Quaternion.theta: Radians get() = (kotlin.math.acos(normalized().w) * /** * Create a normalized Quaternion from rotation angle and rotation vector */ -public fun Quaternion.Companion.fromRotation(theta: Angle, vector: Vector3D): Quaternion { +public fun Quaternion.Companion.fromRotation(theta: Angle, vector: DoubleVector3D): Quaternion { val s = sin(theta / 2) val c = cos(theta / 2) val norm = with(Euclidean3DSpace) { vector.norm() } @@ -35,9 +35,9 @@ public fun Quaternion.Companion.fromRotation(theta: Angle, vector: Vector3D): Qu /** * An axis of quaternion rotation */ -public val Quaternion.vector: Vector3D +public val Quaternion.vector: DoubleVector3D get() { - return object : Vector3D { + return object : DoubleVector3D { private val sint2 = sqrt(1 - w * w) override val x: Double get() = this@vector.x / sint2 override val y: Double get() = this@vector.y / sint2 @@ -49,7 +49,7 @@ public val Quaternion.vector: Vector3D /** * Rotate a vector in a [Euclidean3DSpace] */ -public fun Euclidean3DSpace.rotate(vector: Vector3D, q: Quaternion): Vector3D = with(QuaternionField) { +public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, q: Quaternion): DoubleVector3D = with(QuaternionField) { val p = vector.toQuaternion() (q * p * q.reciprocal).vector } @@ -58,10 +58,10 @@ public fun Euclidean3DSpace.rotate(vector: Vector3D, q: Quaternion): Vector3D = * Use a composition of quaternions to create a rotation */ @UnstableKMathAPI -public fun Euclidean3DSpace.rotate(vector: Vector3D, composition: QuaternionField.() -> Quaternion): Vector3D = +public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, composition: QuaternionField.() -> Quaternion): DoubleVector3D = rotate(vector, QuaternionField.composition()) -public fun Euclidean3DSpace.rotate(vector: Vector3D, matrix: Matrix): Vector3D { +public fun Euclidean3DSpace.rotate(vector: DoubleVector3D, matrix: Matrix): DoubleVector3D { require(matrix.colNum == 3 && matrix.rowNum == 3) { "Square 3x3 rotation matrix is required" } return with(DoubleField.linearSpace) { matrix.dot(vector).asVector3D() } } diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt index 6b5f474bc..8ca6ba248 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt @@ -12,16 +12,16 @@ import kotlin.test.assertEquals internal class Euclidean2DSpaceTest { @Test fun zero() { - assertVectorEquals(Vector2D(0.0, 0.0), Euclidean2DSpace.zero) + assertVectorEquals(Euclidean2DSpace.vector(0.0, 0.0), Euclidean2DSpace.zero) } @Test fun norm() { with(Euclidean2DSpace) { - assertEquals(0.0, zero.norm()) - assertEquals(1.0, Vector2D(1.0, 0.0).norm()) - assertEquals(sqrt(2.0), Vector2D(1.0, 1.0).norm()) - assertEquals(sqrt(5.002001), Vector2D(-2.0, 1.001).norm()) + assertEquals(0.0, norm(zero)) + assertEquals(1.0, norm(vector(1.0, 0.0))) + assertEquals(sqrt(2.0), norm(vector(1.0, 1.0))) + assertEquals(sqrt(5.002001), norm(vector(-2.0, 1.001))) } } @@ -29,16 +29,16 @@ internal class Euclidean2DSpaceTest { fun dotProduct() { with(Euclidean2DSpace) { assertEquals(0.0, zero dot zero) - assertEquals(0.0, zero dot Vector2D(1.0, 0.0)) - assertEquals(0.0, Vector2D(-2.0, 0.001) dot zero) - assertEquals(0.0, Vector2D(1.0, 0.0) dot Vector2D(0.0, 1.0)) + assertEquals(0.0, zero dot vector(1.0, 0.0)) + assertEquals(0.0, vector(-2.0, 0.001) dot zero) + assertEquals(0.0, vector(1.0, 0.0) dot vector(0.0, 1.0)) - assertEquals(1.0, Vector2D(1.0, 0.0) dot Vector2D(1.0, 0.0)) - assertEquals(-2.0, Vector2D(0.0, 1.0) dot Vector2D(1.0, -2.0)) - assertEquals(2.0, Vector2D(1.0, 1.0) dot Vector2D(1.0, 1.0)) - assertEquals(4.001001, Vector2D(-2.0, 1.001) dot Vector2D(-2.0, 0.001)) + assertEquals(1.0, vector(1.0, 0.0) dot vector(1.0, 0.0)) + assertEquals(-2.0, vector(0.0, 1.0) dot vector(1.0, -2.0)) + assertEquals(2.0, vector(1.0, 1.0) dot vector(1.0, 1.0)) + assertEquals(4.001001, vector(-2.0, 1.001) dot vector(-2.0, 0.001)) - assertEquals(-4.998, Vector2D(1.0, 2.0) dot Vector2D(-5.0, 0.001)) + assertEquals(-4.998, vector(1.0, 2.0) dot vector(-5.0, 0.001)) } } @@ -46,12 +46,12 @@ internal class Euclidean2DSpaceTest { fun add() { with(Euclidean2DSpace) { assertVectorEquals( - Vector2D(-2.0, 0.001), - Vector2D(-2.0, 0.001) + zero + vector(-2.0, 0.001), + vector(-2.0, 0.001) + zero ) assertVectorEquals( - Vector2D(-3.0, 3.001), - Vector2D(2.0, 3.0) + Vector2D(-5.0, 0.001) + vector(-3.0, 3.001), + vector(2.0, 3.0) + vector(-5.0, 0.001) ) } } @@ -59,9 +59,9 @@ internal class Euclidean2DSpaceTest { @Test fun multiply() { with(Euclidean2DSpace) { - assertVectorEquals(Vector2D(-4.0, 0.0), Vector2D(-2.0, 0.0) * 2) - assertVectorEquals(Vector2D(4.0, 0.0), Vector2D(-2.0, 0.0) * -2) - assertVectorEquals(Vector2D(300.0, 0.0003), Vector2D(100.0, 0.0001) * 3) + assertVectorEquals(vector(-4.0, 0.0), vector(-2.0, 0.0) * 2) + assertVectorEquals(vector(4.0, 0.0), vector(-2.0, 0.0) * -2) + assertVectorEquals(vector(300.0, 0.0003), vector(100.0, 0.0001) * 3) } } } diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt index 0bc91e77e..191ba54ab 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt @@ -11,21 +11,21 @@ import kotlin.test.assertEquals internal class Euclidean3DSpaceTest { @Test fun zero() { - assertVectorEquals(Vector3D(0.0, 0.0, 0.0), Euclidean3DSpace.zero) + assertVectorEquals(Euclidean3DSpace.vector(0.0, 0.0, 0.0), Euclidean3DSpace.zero) } @Test fun distance() { with(Euclidean3DSpace) { assertEquals(0.0, zero.distanceTo(zero)) - assertEquals(1.0, zero.distanceTo(Vector3D(1.0, 0.0, 0.0))) - assertEquals(kotlin.math.sqrt(5.000001), Vector3D(1.0, -2.0, 0.001).distanceTo(zero)) - assertEquals(0.0, Vector3D(1.0, -2.0, 0.001).distanceTo(Vector3D(1.0, -2.0, 0.001))) - assertEquals(0.0, Vector3D(1.0, 0.0, 0.0).distanceTo(Vector3D(1.0, 0.0, 0.0))) - assertEquals(kotlin.math.sqrt(2.0), Vector3D(1.0, 0.0, 0.0).distanceTo(Vector3D(1.0, 1.0, 1.0))) - assertEquals(3.1622778182822584, Vector3D(0.0, 1.0, 0.0).distanceTo(Vector3D(1.0, -2.0, 0.001))) - assertEquals(0.0, Vector3D(1.0, -2.0, 0.001).distanceTo(Vector3D(1.0, -2.0, 0.001))) - assertEquals(9.695050335093676, Vector3D(1.0, 2.0, 3.0).distanceTo(Vector3D(7.0, -5.0, 0.001))) + assertEquals(1.0, zero.distanceTo(vector(1.0, 0.0, 0.0))) + assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).distanceTo(zero)) + assertEquals(0.0, vector(1.0, -2.0, 0.001).distanceTo(vector(1.0, -2.0, 0.001))) + assertEquals(0.0, vector(1.0, 0.0, 0.0).distanceTo(vector(1.0, 0.0, 0.0))) + assertEquals(kotlin.math.sqrt(2.0), vector(1.0, 0.0, 0.0).distanceTo(vector(1.0, 1.0, 1.0))) + assertEquals(3.1622778182822584, vector(0.0, 1.0, 0.0).distanceTo(vector(1.0, -2.0, 0.001))) + assertEquals(0.0, vector(1.0, -2.0, 0.001).distanceTo(vector(1.0, -2.0, 0.001))) + assertEquals(9.695050335093676, vector(1.0, 2.0, 3.0).distanceTo(vector(7.0, -5.0, 0.001))) } } @@ -33,9 +33,9 @@ internal class Euclidean3DSpaceTest { fun norm() { with(Euclidean3DSpace) { assertEquals(0.0, zero.norm()) - assertEquals(1.0, Vector3D(1.0, 0.0, 0.0).norm()) - assertEquals(kotlin.math.sqrt(3.0), Vector3D(1.0, 1.0, 1.0).norm()) - assertEquals(kotlin.math.sqrt(5.000001), Vector3D(1.0, -2.0, 0.001).norm()) + assertEquals(1.0, vector(1.0, 0.0, 0.0).norm()) + assertEquals(kotlin.math.sqrt(3.0), vector(1.0, 1.0, 1.0).norm()) + assertEquals(kotlin.math.sqrt(5.000001), vector(1.0, -2.0, 0.001).norm()) } } @@ -43,16 +43,16 @@ internal class Euclidean3DSpaceTest { fun dotProduct() { with(Euclidean3DSpace) { assertEquals(0.0, zero dot zero) - assertEquals(0.0, zero dot Vector3D(1.0, 0.0, 0.0)) - assertEquals(0.0, Vector3D(1.0, -2.0, 0.001) dot zero) + assertEquals(0.0, zero dot vector(1.0, 0.0, 0.0)) + assertEquals(0.0, vector(1.0, -2.0, 0.001) dot zero) - assertEquals(1.0, Vector3D(1.0, 0.0, 0.0) dot Vector3D(1.0, 0.0, 0.0)) - assertEquals(1.0, Vector3D(1.0, 0.0, 0.0) dot Vector3D(1.0, 1.0, 1.0)) - assertEquals(-2.0, Vector3D(0.0, 1.0, 0.0) dot Vector3D(1.0, -2.0, 0.001)) - assertEquals(3.0, Vector3D(1.0, 1.0, 1.0) dot Vector3D(1.0, 1.0, 1.0)) - assertEquals(5.000001, Vector3D(1.0, -2.0, 0.001) dot Vector3D(1.0, -2.0, 0.001)) + assertEquals(1.0, vector(1.0, 0.0, 0.0) dot vector(1.0, 0.0, 0.0)) + assertEquals(1.0, vector(1.0, 0.0, 0.0) dot vector(1.0, 1.0, 1.0)) + assertEquals(-2.0, vector(0.0, 1.0, 0.0) dot vector(1.0, -2.0, 0.001)) + assertEquals(3.0, vector(1.0, 1.0, 1.0) dot vector(1.0, 1.0, 1.0)) + assertEquals(5.000001, vector(1.0, -2.0, 0.001) dot vector(1.0, -2.0, 0.001)) - assertEquals(-2.997, Vector3D(1.0, 2.0, 3.0) dot Vector3D(7.0, -5.0, 0.001)) + assertEquals(-2.997, vector(1.0, 2.0, 3.0) dot vector(7.0, -5.0, 0.001)) } } @@ -60,12 +60,12 @@ internal class Euclidean3DSpaceTest { fun add() { with(Euclidean3DSpace) { assertVectorEquals( - Vector3D(1.0, -2.0, 0.001), - Vector3D(1.0, -2.0, 0.001) + zero + vector(1.0, -2.0, 0.001), + vector(1.0, -2.0, 0.001) + zero ) assertVectorEquals( - Vector3D(8.0, -3.0, 3.001), - Vector3D(1.0, 2.0, 3.0) + Vector3D(7.0, -5.0, 0.001) + vector(8.0, -3.0, 3.001), + vector(1.0, 2.0, 3.0) + vector(7.0, -5.0, 0.001) ) } } @@ -73,7 +73,7 @@ internal class Euclidean3DSpaceTest { @Test fun multiply() { with(Euclidean3DSpace) { - assertVectorEquals(Vector3D(2.0, -4.0, 0.0), Vector3D(1.0, -2.0, 0.0) * 2) + assertVectorEquals(vector(2.0, -4.0, 0.0), vector(1.0, -2.0, 0.0) * 2) } } } diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt index dfb65a57c..cebbf5a4d 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt @@ -12,14 +12,14 @@ internal class ProjectionAlongTest { @Test fun projectionIntoYEqualsX() { with(Euclidean2DSpace) { - val normal = Vector2D(-2.0, 2.0) - val base = Vector2D(2.3, 2.3) + val normal = vector(-2.0, 2.0) + val base = vector(2.3, 2.3) assertVectorEquals(zero, projectAlong(zero, normal, base)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> val d = (y - x) / 2.0 - assertVectorEquals(Vector2D(x + d, y - d), projectAlong(Vector2D(x, y), normal, base)) + assertVectorEquals(vector(x + d, y - d), projectAlong(vector(x, y), normal, base)) } } } @@ -30,28 +30,28 @@ internal class ProjectionAlongTest { val a = 5.0 val b = -3.0 val c = -15.0 - val normal = Vector2D(-5.0, 3.0) - val base = Vector2D(3.0, 0.0) + val normal = vector(-5.0, 3.0) + val base = vector(3.0, 0.0) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> val xProj = (b * (b * x - a * y) - a * c) / (a * a + b * b) val yProj = (a * (-b * x + a * y) - b * c) / (a * a + b * b) - assertVectorEquals(Vector2D(xProj, yProj), projectAlong(Vector2D(x, y), normal, base)) + assertVectorEquals(vector(xProj, yProj), projectAlong(vector(x, y), normal, base)) } } } @Test - fun projectOntoPlane() { - val normal = Vector3D(1.0, 3.5, 0.07) - val base = Vector3D(2.0, -0.0037, 11.1111) + fun projectOntoPlane() = with(Euclidean3DSpace){ + val normal = vector(1.0, 3.5, 0.07) + val base = vector(2.0, -0.0037, 11.1111) with(Euclidean3DSpace) { val testDomain = (-10.0..10.0).generateList(0.43) for (x in testDomain) { for (y in testDomain) { for (z in testDomain) { - val v = Vector3D(x, y, z) + val v = vector(x, y, z) val result = projectAlong(v, normal, base) // assert that result is on plane diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt index 076025110..2ca0b5f76 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt @@ -12,10 +12,10 @@ internal class ProjectionOntoLineTest { @Test fun projectionIntoOx() { with(Euclidean2DSpace) { - val ox = Line(zero, Vector2D(1.0, 0.0)) + val ox = Line(zero, vector(1.0, 0.0)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - assertVectorEquals(Vector2D(x, 0.0), projectToLine(Vector2D(x, y), ox)) + assertVectorEquals(vector(x, 0.0), projectToLine(vector(x, y), ox)) } } } @@ -23,10 +23,10 @@ internal class ProjectionOntoLineTest { @Test fun projectionIntoOy() { with(Euclidean2DSpace) { - val line = Line(zero, Vector2D(0.0, 1.0)) + val line = Line(zero, vector(0.0, 1.0)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - assertVectorEquals(Vector2D(0.0, y), projectToLine(Vector2D(x, y), line)) + assertVectorEquals(vector(0.0, y), projectToLine(vector(x, y), line)) } } } @@ -34,13 +34,13 @@ internal class ProjectionOntoLineTest { @Test fun projectionIntoYEqualsX() { with(Euclidean2DSpace) { - val line = Line(zero, Vector2D(1.0, 1.0)) + val line = Line(zero, vector(1.0, 1.0)) assertVectorEquals(zero, projectToLine(zero, line)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> val d = (y - x) / 2.0 - assertVectorEquals(Vector2D(x + d, y - d), projectToLine(Vector2D(x, y), line)) + assertVectorEquals(vector(x + d, y - d), projectToLine(vector(x, y), line)) } } } @@ -51,38 +51,38 @@ internal class ProjectionOntoLineTest { val a = 5.0 val b = -3.0 val c = -15.0 - val line = Line(Vector2D(3.0, 0.0), Vector2D(3.0, 5.0)) + val line = Line(vector(3.0, 0.0), vector(3.0, 5.0)) grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> val xProj = (b * (b * x - a * y) - a * c) / (a * a + b * b) val yProj = (a * (-b * x + a * y) - b * c) / (a * a + b * b) - assertVectorEquals(Vector2D(xProj, yProj), projectToLine(Vector2D(x, y), line)) + assertVectorEquals(vector(xProj, yProj), projectToLine(vector(x, y), line)) } } } @Test - fun projectionOntoLine3d() { + fun projectionOntoLine3d() = with(Euclidean3DSpace) { val line = Line3D( - base = Vector3D(1.0, 3.5, 0.07), - direction = Vector3D(2.0, -0.0037, 11.1111) + base = vector(1.0, 3.5, 0.07), + direction = vector(2.0, -0.0037, 11.1111) ) - with(Euclidean3DSpace) { - val testDomain = (-10.0..10.0).generateList(0.43) - for (x in testDomain) { - for (y in testDomain) { - for (z in testDomain) { - val v = Vector3D(x, y, z) - val result = projectToLine(v, line) - // assert that result is on line - assertTrue(isCollinear(result - line.base, line.direction)) - // assert that PV vector is orthogonal to direction vector - assertTrue(isOrthogonal(v - result, line.direction)) - } + val testDomain = (-10.0..10.0).generateList(0.43) + for (x in testDomain) { + for (y in testDomain) { + for (z in testDomain) { + val v = vector(x, y, z) + val result = projectToLine(v, line) + + // assert that result is on the line + assertTrue(isCollinear(result - line.base, line.direction)) + // assert that PV vector is orthogonal to direction vector + assertTrue(isOrthogonal(v - result, line.direction)) } } } + } } diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt index 033055c19..8febe6722 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/RotationTest.kt @@ -15,7 +15,7 @@ class RotationTest { @Test fun differentRotations() = with(Euclidean3DSpace) { - val vector = Vector3D(1.0, 1.0, 1.0) + val vector = vector(1.0, 1.0, 1.0) val q = Quaternion(1.0, 2.0, -3.0, 4.0).normalized() val rotatedByQ = rotate(vector, q) val matrix = q.toRotationMatrix() @@ -36,7 +36,7 @@ class RotationTest { @Test fun fromRotation() { - val q = Quaternion.fromRotation(0.3.radians, Vector3D(1.0, 1.0, 1.0)) + val q = Quaternion.fromRotation(0.3.radians, Euclidean3DSpace.vector(1.0, 1.0, 1.0)) assertBufferEquals(DoubleBuffer(0.9887711, 0.0862781, 0.0862781, 0.0862781), q) } diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt index 5e45b4870..c98bfa45a 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt @@ -10,7 +10,7 @@ import kotlin.test.Test import kotlin.test.assertEquals internal class Vector2DTest { - private val vector = Vector2D(1.0, -7.999) + private val vector = Euclidean2DSpace.vector(1.0, -7.999) @Test fun size() { diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt index 55bab4775..fabcaa9aa 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt @@ -10,7 +10,7 @@ import kotlin.test.Test import kotlin.test.assertEquals internal class Vector3DTest { - private val vector = Vector3D(1.0, -7.999, 0.001) + private val vector = Euclidean3DSpace.vector(1.0, -7.999, 0.001) @Test fun size() { diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt index 0f957529d..f8b64bc64 100644 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt @@ -25,12 +25,12 @@ fun grid( return xs.flatMap { x -> ys.map { y -> x to y } } } -fun assertVectorEquals(expected: Vector2D, actual: Vector2D, absoluteTolerance: Double = 1e-6) { +fun assertVectorEquals(expected: DoubleVector2D, actual: DoubleVector2D, absoluteTolerance: Double = 1e-6) { assertEquals(expected.x, actual.x, absoluteTolerance) assertEquals(expected.y, actual.y, absoluteTolerance) } -fun assertVectorEquals(expected: Vector3D, actual: Vector3D, absoluteTolerance: Double = 1e-6) { +fun assertVectorEquals(expected: DoubleVector3D, actual: DoubleVector3D, absoluteTolerance: Double = 1e-6) { assertEquals(expected.x, actual.x, absoluteTolerance) assertEquals(expected.y, actual.y, absoluteTolerance) assertEquals(expected.z, actual.z, absoluteTolerance) diff --git a/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt b/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt new file mode 100644 index 000000000..5fcd2b23e --- /dev/null +++ b/kmath-geometry/src/jvmMain/kotlin/space/kscience/kmath/geometry/lineExtensions.kt @@ -0,0 +1,20 @@ +/* + * 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. + */ + +import space.kscience.kmath.geometry.GeometrySpace +import space.kscience.kmath.geometry.Line +import space.kscience.kmath.geometry.LineSegment +import space.kscience.kmath.geometry.Vector +import space.kscience.kmath.operations.Group + +/** + * Get a line, containing this [LineSegment] + */ +context(Group) public val LineSegment.line: Line get() = Line(begin, end - begin) + +/** + * Get a length of a line segment + */ +context(GeometrySpace) public val LineSegment.length: Double get() = norm(end - begin) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt index 134342b33..a7a98288c 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/DubinsPath.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Vector2D import kotlin.math.PI import kotlin.math.acos import kotlin.math.cos @@ -17,10 +17,10 @@ internal fun Pose2D.getLeftCircle(radius: Double): Circle2D = getTangentCircles( internal fun Pose2D.getRightCircle(radius: Double): Circle2D = getTangentCircles(radius).second -internal fun Pose2D.getTangentCircles(radius: Double): Pair { +internal fun Pose2D.getTangentCircles(radius: Double): Pair = with(Euclidean2DSpace) { val dX = radius * cos(theta) val dY = radius * sin(theta) - return Circle2D(Vector2D(x - dX, y + dY), radius) to Circle2D(Vector2D(x + dX, y - dY), radius) + return Circle2D(vector(x - dX, y + dY), radius) to Circle2D(vector(x + dX, y - dY), radius) } internal fun leftOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = outerTangent(a, b, ArcSegment.Direction.LEFT) @@ -29,21 +29,21 @@ internal fun rightOuterTangent(a: Circle2D, b: Circle2D): StraightSegment = oute ArcSegment.Direction.RIGHT ) -private fun outerTangent(a: Circle2D, b: Circle2D, side: ArcSegment.Direction): StraightSegment { +private fun outerTangent(a: Circle2D, b: Circle2D, side: ArcSegment.Direction): StraightSegment = with(Euclidean2DSpace){ val centers = StraightSegment(a.center, b.center) val p1 = when (side) { - ArcSegment.Direction.LEFT -> Vector2D( + ArcSegment.Direction.LEFT -> vector( a.center.x - a.radius * cos(centers.theta), a.center.y + a.radius * sin(centers.theta) ) - ArcSegment.Direction.RIGHT -> Vector2D( + ArcSegment.Direction.RIGHT -> vector( a.center.x + a.radius * cos(centers.theta), a.center.y - a.radius * sin(centers.theta) ) } return StraightSegment( p1, - Vector2D(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) + vector(p1.x + (centers.end.x - centers.start.x), p1.y + (centers.end.y - centers.start.y)) ) } @@ -53,7 +53,7 @@ internal fun leftInnerTangent(base: Circle2D, direction: Circle2D): StraightSegm internal fun rightInnerTangent(base: Circle2D, direction: Circle2D): StraightSegment? = innerTangent(base, direction, ArcSegment.Direction.RIGHT) -private fun innerTangent(base: Circle2D, direction: Circle2D, side: ArcSegment.Direction): StraightSegment? { +private fun innerTangent(base: Circle2D, direction: Circle2D, side: ArcSegment.Direction): StraightSegment? = with(Euclidean2DSpace){ val centers = StraightSegment(base.center, direction.center) if (centers.length < base.radius * 2) return null val angle = theta( @@ -64,8 +64,8 @@ private fun innerTangent(base: Circle2D, direction: Circle2D, side: ArcSegment.D ) val dX = base.radius * sin(angle) val dY = base.radius * cos(angle) - val p1 = Vector2D(base.center.x + dX, base.center.y + dY) - val p2 = Vector2D(direction.center.x - dX, direction.center.y - dY) + val p1 = vector(base.center.x + dX, base.center.y + dY) + val p2 = vector(direction.center.x - dX, direction.center.y - dY) return StraightSegment(p1, p2) } @@ -106,7 +106,7 @@ public class DubinsPath( public fun shortest(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath = all(start, end, turningRadius).minBy { it.length } - public fun rlr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { + public fun rlr(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? = with(Euclidean2DSpace){ val c1 = start.getRightCircle(turningRadius) val c2 = end.getRightCircle(turningRadius) val centers = StraightSegment(c1.center, c2.center) @@ -115,20 +115,20 @@ public class DubinsPath( var theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle2D(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + val p1 = vector(c1.center.x + dX, c1.center.y + dY) theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val p2 = vector(e.center.x + dX, e.center.y + dY) val a1 = ArcSegment.of(c1.center, start, p1, ArcSegment.Direction.RIGHT) val a2 = ArcSegment.of(e.center, p1, p2, ArcSegment.Direction.LEFT) val a3 = ArcSegment.of(c2.center, p2, end, ArcSegment.Direction.RIGHT) return DubinsPath(a1, a2, a3) } - public fun lrl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath? { + public fun lrl(start: Pose2D, end: Pose2D, turningRadius: Double): DubinsPath?= with(Euclidean2DSpace) { val c1 = start.getLeftCircle(turningRadius) val c2 = end.getLeftCircle(turningRadius) val centers = StraightSegment(c1.center, c2.center) @@ -137,13 +137,13 @@ public class DubinsPath( var theta = theta(centers.theta + acos(centers.length / (turningRadius * 4))) var dX = turningRadius * sin(theta) var dY = turningRadius * cos(theta) - val p = Vector2D(c1.center.x + dX * 2, c1.center.y + dY * 2) + val p = vector(c1.center.x + dX * 2, c1.center.y + dY * 2) val e = Circle2D(p, turningRadius) - val p1 = Vector2D(c1.center.x + dX, c1.center.y + dY) + val p1 = vector(c1.center.x + dX, c1.center.y + dY) theta = theta(centers.theta - acos(centers.length / (turningRadius * 4))) dX = turningRadius * sin(theta) dY = turningRadius * cos(theta) - val p2 = Vector2D(e.center.x + dX, e.center.y + dY) + val p2 = vector(e.center.x + dX, e.center.y + dY) val a1 = ArcSegment.of(c1.center, start, p1, ArcSegment.Direction.LEFT) val a2 = ArcSegment.of(e.center, p1, p2, ArcSegment.Direction.RIGHT) val a3 = ArcSegment.of(c2.center, p2, end, ArcSegment.Direction.LEFT) diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt index 1f7c4a52e..a7570156c 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Pose2D.kt @@ -5,29 +5,29 @@ package space.kscience.kmath.trajectory +import space.kscience.kmath.geometry.DoubleVector2D import space.kscience.kmath.geometry.Vector -import space.kscience.kmath.geometry.Vector2D import kotlin.math.atan2 /** * Combination of [Vector] and its view angle */ -public interface Pose2D: Vector2D{ - public val coordinate: Vector2D +public interface Pose2D: DoubleVector2D{ + public val coordinate: DoubleVector2D public val theta: Double } public class PhaseVector2D( - override val coordinate: Vector2D, - public val velocity: Vector2D -): Pose2D, Vector2D by coordinate{ + override val coordinate: DoubleVector2D, + public val velocity: DoubleVector2D +): Pose2D, DoubleVector2D by coordinate{ override val theta: Double get() = atan2(velocity.y, velocity.x) } internal class Pose2DImpl( - override val coordinate: Vector2D, + override val coordinate: DoubleVector2D, override val theta: Double -) : Pose2D, Vector2D by coordinate +) : Pose2D, DoubleVector2D by coordinate -public fun Pose2D(coordinate: Vector2D, theta: Double): Pose2D = Pose2DImpl(coordinate, theta) \ No newline at end of file +public fun Pose2D(coordinate: DoubleVector2D, theta: Double): Pose2D = Pose2DImpl(coordinate, theta) \ No newline at end of file diff --git a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt index 2e97d43b0..554607cbd 100644 --- a/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt +++ b/kmath-trajectory/src/commonMain/kotlin/space/kscience/kmath/trajectory/Trajectory.kt @@ -6,8 +6,8 @@ package space.kscience.kmath.trajectory import space.kscience.kmath.geometry.Circle2D +import space.kscience.kmath.geometry.DoubleVector2D import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.geometry.circumference import kotlin.math.PI import kotlin.math.atan2 @@ -20,8 +20,8 @@ public sealed interface Trajectory { * Straight path segment. The order of start and end defines the direction */ public data class StraightSegment( - internal val start: Vector2D, - internal val end: Vector2D, + internal val start: DoubleVector2D, + internal val end: DoubleVector2D, ) : Trajectory { override val length: Double get() = start.distanceTo(end) @@ -68,9 +68,9 @@ public data class ArcSegment( } public companion object { - public fun of(center: Vector2D, start: Vector2D, end: Vector2D, direction: Direction): ArcSegment { + public fun of(center: DoubleVector2D, start: DoubleVector2D, end: DoubleVector2D, direction: Direction): ArcSegment { fun calculatePose( - vector: Vector2D, + vector: DoubleVector2D, theta: Double, direction: Direction, ): Pose2D = Pose2D( diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt index 7ee68bd92..5a9cc5be8 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/Math.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.trajectory -import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.Euclidean2DSpace import kotlin.math.PI import kotlin.math.abs import kotlin.math.sin @@ -13,12 +13,12 @@ fun Double.equalFloat(other: Double) = abs(this - other) < maxFloatDelta fun Pose2D.equalsFloat(other: Pose2D) = x.equalFloat(other.x) && y.equalFloat(other.y) && theta.equalFloat(other.theta) fun StraightSegment.inverse() = StraightSegment(end, start) -fun StraightSegment.shift(shift: Int, width: Double): StraightSegment { +fun StraightSegment.shift(shift: Int, width: Double): StraightSegment = with(Euclidean2DSpace){ val dX = width * sin(inverse().theta) val dY = width * sin(theta) return StraightSegment( - Vector2D(start.x - dX * shift, start.y - dY * shift), - Vector2D(end.x - dX * shift, end.y - dY * shift) + vector(start.x - dX * shift, start.y - dY * shift), + vector(end.x - dX * shift, end.y - dY * shift) ) } diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt index 09375a400..68a5f8454 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/dubins/DubinsTests.kt @@ -5,8 +5,7 @@ package space.kscience.kmath.trajectory.dubins -import space.kscience.kmath.geometry.Euclidean2DSpace.distanceTo -import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.trajectory.* import kotlin.test.Test import kotlin.test.assertNotNull @@ -16,8 +15,8 @@ import kotlin.test.assertTrue class DubinsTests { @Test - fun dubinsTest() { - val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + fun dubinsTest() = with(Euclidean2DSpace){ + val straight = StraightSegment(vector(0.0, 0.0), vector(100.0, 100.0)) val lineP1 = straight.shift(1, 10.0).inverse() val start = Pose2D(straight.end, straight.theta) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt index c66fa201b..88423ee99 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/ArcTests.kt @@ -1,7 +1,7 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.circumference import space.kscience.kmath.trajectory.ArcSegment import space.kscience.kmath.trajectory.radiansToDegrees @@ -11,9 +11,9 @@ import kotlin.test.assertEquals class ArcTests { @Test - fun arcTest() { - val circle = Circle2D(Vector2D(0.0, 0.0), 2.0) - val arc = ArcSegment.of(circle.center, Vector2D(-2.0, 0.0), Vector2D(0.0, 2.0), ArcSegment.Direction.RIGHT) + fun arcTest() = with(Euclidean2DSpace){ + val circle = Circle2D(vector(0.0, 0.0), 2.0) + val arc = ArcSegment.of(circle.center, vector(-2.0, 0.0), vector(0.0, 2.0), ArcSegment.Direction.RIGHT) assertEquals(circle.circumference / 4, arc.length, 1.0) assertEquals(0.0, arc.start.theta.radiansToDegrees()) assertEquals(90.0, arc.end.theta.radiansToDegrees()) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt index 5170c1db5..f1f9c6a3b 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/CircleTests.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Circle2D -import space.kscience.kmath.geometry.Vector2D +import space.kscience.kmath.geometry.Euclidean2DSpace import space.kscience.kmath.geometry.circumference import space.kscience.kmath.trajectory.maxFloatDelta import kotlin.test.Test @@ -16,7 +16,7 @@ class CircleTests { @Test fun arcTest() { - val center = Vector2D(0.0, 0.0) + val center = Euclidean2DSpace.vector(0.0, 0.0) val radius = 2.0 val expectedCircumference = 12.56637 val circle = Circle2D(center, radius) diff --git a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt index 11eaa0fb3..b8fe256c7 100644 --- a/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt +++ b/kmath-trajectory/src/commonTest/kotlin/space/kscience/kmath/trajectory/segments/LineTests.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.trajectory.segments import space.kscience.kmath.geometry.Euclidean2DSpace -import space.kscience.kmath.geometry.Vector2D import space.kscience.kmath.trajectory.StraightSegment import space.kscience.kmath.trajectory.radiansToDegrees import kotlin.math.pow @@ -12,22 +11,22 @@ import kotlin.test.assertEquals class LineTests { @Test - fun lineTest() { - val straight = StraightSegment(Vector2D(0.0, 0.0), Vector2D(100.0, 100.0)) + fun lineTest() = with(Euclidean2DSpace){ + val straight = StraightSegment(vector(0.0, 0.0), vector(100.0, 100.0)) assertEquals(sqrt(100.0.pow(2) + 100.0.pow(2)), straight.length) assertEquals(45.0, straight.theta.radiansToDegrees()) } @Test - fun lineAngleTest() { + fun lineAngleTest() = with(Euclidean2DSpace){ //val zero = Vector2D(0.0, 0.0) - val north = StraightSegment(Euclidean2DSpace.zero, Vector2D(0.0, 2.0)) + val north = StraightSegment(Euclidean2DSpace.zero, vector(0.0, 2.0)) assertEquals(0.0, north.theta.radiansToDegrees()) - val east = StraightSegment(Euclidean2DSpace.zero, Vector2D(2.0, 0.0)) + val east = StraightSegment(Euclidean2DSpace.zero, vector(2.0, 0.0)) assertEquals(90.0, east.theta.radiansToDegrees()) - val south = StraightSegment(Euclidean2DSpace.zero, Vector2D(0.0, -2.0)) + val south = StraightSegment(Euclidean2DSpace.zero, vector(0.0, -2.0)) assertEquals(180.0, south.theta.radiansToDegrees()) - val west = StraightSegment(Euclidean2DSpace.zero, Vector2D(-2.0, 0.0)) + val west = StraightSegment(Euclidean2DSpace.zero, vector(-2.0, 0.0)) assertEquals(270.0, west.theta.radiansToDegrees()) } } From ad9775132792b93e33c143cbfe38b347bc26abf3 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 4 Sep 2022 20:59:30 +0300 Subject: [PATCH 168/174] Refactor for build tools 0.13.0 --- build.gradle.kts | 11 ++++++++-- .../kmath/structures/StreamDoubleFieldND.kt | 4 ++++ .../kscience/kmath/tensors/OLSWithSVD.kt | 2 ++ .../kscience/kmath/tensors/neuralNetwork.kt | 3 +++ gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- kmath-ast/build.gradle.kts | 7 +++++-- .../ast/rendering/multiplatformToString.kt | 9 ++++++++ .../kscience/kmath/ast/runCompilerTest.kt | 10 +++++++++ kmath-commons/build.gradle.kts | 3 +-- kmath-complex/build.gradle.kts | 12 ++++++----- kmath-core/build.gradle.kts | 21 +++++++------------ kmath-coroutines/build.gradle.kts | 8 ++++--- kmath-dimensions/build.gradle.kts | 5 ++++- kmath-ejml/build.gradle.kts | 3 +-- .../space/kscience/kmath/ejml/_generated.kt | 4 ++-- kmath-for-real/build.gradle.kts | 8 ++++--- kmath-functions/build.gradle.kts | 8 ++++--- kmath-geometry/build.gradle.kts | 5 ++++- kmath-histograms/build.gradle.kts | 5 ++++- kmath-kotlingrad/build.gradle.kts | 3 +-- kmath-memory/build.gradle.kts | 5 ++++- .../kscience/kmath/multik/MultikNDTest.kt | 2 ++ kmath-nd4j/build.gradle.kts | 3 +-- .../kscience/kmath/nd4j/Nd4jArrayAlgebra.kt | 2 ++ .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 3 +++ kmath-optimization/build.gradle.kts | 5 ++++- kmath-polynomial/build.gradle.kts | 6 ++++-- kmath-stat/build.gradle.kts | 5 ++++- kmath-symja/build.gradle.kts | 3 +-- .../tensorflow/DoubleTensorFlowAlgebra.kt | 1 + .../kmath/tensorflow/DoubleTensorFlowOps.kt | 2 ++ kmath-tensors/build.gradle.kts | 8 ++++--- kmath-trajectory/build.gradle.kts | 8 ++++--- kmath-viktor/build.gradle.kts | 5 ++--- .../kscience/kmath/viktor/ViktorBuffer.kt | 2 +- test-utils/build.gradle.kts | 5 ++++- 37 files changed, 136 insertions(+), 64 deletions(-) create mode 100644 kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt create mode 100644 kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 04cb76285..4a083b437 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,6 @@ +import space.kscience.gradle.useApache2Licence +import space.kscience.gradle.useSPCTeam + plugins { id("space.kscience.gradle.project") id("org.jetbrains.kotlinx.kover") version "0.5.0" @@ -68,8 +71,12 @@ subprojects { readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - github("kmath", addToRelease = false) - space() + pom("https://github.com/SciProgCentre/kmath") { + useApache2Licence() + useSPCTeam() + } + github("kmath", "SciProgCentre", addToRelease = false) + space("https://maven.pkg.jetbrains.space/mipt-npm/p/sci/dev") sonatype() } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index aed0a7868..4aa420305 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.structures +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField @@ -49,6 +50,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND.map( transform: DoubleField.(Double) -> Double, ): BufferND { @@ -56,6 +58,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): BufferND { @@ -69,6 +72,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND, right: StructureND, diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index f7c5bb4b7..8082ed8e2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra @@ -13,6 +14,7 @@ import kotlin.math.abs // OLS estimator using SVD +@OptIn(PerformancePitfall::class) fun main() { //seed for random val randSeed = 100500L diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt index cbc83c336..502f6d53f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt @@ -3,8 +3,11 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:OptIn(PerformancePitfall::class) + package space.kscience.kmath.tensors +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensor diff --git a/gradle.properties b/gradle.properties index b3e3f4cda..0d1506980 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,4 +12,4 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx4096m -toolsVersion=0.12.0-kotlin-1.7.20-Beta +toolsVersion=0.13.0-kotlin-1.7.20-Beta diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fcea..8049c684f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index c1333eba5..7fd0f43f7 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -1,6 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") + id("space.kscience.gradle.mpp") +} + +kscience{ + native() } kotlin.js { diff --git a/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt new file mode 100644 index 000000000..ec66be830 --- /dev/null +++ b/kmath-ast/src/nativeMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2018-2022 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.ast.rendering + +internal actual fun Double.multiplatformToString(): String = toString() +internal actual fun Float.multiplatformToString(): String = toString() diff --git a/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt b/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt new file mode 100644 index 000000000..0674b0492 --- /dev/null +++ b/kmath-ast/src/nativeTest/kotlin/space/kscience/kmath/ast/runCompilerTest.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2018-2022 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.ast + +internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { + //doNothing +} \ No newline at end of file diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 643307b48..50fef7ac8 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("jvm") - id("space.kscience.gradle.common") + id("space.kscience.gradle.jvm") } description = "Commons math binding for kmath" diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts index dbe96b153..b63def0a7 100644 --- a/kmath-complex/build.gradle.kts +++ b/kmath-complex/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") +} + +kscience { + native() } kotlin.sourceSets { @@ -20,14 +22,14 @@ readme { feature( id = "complex", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt" - ){ + ) { "Complex numbers operations" } feature( id = "quaternion", ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt" - ){ + ) { "Quaternions and their composition" } } diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index d055b5350..f33d33324 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -1,6 +1,13 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() + + dependencies { + api(project(":kmath-memory")) + } } kotlin.sourceSets { @@ -10,20 +17,8 @@ kotlin.sourceSets { it.optIn("space.kscience.kmath.misc.PerformancePitfall") it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } - - commonMain { - dependencies { - api(project(":kmath-memory")) - } - } } -//generateUml { -// classTree { -// -// } -//} - readme { description = "Core classes, algebra definitions, basic linear algebra" maturity = space.kscience.gradle.Maturity.DEVELOPMENT diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 104adf268..529084619 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") +} + +kscience{ + native() } kotlin.sourceSets { diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts index 1c042ab70..29c0eccb6 100644 --- a/kmath-dimensions/build.gradle.kts +++ b/kmath-dimensions/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() } description = "A proof of concept module for adding type-safe dimensions to structures" diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts index d400d6600..d7f780d79 100644 --- a/kmath-ejml/build.gradle.kts +++ b/kmath-ejml/build.gradle.kts @@ -1,8 +1,7 @@ import space.kscience.kmath.ejml.codegen.ejmlCodegen plugins { - kotlin("jvm") - id("space.kscience.gradle.common") + id("space.kscience.gradle.jvm") } dependencies { diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt index 5426055b3..aac327a84 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -1,6 +1,6 @@ /* - * Copyright 2018-2022 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. + * 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 file. */ /* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 6b6242c24..308b8d732 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") +} + +kscience{ + native() } kotlin.sourceSets.commonMain { diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index c68102c2e..2e7b023c1 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") +} + +kscience{ + native() } description = "Functions, integration and interpolation" diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index c2057bcbe..b868af8d0 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() } kotlin.sourceSets.commonMain { diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 94d1f5fb7..d31526a74 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() } //apply(plugin = "kotlinx-atomicfu") diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index a7f4ee37f..cf4a4bc1d 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("jvm") - id("space.kscience.gradle.common") + id("space.kscience.gradle.jvm") } kotlin.sourceSets diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 55a7ff6aa..50eb448a7 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience { + native() } readme { diff --git a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt index 8ad220221..392532d8e 100644 --- a/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ b/kmath-multik/src/commonTest/kotlin/space/kscience/kmath/multik/MultikNDTest.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.multik import org.jetbrains.kotlinx.multik.default.DefaultEngine +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.one import space.kscience.kmath.operations.DoubleField @@ -14,6 +15,7 @@ import space.kscience.kmath.tensors.core.tensorAlgebra import kotlin.test.Test import kotlin.test.assertTrue +@OptIn(PerformancePitfall::class) internal class MultikNDTest { val multikAlgebra = MultikDoubleAlgebra(DefaultEngine()) diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index 11af7d6dc..e5c4af891 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("jvm") - id("space.kscience.gradle.common") + id("space.kscience.gradle.jvm") } description = "ND4J NDStructure implementation and according NDAlgebra classes" diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt index f359b9115..859773211 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt @@ -45,6 +45,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.mapIndexed( transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { @@ -53,6 +54,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND, right: StructureND, diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index 5ecfe30d6..b6a2029e7 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -40,12 +40,15 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): Nd4jArrayStructure + @OptIn(PerformancePitfall::class) override fun StructureND.map(transform: A.(T) -> T): Nd4jArrayStructure = structureND(shape) { index -> elementAlgebra.transform(get(index)) } + @OptIn(PerformancePitfall::class) override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure = structureND(shape) { index -> elementAlgebra.transform(index, get(index)) } + @OptIn(PerformancePitfall::class) override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): Nd4jArrayStructure { require(left.shape.contentEquals(right.shape)) return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) } diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts index 53f379830..f4256b9aa 100644 --- a/kmath-optimization/build.gradle.kts +++ b/kmath-optimization/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() } kotlin.sourceSets { diff --git a/kmath-polynomial/build.gradle.kts b/kmath-polynomial/build.gradle.kts index c6946878c..4e469f0d1 100644 --- a/kmath-polynomial/build.gradle.kts +++ b/kmath-polynomial/build.gradle.kts @@ -1,7 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - // Disable native target to avoid CI crashes -// id("space.kscience.gradle.native") +} + +kscience{ + native() } description = "Polynomials, rational functions, and utilities" diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index 1d1831047..f6ca54e17 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() } kotlin.sourceSets { diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts index 1984236ca..8741de2ae 100644 --- a/kmath-symja/build.gradle.kts +++ b/kmath-symja/build.gradle.kts @@ -4,8 +4,7 @@ */ plugins { - kotlin("jvm") - id("space.kscience.gradle.common") + id("space.kscience.gradle.jvm") } description = "Symja integration module" diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt index fa7050d2a..c4d192792 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt @@ -93,6 +93,7 @@ public fun DoubleField.produceWithTF( * * The resulting tensors are available outside of scope */ +@OptIn(UnstableKMathAPI::class) public fun DoubleField.produceMapWithTF( block: DoubleTensorFlowAlgebra.() -> Map>, ): Map> = Graph().use { graph -> diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt index 21340a8db..a35556be1 100644 --- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt +++ b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensorflow import org.junit.jupiter.api.Test +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.get import space.kscience.kmath.nd.structureND import space.kscience.kmath.operations.DoubleField @@ -13,6 +14,7 @@ import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.sum import kotlin.test.assertEquals +@OptIn(UnstableKMathAPI::class) class DoubleTensorFlowOps { @Test fun basicOps() { diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index b2a4c36bd..3d92f07b6 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") +} + +kscience{ + native() } kotlin.sourceSets { diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts index f4dba25ab..5ee0a241d 100644 --- a/kmath-trajectory/build.gradle.kts +++ b/kmath-trajectory/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - kotlin("multiplatform") - id("space.kscience.gradle.common") - id("space.kscience.gradle.native") + id("space.kscience.gradle.mpp") +} + +kscience{ + native() } kotlin.sourceSets.commonMain { diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts index 1b22e9c38..7a135f316 100644 --- a/kmath-viktor/build.gradle.kts +++ b/kmath-viktor/build.gradle.kts @@ -1,13 +1,12 @@ plugins { - kotlin("jvm") - id("space.kscience.gradle.common") + id("space.kscience.gradle.jvm") } description = "Binding for https://github.com/JetBrains-Research/viktor" dependencies { api(project(":kmath-core")) - api("org.jetbrains.bio:viktor:1.1.0") + api("org.jetbrains.bio:viktor:1.2.0") } readme { diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index 90d5ad9a9..52dc1e192 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -13,7 +13,7 @@ import space.kscience.kmath.structures.MutableBuffer @JvmInline public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { override val size: Int - get() = flatArray.size + get() = flatArray.length override inline fun get(index: Int): Double = flatArray[index] diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts index 49c4758e3..98bd7328d 100644 --- a/test-utils/build.gradle.kts +++ b/test-utils/build.gradle.kts @@ -1,6 +1,9 @@ plugins { id("space.kscience.gradle.mpp") - id("space.kscience.gradle.native") +} + +kscience{ + native() } kotlin.sourceSets { From 5042fda751940c04d944046d645a58c685776a75 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 5 Sep 2022 16:30:39 +0300 Subject: [PATCH 169/174] Int Tensor Algebra implementation --- build.gradle.kts | 2 +- buildSrc/build.gradle.kts | 3 +- .../space/kscience/kmath/nd/BufferND.kt | 2 +- .../space/kscience/kmath/nd/DoubleFieldND.kt | 2 +- .../space/kscience/kmath/nd/IntRingND.kt | 50 ++ .../space/kscience/kmath/nd/ShortRingND.kt | 5 +- .../space/kscience/kmath/nd/StructureND.kt | 17 +- .../kmath/operations/BufferAlgebra.kt | 3 + kmath-geometry/build.gradle.kts | 10 +- kmath-tensors/build.gradle.kts | 4 + .../kmath/tensors/core/DoubleTensorAlgebra.kt | 6 +- .../kscience/kmath/tensors/core/IntTensor.kt | 10 +- .../kmath/tensors/core/IntTensorAlgebra.kt | 493 ++++++++++++++++++ .../kmath/tensors/core/internal/checks.kt | 9 +- .../tensors/core/internal/tensorCastsUtils.kt | 4 +- .../tensors/core/tensorAlgebraExtensions.kt | 5 +- kmath-trajectory/build.gradle.kts | 4 +- 17 files changed, 593 insertions(+), 36 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt diff --git a/build.gradle.kts b/build.gradle.kts index 4a083b437..890824d65 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,7 +14,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-2" + version = "0.3.1-dev-3" } subprojects { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 9bf5d03d0..0f95a7b3f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,8 +1,7 @@ plugins { - kotlin("jvm") version "1.7.20-Beta" `kotlin-dsl` `version-catalog` - alias(npmlibs.plugins.kotlin.plugin.serialization) + kotlin("plugin.serialization") version "1.6.21" } java.targetCompatibility = JavaVersion.VERSION_11 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index 5484ce545..1eb08fa8c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -56,7 +56,7 @@ public inline fun StructureND.mapToBuffer( * @param strides The strides to access elements of [MutableBuffer] by linear indices. * @param buffer The underlying buffer. */ -public class MutableBufferND( +public open class MutableBufferND( strides: ShapeIndexer, override val buffer: MutableBuffer, ) : MutableStructureND, BufferND(strides, buffer) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt index 7f8d3c55d..4e8876731 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt @@ -16,7 +16,7 @@ import kotlin.math.pow as kpow public class DoubleBufferND( indexes: ShapeIndexer, override val buffer: DoubleBuffer, -) : BufferND(indexes, buffer) +) : MutableBufferND(indexes, buffer) public sealed class DoubleFieldOpsND : BufferedFieldOpsND(DoubleField.bufferAlgebra), diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt new file mode 100644 index 000000000..ac01239a9 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/IntRingND.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2018-2022 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.nd + +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.IntRing +import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.structures.IntBuffer +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + +public class IntBufferND( + indexes: ShapeIndexer, + override val buffer: IntBuffer, +) : MutableBufferND(indexes, buffer) + +public sealed class IntRingOpsND : BufferedRingOpsND(IntRing.bufferAlgebra) { + + override fun structureND(shape: Shape, initializer: IntRing.(IntArray) -> Int): IntBufferND { + val indexer = indexerBuilder(shape) + return IntBufferND( + indexer, + IntBuffer(indexer.linearSize) { offset -> + elementAlgebra.initializer(indexer.index(offset)) + } + ) + } + + public companion object : IntRingOpsND() +} + +@OptIn(UnstableKMathAPI::class) +public class IntRingND( + override val shape: Shape +) : IntRingOpsND(), RingND, NumbersAddOps> { + + override fun number(value: Number): BufferND { + val int = value.toInt() // minimize conversions + return structureND(shape) { int } + } +} + +public inline fun IntRing.withNdAlgebra(vararg shape: Int, action: IntRingND.() -> R): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return IntRingND(shape).run(action) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt index ea37da7a3..249b6801d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt @@ -22,8 +22,9 @@ public class ShortRingND( ) : ShortRingOpsND(), RingND, NumbersAddOps> { override fun number(value: Number): BufferND { - val d = value.toShort() // minimize conversions - return structureND(shape) { d } + val short + = value.toShort() // minimize conversions + return structureND(shape) { short } } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 0fed49f40..aece10c2e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -82,7 +82,7 @@ public interface StructureND : Featured, WithShape { public fun contentEquals( st1: StructureND, st2: StructureND, - tolerance: Double = 1e-11 + tolerance: Double = 1e-11, ): Boolean { if (st1 === st2) return true @@ -101,11 +101,17 @@ public interface StructureND : Featured, WithShape { val bufferRepr: String = when (structure.shape.size) { 1 -> (0 until structure.shape[0]).map { structure[it] } .joinToString(prefix = "[", postfix = "]", separator = ", ") - 2 -> (0 until structure.shape[0]).joinToString(prefix = "[\n", postfix = "\n]", separator = ",\n") { i -> + + 2 -> (0 until structure.shape[0]).joinToString( + prefix = "[\n", + postfix = "\n]", + separator = ",\n" + ) { i -> (0 until structure.shape[1]).joinToString(prefix = " [", postfix = "]", separator = ", ") { j -> structure[i, j].toString() } } + else -> "..." } val className = structure::class.simpleName ?: "StructureND" @@ -226,6 +232,13 @@ public interface MutableStructureND : StructureND { public operator fun set(index: IntArray, value: T) } +/** + * Set value at specified indices + */ +public operator fun MutableStructureND.set(vararg index: Int, value: T) { + set(index, value) +} + /** * Transform a structure element-by element in place. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt index 3af77856c..af0bc4d9b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt @@ -142,6 +142,9 @@ public open class BufferRingOps>( super.binaryOperationFunction(operation) } +public val IntRing.bufferAlgebra: BufferRingOps + get() = BufferRingOps(IntRing) + public val ShortRing.bufferAlgebra: BufferRingOps get() = BufferRingOps(ShortRing) diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index b868af8d0..52d76d5d2 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -4,18 +4,12 @@ plugins { kscience{ native() -} - -kotlin.sourceSets.commonMain { - dependencies { + withContextReceivers() + dependencies{ api(projects.kmath.kmathComplex) } } -kscience { - withContextReceivers() -} - readme { maturity = space.kscience.gradle.Maturity.PROTOTYPE } diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 3d92f07b6..78ea4ba42 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -4,6 +4,10 @@ plugins { kscience{ native() + dependencies { + api(projects.kmathCore) + api(projects.kmathStat) + } } kotlin.sourceSets { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 53115d5e5..94ad3f43c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -31,8 +31,7 @@ public open class DoubleTensorAlgebra : public companion object : DoubleTensorAlgebra() - override val elementAlgebra: DoubleField - get() = DoubleField + override val elementAlgebra: DoubleField get() = DoubleField /** @@ -622,7 +621,8 @@ public open class DoubleTensorAlgebra : } val resNumElements = resShape.reduce(Int::times) val init = foldFunction(DoubleArray(1) { 0.0 }) - val resTensor = BufferedTensor(resShape, + val resTensor = BufferedTensor( + resShape, MutableBuffer.auto(resNumElements) { init }, 0 ) for (index in resTensor.indices) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt index ccff9606e..a2b942bf0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt @@ -11,11 +11,11 @@ import space.kscience.kmath.tensors.core.internal.array /** * Default [BufferedTensor] implementation for [Int] values */ -public class IntTensor internal constructor( +public class IntTensor @PublishedApi internal constructor( shape: IntArray, buffer: IntArray, - offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset){ - public fun asDouble() : DoubleTensor = - DoubleTensor(shape, mutableBuffer.array().map{ it.toDouble()}.toDoubleArray(), bufferStart) + offset: Int = 0, +) : BufferedTensor(shape, IntBuffer(buffer), offset) { + public fun asDouble(): DoubleTensor = + DoubleTensor(shape, mutableBuffer.array().map { it.toDouble() }.toDoubleArray(), bufferStart) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt new file mode 100644 index 000000000..0c8ddcf87 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt @@ -0,0 +1,493 @@ +/* + * Copyright 2018-2022 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + + +@file:OptIn(PerformancePitfall::class) + +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.IntRing +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.tensors.api.* +import space.kscience.kmath.tensors.core.internal.* +import kotlin.math.* + +/** + * Implementation of basic operations over double tensors and basic algebra operations on them. + */ +public open class IntTensorAlgebra : TensorAlgebra { + + public companion object : IntTensorAlgebra() + + override fun StructureND.dot(other: StructureND): Tensor { + TODO("Not yet implemented") + } + + override val elementAlgebra: IntRing get() = IntRing + + + /** + * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. + * + * @param transform the function to be applied to each element of the tensor. + * @return the resulting tensor after applying the function. + */ + @PerformancePitfall + @Suppress("OVERRIDE_BY_INLINE") + final override inline fun StructureND.map(transform: IntRing.(Int) -> Int): IntTensor { + val tensor = this.tensor + //TODO remove additional copy + val sourceArray = tensor.copyArray() + val array = IntArray(tensor.numElements) { IntRing.transform(sourceArray[it]) } + return IntTensor( + tensor.shape, + array, + tensor.bufferStart + ) + } + + @PerformancePitfall + @Suppress("OVERRIDE_BY_INLINE") + final override inline fun StructureND.mapIndexed(transform: IntRing.(index: IntArray, Int) -> Int): IntTensor { + val tensor = this.tensor + //TODO remove additional copy + val sourceArray = tensor.copyArray() + val array = IntArray(tensor.numElements) { IntRing.transform(tensor.indices.index(it), sourceArray[it]) } + return IntTensor( + tensor.shape, + array, + tensor.bufferStart + ) + } + + @PerformancePitfall + override fun zip( + left: StructureND, + right: StructureND, + transform: IntRing.(Int, Int) -> Int, + ): IntTensor { + require(left.shape.contentEquals(right.shape)) { + "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" + } + val leftTensor = left.tensor + val leftArray = leftTensor.copyArray() + val rightTensor = right.tensor + val rightArray = rightTensor.copyArray() + val array = IntArray(leftTensor.numElements) { IntRing.transform(leftArray[it], rightArray[it]) } + return IntTensor( + leftTensor.shape, + array + ) + } + + override fun StructureND.valueOrNull(): Int? = if (tensor.shape contentEquals intArrayOf(1)) + tensor.mutableBuffer.array()[tensor.bufferStart] else null + + override fun StructureND.value(): Int = valueOrNull() + ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") + + /** + * Constructs a tensor with the specified shape and data. + * + * @param shape the desired shape for the tensor. + * @param buffer one-dimensional data array. + * @return tensor with the [shape] shape and [buffer] data. + */ + public fun fromArray(shape: IntArray, buffer: IntArray): IntTensor { + checkEmptyShape(shape) + check(buffer.isNotEmpty()) { "Illegal empty buffer provided" } + check(buffer.size == shape.reduce(Int::times)) { + "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" + } + return IntTensor(shape, buffer, 0) + } + + /** + * Constructs a tensor with the specified shape and initializer. + * + * @param shape the desired shape for the tensor. + * @param initializer mapping tensor indices to values. + * @return tensor with the [shape] shape and data generated by the [initializer]. + */ + override fun structureND(shape: IntArray, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray( + shape, + TensorLinearStructure(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray() + ) + + override operator fun Tensor.get(i: Int): IntTensor { + val lastShape = tensor.shape.drop(1).toIntArray() + val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) + val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart + return IntTensor(newShape, tensor.mutableBuffer.array(), newStart) + } + + /** + * Creates a tensor of a given shape and fills all elements with a given value. + * + * @param value the value to fill the output tensor with. + * @param shape array of integers defining the shape of the output tensor. + * @return tensor with the [shape] shape and filled with [value]. + */ + public fun full(value: Int, shape: IntArray): IntTensor { + checkEmptyShape(shape) + val buffer = IntArray(shape.reduce(Int::times)) { value } + return IntTensor(shape, buffer) + } + + /** + * Returns a tensor with the same shape as `input` filled with [value]. + * + * @param value the value to fill the output tensor with. + * @return tensor with the `input` tensor shape and filled with [value]. + */ + public fun Tensor.fullLike(value: Int): IntTensor { + val shape = tensor.shape + val buffer = IntArray(tensor.numElements) { value } + return IntTensor(shape, buffer) + } + + /** + * Returns a tensor filled with the scalar value `0`, with the shape defined by the variable argument [shape]. + * + * @param shape array of integers defining the shape of the output tensor. + * @return tensor filled with the scalar value `0`, with the [shape] shape. + */ + public fun zeros(shape: IntArray): IntTensor = full(0, shape) + + /** + * Returns a tensor filled with the scalar value `0`, with the same shape as a given array. + * + * @return tensor filled with the scalar value `0`, with the same shape as `input` tensor. + */ + public fun StructureND.zeroesLike(): IntTensor = tensor.fullLike(0) + + /** + * Returns a tensor filled with the scalar value `1`, with the shape defined by the variable argument [shape]. + * + * @param shape array of integers defining the shape of the output tensor. + * @return tensor filled with the scalar value `1`, with the [shape] shape. + */ + public fun ones(shape: IntArray): IntTensor = full(1, shape) + + /** + * Returns a tensor filled with the scalar value `1`, with the same shape as a given array. + * + * @return tensor filled with the scalar value `1`, with the same shape as `input` tensor. + */ + public fun Tensor.onesLike(): IntTensor = tensor.fullLike(1) + + /** + * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. + * + * @param n the number of rows and columns + * @return a 2-D tensor with ones on the diagonal and zeros elsewhere. + */ + public fun eye(n: Int): IntTensor { + val shape = intArrayOf(n, n) + val buffer = IntArray(n * n) { 0 } + val res = IntTensor(shape, buffer) + for (i in 0 until n) { + res[intArrayOf(i, i)] = 1 + } + return res + } + + /** + * Return a copy of the tensor. + * + * @return a copy of the `input` tensor with a copied buffer. + */ + public fun StructureND.copy(): IntTensor = + IntTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) + + override fun Int.plus(arg: StructureND): IntTensor { + val resBuffer = IntArray(arg.tensor.numElements) { i -> + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + this + } + return IntTensor(arg.shape, resBuffer) + } + + override fun StructureND.plus(arg: Int): IntTensor = arg + tensor + + override fun StructureND.plus(arg: StructureND): IntTensor { + checkShapesCompatible(tensor, arg.tensor) + val resBuffer = IntArray(tensor.numElements) { i -> + tensor.mutableBuffer.array()[i] + arg.tensor.mutableBuffer.array()[i] + } + return IntTensor(tensor.shape, resBuffer) + } + + override fun Tensor.plusAssign(value: Int) { + for (i in 0 until tensor.numElements) { + tensor.mutableBuffer.array()[tensor.bufferStart + i] += value + } + } + + override fun Tensor.plusAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg.tensor) + for (i in 0 until tensor.numElements) { + tensor.mutableBuffer.array()[tensor.bufferStart + i] += + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + } + } + + override fun Int.minus(arg: StructureND): IntTensor { + val resBuffer = IntArray(arg.tensor.numElements) { i -> + this - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + } + return IntTensor(arg.shape, resBuffer) + } + + override fun StructureND.minus(arg: Int): IntTensor { + val resBuffer = IntArray(tensor.numElements) { i -> + tensor.mutableBuffer.array()[tensor.bufferStart + i] - arg + } + return IntTensor(tensor.shape, resBuffer) + } + + override fun StructureND.minus(arg: StructureND): IntTensor { + checkShapesCompatible(tensor, arg) + val resBuffer = IntArray(tensor.numElements) { i -> + tensor.mutableBuffer.array()[i] - arg.tensor.mutableBuffer.array()[i] + } + return IntTensor(tensor.shape, resBuffer) + } + + override fun Tensor.minusAssign(value: Int) { + for (i in 0 until tensor.numElements) { + tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value + } + } + + override fun Tensor.minusAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg) + for (i in 0 until tensor.numElements) { + tensor.mutableBuffer.array()[tensor.bufferStart + i] -= + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + } + } + + override fun Int.times(arg: StructureND): IntTensor { + val resBuffer = IntArray(arg.tensor.numElements) { i -> + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] * this + } + return IntTensor(arg.shape, resBuffer) + } + + override fun StructureND.times(arg: Int): IntTensor = arg * tensor + + override fun StructureND.times(arg: StructureND): IntTensor { + checkShapesCompatible(tensor, arg) + val resBuffer = IntArray(tensor.numElements) { i -> + tensor.mutableBuffer.array()[tensor.bufferStart + i] * + arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + } + return IntTensor(tensor.shape, resBuffer) + } + + override fun Tensor.timesAssign(value: Int) { + for (i in 0 until tensor.numElements) { + tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value + } + } + + override fun Tensor.timesAssign(arg: StructureND) { + checkShapesCompatible(tensor, arg) + for (i in 0 until tensor.numElements) { + tensor.mutableBuffer.array()[tensor.bufferStart + i] *= + arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + } + } + + override fun StructureND.unaryMinus(): IntTensor { + val resBuffer = IntArray(tensor.numElements) { i -> + tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() + } + return IntTensor(tensor.shape, resBuffer) + } + + override fun Tensor.transpose(i: Int, j: Int): IntTensor { + val ii = tensor.minusIndex(i) + val jj = tensor.minusIndex(j) + checkTranspose(tensor.dimension, ii, jj) + val n = tensor.numElements + val resBuffer = IntArray(n) + + val resShape = tensor.shape.copyOf() + resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } + + val resTensor = IntTensor(resShape, resBuffer) + + for (offset in 0 until n) { + val oldMultiIndex = tensor.indices.index(offset) + val newMultiIndex = oldMultiIndex.copyOf() + newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } + + val linearIndex = resTensor.indices.offset(newMultiIndex) + resTensor.mutableBuffer.array()[linearIndex] = + tensor.mutableBuffer.array()[tensor.bufferStart + offset] + } + return resTensor + } + + override fun Tensor.view(shape: IntArray): IntTensor { + checkView(tensor, shape) + return IntTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) + } + + override fun Tensor.viewAs(other: StructureND): IntTensor = + tensor.view(other.shape) + + override fun diagonalEmbedding( + diagonalEntries: Tensor, + offset: Int, + dim1: Int, + dim2: Int, + ): IntTensor { + val n = diagonalEntries.shape.size + val d1 = minusIndexFrom(n + 1, dim1) + val d2 = minusIndexFrom(n + 1, dim2) + + check(d1 != d2) { + "Diagonal dimensions cannot be identical $d1, $d2" + } + check(d1 <= n && d2 <= n) { + "Dimension out of range" + } + + var lessDim = d1 + var greaterDim = d2 + var realOffset = offset + if (lessDim > greaterDim) { + realOffset *= -1 + lessDim = greaterDim.also { greaterDim = lessDim } + } + + val resShape = diagonalEntries.shape.slice(0 until lessDim).toIntArray() + + intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + + diagonalEntries.shape.slice(lessDim until greaterDim - 1).toIntArray() + + intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + + diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() + val resTensor = zeros(resShape) + + for (i in 0 until diagonalEntries.tensor.numElements) { + val multiIndex = diagonalEntries.tensor.indices.index(i) + + var offset1 = 0 + var offset2 = abs(realOffset) + if (realOffset < 0) { + offset1 = offset2.also { offset2 = offset1 } + } + val diagonalMultiIndex = multiIndex.slice(0 until lessDim).toIntArray() + + intArrayOf(multiIndex[n - 1] + offset1) + + multiIndex.slice(lessDim until greaterDim - 1).toIntArray() + + intArrayOf(multiIndex[n - 1] + offset2) + + multiIndex.slice(greaterDim - 1 until n - 1).toIntArray() + + resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] + } + + return resTensor.tensor + } + + private infix fun Tensor.eq( + other: Tensor, + ): Boolean { + checkShapesCompatible(tensor, other) + val n = tensor.numElements + if (n != other.tensor.numElements) { + return false + } + for (i in 0 until n) { + if (tensor.mutableBuffer[tensor.bufferStart + i] != other.tensor.mutableBuffer[other.tensor.bufferStart + i]) { + return false + } + } + return true + } + + /** + * Concatenates a sequence of tensors with equal shapes along the first dimension. + * + * @param tensors the [List] of tensors with same shapes to concatenate + * @return tensor with concatenation result + */ + public fun stack(tensors: List>): IntTensor { + check(tensors.isNotEmpty()) { "List must have at least 1 element" } + val shape = tensors[0].shape + check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } + val resShape = intArrayOf(tensors.size) + shape + val resBuffer = tensors.flatMap { + it.tensor.mutableBuffer.array().drop(it.tensor.bufferStart).take(it.tensor.numElements) + }.toIntArray() + return IntTensor(resShape, resBuffer, 0) + } + + /** + * Builds tensor from rows of the input tensor. + * + * @param indices the [IntArray] of 1-dimensional indices + * @return tensor with rows corresponding to row by [indices] + */ + public fun Tensor.rowsByIndices(indices: IntArray): IntTensor = stack(indices.map { this[it] }) + + private inline fun StructureND.fold(foldFunction: (IntArray) -> Int): Int = + foldFunction(tensor.copyArray()) + + private inline fun StructureND.foldDim( + dim: Int, + keepDim: Boolean, + foldFunction: (IntArray) -> R, + ): BufferedTensor { + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val resShape = if (keepDim) { + shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() + } else { + shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() + } + val resNumElements = resShape.reduce(Int::times) + val init = foldFunction(IntArray(1) { 0 }) + val resTensor = BufferedTensor( + resShape, + MutableBuffer.auto(resNumElements) { init }, 0 + ) + for (index in resTensor.indices) { + val prefix = index.take(dim).toIntArray() + val suffix = index.takeLast(dimension - dim - 1).toIntArray() + resTensor[index] = foldFunction(IntArray(shape[dim]) { i -> + tensor[prefix + intArrayOf(i) + suffix] + }) + } + return resTensor + } + + override fun StructureND.sum(): Int = tensor.fold { it.sum() } + + override fun StructureND.sum(dim: Int, keepDim: Boolean): IntTensor = + foldDim(dim, keepDim) { x -> x.sum() }.toIntTensor() + + override fun StructureND.min(): Int = this.fold { it.minOrNull()!! } + + override fun StructureND.min(dim: Int, keepDim: Boolean): IntTensor = + foldDim(dim, keepDim) { x -> x.minOrNull()!! }.toIntTensor() + + override fun StructureND.max(): Int = this.fold { it.maxOrNull()!! } + + override fun StructureND.max(dim: Int, keepDim: Boolean): IntTensor = + foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.toIntTensor() + + + override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = + foldDim(dim, keepDim) { x -> + x.withIndex().maxByOrNull { it.value }?.index!! + }.toIntTensor() +} + +public val Int.Companion.tensorAlgebra: IntTensorAlgebra.Companion get() = IntTensorAlgebra +public val IntRing.tensorAlgebra: IntTensorAlgebra.Companion get() = IntTensorAlgebra + + diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index 5db311db4..e997dfcca 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -16,10 +16,9 @@ internal fun checkEmptyShape(shape: IntArray) = "Illegal empty shape provided" } -internal fun checkEmptyDoubleBuffer(buffer: DoubleArray) = - check(buffer.isNotEmpty()) { - "Illegal empty buffer provided" - } +internal fun checkEmptyDoubleBuffer(buffer: DoubleArray) = check(buffer.isNotEmpty()) { + "Illegal empty buffer provided" +} internal fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray) = check(buffer.size == shape.reduce(Int::times)) { @@ -50,7 +49,7 @@ internal fun checkSquareMatrix(shape: IntArray) { } internal fun DoubleTensorAlgebra.checkSymmetric( - tensor: Tensor, epsilon: Double = 1e-6 + tensor: Tensor, epsilon: Double = 1e-6, ) = check(tensor.eq(tensor.transpose(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index dad4368c1..c19b8bf95 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -8,7 +8,6 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.structures.asMutableBuffer -import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.BufferedTensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.IntTensor @@ -43,7 +42,8 @@ internal val StructureND.tensor: DoubleTensor else -> this.toBufferedTensor().asTensor() } -internal val Tensor.tensor: IntTensor +@PublishedApi +internal val StructureND.tensor: IntTensor get() = when (this) { is IntTensor -> this else -> this.toBufferedTensor().asTensor() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt index 5904e574e..619d5c753 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt @@ -13,7 +13,10 @@ import kotlin.jvm.JvmName @JvmName("varArgOne") public fun DoubleTensorAlgebra.one(vararg shape: Int): DoubleTensor = ones(intArrayOf(*shape)) + public fun DoubleTensorAlgebra.one(shape: Shape): DoubleTensor = ones(shape) + @JvmName("varArgZero") public fun DoubleTensorAlgebra.zero(vararg shape: Int): DoubleTensor = zeros(intArrayOf(*shape)) -public fun DoubleTensorAlgebra.zero(shape: Shape): DoubleTensor = zeros(shape) \ No newline at end of file + +public fun DoubleTensorAlgebra.zero(shape: Shape): DoubleTensor = zeros(shape) diff --git a/kmath-trajectory/build.gradle.kts b/kmath-trajectory/build.gradle.kts index 5ee0a241d..16a84b691 100644 --- a/kmath-trajectory/build.gradle.kts +++ b/kmath-trajectory/build.gradle.kts @@ -4,9 +4,7 @@ plugins { kscience{ native() -} - -kotlin.sourceSets.commonMain { + withContextReceivers() dependencies { api(projects.kmath.kmathGeometry) } From a9821772dbb021f52390428cc510c182f9a1bd16 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 5 Sep 2022 22:08:35 +0300 Subject: [PATCH 170/174] Move power to ExtendedFieldOps --- .../space/kscience/kmath/nd/DoubleFieldND.kt | 12 +- .../kmath/operations/DoubleBufferOps.kt | 6 + .../kscience/kmath/operations/numbers.kt | 20 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 1 + .../core/BroadcastDoubleTensorAlgebra.kt | 41 ++- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 320 +++++++++--------- .../kmath/tensors/core/IntTensorAlgebra.kt | 172 +++++----- .../kmath/tensors/core/internal/checks.kt | 4 +- .../tensors/core/internal/tensorCastsUtils.kt | 21 +- .../kmath/tensors/core/tensorCasts.kt | 14 +- .../kmath/tensors/core/TestDoubleTensor.kt | 10 +- 11 files changed, 320 insertions(+), 301 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt index 4e8876731..aab137321 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.operations.* import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.math.pow import kotlin.math.pow as kpow public class DoubleBufferND( @@ -165,6 +166,15 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND(D override fun atanh(arg: StructureND): DoubleBufferND = mapInline(arg.toBufferND()) { kotlin.math.atanh(it) } + override fun power( + arg: StructureND, + pow: Number, + ): StructureND = if (pow is Int) { + mapInline(arg.toBufferND()) { it.pow(pow) } + } else { + mapInline(arg.toBufferND()) { it.pow(pow.toDouble()) } + } + public companion object : DoubleFieldOpsND() } @@ -181,7 +191,7 @@ public class DoubleFieldND(override val shape: Shape) : it.kpow(pow) } - override fun power(arg: StructureND, pow: Number): DoubleBufferND = if(pow.isInteger()){ + override fun power(arg: StructureND, pow: Number): DoubleBufferND = if (pow.isInteger()) { power(arg, pow.toInt()) } else { val dpow = pow.toDouble() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt index 811926c23..ded8753a3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt @@ -133,6 +133,12 @@ public abstract class DoubleBufferOps : BufferAlgebra, Exte override fun scale(a: Buffer, value: Double): DoubleBuffer = a.mapInline { it * value } + override fun power(arg: Buffer, pow: Number): Buffer = if (pow is Int) { + arg.mapInline { it.pow(pow) } + } else { + arg.mapInline { it.pow(pow.toDouble()) } + } + public companion object : DoubleBufferOps() { public inline fun Buffer.mapInline(block: (Double) -> Double): DoubleBuffer = if (this is DoubleBuffer) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 16088a825..224ca1daf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -2,12 +2,13 @@ * Copyright 2018-2022 KMath contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ - +@file:Suppress("NOTHING_TO_INLINE") package space.kscience.kmath.operations import space.kscience.kmath.structures.* import kotlin.math.pow as kpow + /** * Advanced Number-like semifield that implements basic operations. */ @@ -15,7 +16,8 @@ public interface ExtendedFieldOps : FieldOps, TrigonometricOperations, ExponentialOperations, - ScaleOperations { + ScaleOperations, + PowerOperations { override fun tan(arg: T): T = sin(arg) / cos(arg) override fun tanh(arg: T): T = sinh(arg) / cosh(arg) @@ -41,7 +43,7 @@ public interface ExtendedFieldOps : /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOps, Field, PowerOperations, NumericAlgebra { +public interface ExtendedField : ExtendedFieldOps, Field, NumericAlgebra { override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) @@ -64,7 +66,7 @@ public interface ExtendedField : ExtendedFieldOps, Field, PowerOperatio /** * A field for [Double] without boxing. Does not produce appropriate field element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") public object DoubleField : ExtendedField, Norm, ScaleOperations { override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::DoubleBuffer) @@ -124,7 +126,7 @@ public val Double.Companion.algebra: DoubleField get() = DoubleField /** * A field for [Float] without boxing. Does not produce appropriate field element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") public object FloatField : ExtendedField, Norm { override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::FloatBuffer) @@ -180,7 +182,7 @@ public val Float.Companion.algebra: FloatField get() = FloatField /** * A field for [Int] without boxing. Does not produce corresponding ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") public object IntRing : Ring, Norm, NumericAlgebra { override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::IntBuffer) @@ -203,7 +205,7 @@ public val Int.Companion.algebra: IntRing get() = IntRing /** * A field for [Short] without boxing. Does not produce appropriate ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") public object ShortRing : Ring, Norm, NumericAlgebra { override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::ShortBuffer) @@ -226,7 +228,7 @@ public val Short.Companion.algebra: ShortRing get() = ShortRing /** * A field for [Byte] without boxing. Does not produce appropriate ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") public object ByteRing : Ring, Norm, NumericAlgebra { override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::ByteBuffer) @@ -249,7 +251,7 @@ public val Byte.Companion.algebra: ByteRing get() = ByteRing /** * A field for [Double] without boxing. Does not produce appropriate ring element. */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") public object LongRing : Ring, Norm, NumericAlgebra { override val bufferFactory: MutableBufferFactory = MutableBufferFactory(::LongBuffer) diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index b6a2029e7..18068eaec 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -138,6 +138,7 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun StructureND.atan(): Nd4jArrayStructure = Transforms.atan(ndArray).wrap() override fun StructureND.tanh(): Nd4jArrayStructure = Transforms.tanh(ndArray).wrap() override fun StructureND.atanh(): Nd4jArrayStructure = Transforms.atanh(ndArray).wrap() + override fun power(arg: StructureND, pow: Number): StructureND = Transforms.pow(arg.ndArray, pow).wrap() override fun StructureND.ceil(): Nd4jArrayStructure = Transforms.ceil(ndArray).wrap() override fun StructureND.floor(): Nd4jArrayStructure = Transforms.floor(ndArray).wrap() override fun StructureND.std(dim: Int, keepDim: Boolean): Nd4jArrayStructure = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index fce7d30fd..31e5b6e69 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -11,7 +11,6 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.broadcastTensors import space.kscience.kmath.tensors.core.internal.broadcastTo -import space.kscience.kmath.tensors.core.internal.tensor /** * Basic linear algebra operations implemented with broadcasting. @@ -20,7 +19,7 @@ import space.kscience.kmath.tensors.core.internal.tensor public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun StructureND.plus(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -30,15 +29,15 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } override fun Tensor.plusAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += - newOther.mutableBuffer.array()[tensor.bufferStart + i] + val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) + for (i in 0 until asDoubleTensor().indices.linearSize) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] += + newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun StructureND.minus(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -48,15 +47,15 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } override fun Tensor.minusAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - newOther.mutableBuffer.array()[tensor.bufferStart + i] + val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) + for (i in 0 until asDoubleTensor().indices.linearSize) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] -= + newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun StructureND.times(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -67,15 +66,15 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } override fun Tensor.timesAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - newOther.mutableBuffer.array()[tensor.bufferStart + i] + val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) + for (i in 0 until asDoubleTensor().indices.linearSize) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] *= + newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun StructureND.div(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> @@ -86,10 +85,10 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } override fun Tensor.divAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] /= - newOther.mutableBuffer.array()[tensor.bufferStart + i] + val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) + for (i in 0 until asDoubleTensor().indices.linearSize) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] /= + newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 94ad3f43c..096c97324 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -43,7 +43,7 @@ public open class DoubleTensorAlgebra : @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.map(transform: DoubleField.(Double) -> Double): DoubleTensor { - val tensor = this.tensor + val tensor = this.asDoubleTensor() //TODO remove additional copy val sourceArray = tensor.copyArray() val array = DoubleArray(tensor.numElements) { DoubleField.transform(sourceArray[it]) } @@ -57,7 +57,7 @@ public open class DoubleTensorAlgebra : @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor { - val tensor = this.tensor + val tensor = this.asDoubleTensor() //TODO remove additional copy val sourceArray = tensor.copyArray() val array = DoubleArray(tensor.numElements) { DoubleField.transform(tensor.indices.index(it), sourceArray[it]) } @@ -77,9 +77,9 @@ public open class DoubleTensorAlgebra : require(left.shape.contentEquals(right.shape)) { "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" } - val leftTensor = left.tensor + val leftTensor = left.asDoubleTensor() val leftArray = leftTensor.copyArray() - val rightTensor = right.tensor + val rightTensor = right.asDoubleTensor() val rightArray = rightTensor.copyArray() val array = DoubleArray(leftTensor.numElements) { DoubleField.transform(leftArray[it], rightArray[it]) } return DoubleTensor( @@ -88,8 +88,8 @@ public open class DoubleTensorAlgebra : ) } - override fun StructureND.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) - tensor.mutableBuffer.array()[tensor.bufferStart] else null + override fun StructureND.valueOrNull(): Double? = if (asDoubleTensor().shape contentEquals intArrayOf(1)) + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart] else null override fun StructureND.value(): Double = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") @@ -121,10 +121,10 @@ public open class DoubleTensorAlgebra : ) override operator fun Tensor.get(i: Int): DoubleTensor { - val lastShape = tensor.shape.drop(1).toIntArray() + val lastShape = asDoubleTensor().shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart - return DoubleTensor(newShape, tensor.mutableBuffer.array(), newStart) + val newStart = newShape.reduce(Int::times) * i + asDoubleTensor().bufferStart + return DoubleTensor(newShape, asDoubleTensor().mutableBuffer.array(), newStart) } /** @@ -147,8 +147,8 @@ public open class DoubleTensorAlgebra : * @return tensor with the `input` tensor shape and filled with [value]. */ public fun Tensor.fullLike(value: Double): DoubleTensor { - val shape = tensor.shape - val buffer = DoubleArray(tensor.numElements) { value } + val shape = asDoubleTensor().shape + val buffer = DoubleArray(asDoubleTensor().numElements) { value } return DoubleTensor(shape, buffer) } @@ -165,7 +165,7 @@ public open class DoubleTensorAlgebra : * * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. */ - public fun StructureND.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) + public fun StructureND.zeroesLike(): DoubleTensor = asDoubleTensor().fullLike(0.0) /** * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. @@ -180,7 +180,7 @@ public open class DoubleTensorAlgebra : * * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor. */ - public fun Tensor.onesLike(): DoubleTensor = tensor.fullLike(1.0) + public fun Tensor.onesLike(): DoubleTensor = asDoubleTensor().fullLike(1.0) /** * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. @@ -204,182 +204,182 @@ public open class DoubleTensorAlgebra : * @return a copy of the `input` tensor with a copied buffer. */ public fun StructureND.copy(): DoubleTensor = - DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) + DoubleTensor(asDoubleTensor().shape, asDoubleTensor().mutableBuffer.array().copyOf(), asDoubleTensor().bufferStart) override fun Double.plus(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + this + val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> + arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] + this } return DoubleTensor(arg.shape, resBuffer) } - override fun StructureND.plus(arg: Double): DoubleTensor = arg + tensor + override fun StructureND.plus(arg: Double): DoubleTensor = arg + asDoubleTensor() override fun StructureND.plus(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg.tensor) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] + arg.tensor.mutableBuffer.array()[i] + checkShapesCompatible(asDoubleTensor(), arg.asDoubleTensor()) + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[i] + arg.asDoubleTensor().mutableBuffer.array()[i] } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(asDoubleTensor().shape, resBuffer) } override fun Tensor.plusAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += value + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] += value } } override fun Tensor.plusAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg.tensor) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asDoubleTensor(), arg.asDoubleTensor()) + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] += + arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun Double.minus(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - this - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> + this - arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] } return DoubleTensor(arg.shape, resBuffer) } override fun StructureND.minus(arg: Double): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] - arg + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] - arg } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(asDoubleTensor().shape, resBuffer) } override fun StructureND.minus(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] - arg.tensor.mutableBuffer.array()[i] + checkShapesCompatible(asDoubleTensor(), arg) + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[i] - arg.asDoubleTensor().mutableBuffer.array()[i] } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(asDoubleTensor().shape, resBuffer) } override fun Tensor.minusAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] -= value } } override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asDoubleTensor(), arg) + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] -= + arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun Double.times(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] * this + val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> + arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] * this } return DoubleTensor(arg.shape, resBuffer) } - override fun StructureND.times(arg: Double): DoubleTensor = arg * tensor + override fun StructureND.times(arg: Double): DoubleTensor = arg * asDoubleTensor() override fun StructureND.times(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] * - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + checkShapesCompatible(asDoubleTensor(), arg) + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] * + arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(asDoubleTensor().shape, resBuffer) } override fun Tensor.timesAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] *= value } } override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asDoubleTensor(), arg) + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] *= + arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun Double.div(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - this / arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> + this / arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] } return DoubleTensor(arg.shape, resBuffer) } override fun StructureND.div(arg: Double): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] / arg + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] / arg } return DoubleTensor(shape, resBuffer) } override fun StructureND.div(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] / - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + checkShapesCompatible(asDoubleTensor(), arg) + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] / + arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(asDoubleTensor().shape, resBuffer) } override fun Tensor.divAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] /= value + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] /= value } } override fun Tensor.divAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] /= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asDoubleTensor(), arg) + for (i in 0 until asDoubleTensor().numElements) { + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] /= + arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] } } override fun StructureND.unaryMinus(): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() + val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i].unaryMinus() } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(asDoubleTensor().shape, resBuffer) } override fun Tensor.transpose(i: Int, j: Int): DoubleTensor { - val ii = tensor.minusIndex(i) - val jj = tensor.minusIndex(j) - checkTranspose(tensor.dimension, ii, jj) - val n = tensor.numElements + val ii = asDoubleTensor().minusIndex(i) + val jj = asDoubleTensor().minusIndex(j) + checkTranspose(asDoubleTensor().dimension, ii, jj) + val n = asDoubleTensor().numElements val resBuffer = DoubleArray(n) - val resShape = tensor.shape.copyOf() + val resShape = asDoubleTensor().shape.copyOf() resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } val resTensor = DoubleTensor(resShape, resBuffer) for (offset in 0 until n) { - val oldMultiIndex = tensor.indices.index(offset) + val oldMultiIndex = asDoubleTensor().indices.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } val linearIndex = resTensor.indices.offset(newMultiIndex) resTensor.mutableBuffer.array()[linearIndex] = - tensor.mutableBuffer.array()[tensor.bufferStart + offset] + asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + offset] } return resTensor } override fun Tensor.view(shape: IntArray): DoubleTensor { - checkView(tensor, shape) - return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) + checkView(asDoubleTensor(), shape) + return DoubleTensor(shape, asDoubleTensor().mutableBuffer.array(), asDoubleTensor().bufferStart) } override fun Tensor.viewAs(other: StructureND): DoubleTensor = - tensor.view(other.shape) + asDoubleTensor().view(other.shape) /** * Broadcasting Matrix product of two tensors. @@ -412,25 +412,25 @@ public open class DoubleTensorAlgebra : */ @UnstableKMathAPI public infix fun StructureND.matmul(other: StructureND): DoubleTensor { - if (tensor.shape.size == 1 && other.shape.size == 1) { - return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) + if (asDoubleTensor().shape.size == 1 && other.shape.size == 1) { + return DoubleTensor(intArrayOf(1), doubleArrayOf(asDoubleTensor().times(other).asDoubleTensor().mutableBuffer.array().sum())) } - var newThis = tensor.copy() + var newThis = asDoubleTensor().copy() var newOther = other.copy() var penultimateDim = false var lastDim = false - if (tensor.shape.size == 1) { + if (asDoubleTensor().shape.size == 1) { penultimateDim = true - newThis = tensor.view(intArrayOf(1) + tensor.shape) + newThis = asDoubleTensor().view(intArrayOf(1) + asDoubleTensor().shape) } if (other.shape.size == 1) { lastDim = true - newOther = other.tensor.view(other.shape + intArrayOf(1)) + newOther = other.asDoubleTensor().view(other.shape + intArrayOf(1)) } - val broadcastTensors = broadcastOuterTensors(newThis.tensor, newOther.tensor) + val broadcastTensors = broadcastOuterTensors(newThis.asDoubleTensor(), newOther.asDoubleTensor()) newThis = broadcastTensors[0] newOther = broadcastTensors[1] @@ -497,8 +497,8 @@ public open class DoubleTensorAlgebra : diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() val resTensor = zeros(resShape) - for (i in 0 until diagonalEntries.tensor.numElements) { - val multiIndex = diagonalEntries.tensor.indices.index(i) + for (i in 0 until diagonalEntries.asDoubleTensor().numElements) { + val multiIndex = diagonalEntries.asDoubleTensor().indices.index(i) var offset1 = 0 var offset2 = abs(realOffset) @@ -514,7 +514,7 @@ public open class DoubleTensorAlgebra : resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] } - return resTensor.tensor + return resTensor.asDoubleTensor() } /** @@ -525,7 +525,7 @@ public open class DoubleTensorAlgebra : * @return true if two tensors have the same shape and elements, false otherwise. */ public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean = - tensor.eq(other) { x, y -> abs(x - y) < epsilon } + asDoubleTensor().eq(other) { x, y -> abs(x - y) < epsilon } /** * Compares element-wise two tensors. @@ -534,21 +534,21 @@ public open class DoubleTensorAlgebra : * @param other the tensor to compare with `input` tensor. * @return true if two tensors have the same shape and elements, false otherwise. */ - public infix fun Tensor.eq(other: Tensor): Boolean = tensor.eq(other, 1e-5) + public infix fun Tensor.eq(other: Tensor): Boolean = asDoubleTensor().eq(other, 1e-5) private fun Tensor.eq( other: Tensor, eqFunction: (Double, Double) -> Boolean, ): Boolean { - checkShapesCompatible(tensor, other) - val n = tensor.numElements - if (n != other.tensor.numElements) { + checkShapesCompatible(asDoubleTensor(), other) + val n = asDoubleTensor().numElements + if (n != other.asDoubleTensor().numElements) { return false } for (i in 0 until n) { if (!eqFunction( - tensor.mutableBuffer[tensor.bufferStart + i], - other.tensor.mutableBuffer[other.tensor.bufferStart + i] + asDoubleTensor().mutableBuffer[asDoubleTensor().bufferStart + i], + other.asDoubleTensor().mutableBuffer[other.asDoubleTensor().bufferStart + i] ) ) { return false @@ -578,7 +578,7 @@ public open class DoubleTensorAlgebra : * with `0.0` mean and `1.0` standard deviation. */ public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = - DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) + DoubleTensor(asDoubleTensor().shape, getRandomNormals(asDoubleTensor().shape.reduce(Int::times), seed)) /** * Concatenates a sequence of tensors with equal shapes along the first dimension. @@ -592,7 +592,7 @@ public open class DoubleTensorAlgebra : check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape val resBuffer = tensors.flatMap { - it.tensor.mutableBuffer.array().drop(it.tensor.bufferStart).take(it.tensor.numElements) + it.asDoubleTensor().mutableBuffer.array().drop(it.asDoubleTensor().bufferStart).take(it.asDoubleTensor().numElements) }.toDoubleArray() return DoubleTensor(resShape, resBuffer, 0) } @@ -606,7 +606,7 @@ public open class DoubleTensorAlgebra : public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) private inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = - foldFunction(tensor.copyArray()) + foldFunction(asDoubleTensor().copyArray()) private inline fun StructureND.foldDim( dim: Int, @@ -629,44 +629,44 @@ public open class DoubleTensorAlgebra : val prefix = index.take(dim).toIntArray() val suffix = index.takeLast(dimension - dim - 1).toIntArray() resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> - tensor[prefix + intArrayOf(i) + suffix] + asDoubleTensor()[prefix + intArrayOf(i) + suffix] }) } return resTensor } - override fun StructureND.sum(): Double = tensor.fold { it.sum() } + override fun StructureND.sum(): Double = asDoubleTensor().fold { it.sum() } override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.sum() }.toDoubleTensor() + foldDim(dim, keepDim) { x -> x.sum() }.asDoubleTensor() override fun StructureND.min(): Double = this.fold { it.minOrNull()!! } override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.minOrNull()!! }.toDoubleTensor() + foldDim(dim, keepDim) { x -> x.minOrNull()!! }.asDoubleTensor() override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.toDoubleTensor() + foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.asDoubleTensor() override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = foldDim(dim, keepDim) { x -> x.withIndex().maxByOrNull { it.value }?.index!! - }.toIntTensor() + }.asIntTensor() - override fun StructureND.mean(): Double = this.fold { it.sum() / tensor.numElements } + override fun StructureND.mean(): Double = this.fold { it.sum() / asDoubleTensor().numElements } override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = foldDim(dim, keepDim) { arr -> check(dim < dimension) { "Dimension $dim out of range $dimension" } arr.sum() / shape[dim] - }.toDoubleTensor() + }.asDoubleTensor() override fun StructureND.std(): Double = fold { arr -> - val mean = arr.sum() / tensor.numElements - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) + val mean = arr.sum() / asDoubleTensor().numElements + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (asDoubleTensor().numElements - 1)) } override fun StructureND.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( @@ -676,11 +676,11 @@ public open class DoubleTensorAlgebra : check(dim < dimension) { "Dimension $dim out of range $dimension" } val mean = arr.sum() / shape[dim] sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) - }.toDoubleTensor() + }.asDoubleTensor() override fun StructureND.variance(): Double = fold { arr -> - val mean = arr.sum() / tensor.numElements - arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) + val mean = arr.sum() / asDoubleTensor().numElements + arr.sumOf { (it - mean) * (it - mean) } / (asDoubleTensor().numElements - 1) } override fun StructureND.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( @@ -690,7 +690,7 @@ public open class DoubleTensorAlgebra : check(dim < dimension) { "Dimension $dim out of range $dimension" } val mean = arr.sum() / shape[dim] arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) - }.toDoubleTensor() + }.asDoubleTensor() private fun cov(x: DoubleTensor, y: DoubleTensor): Double { val n = x.shape[0] @@ -716,45 +716,51 @@ public open class DoubleTensorAlgebra : ) for (i in 0 until n) { for (j in 0 until n) { - resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor) + resTensor[intArrayOf(i, j)] = cov(tensors[i].asDoubleTensor(), tensors[j].asDoubleTensor()) } } return resTensor } - override fun StructureND.exp(): DoubleTensor = tensor.map { exp(it) } + override fun StructureND.exp(): DoubleTensor = asDoubleTensor().map { exp(it) } - override fun StructureND.ln(): DoubleTensor = tensor.map { ln(it) } + override fun StructureND.ln(): DoubleTensor = asDoubleTensor().map { ln(it) } - override fun StructureND.sqrt(): DoubleTensor = tensor.map { sqrt(it) } + override fun StructureND.sqrt(): DoubleTensor = asDoubleTensor().map { sqrt(it) } - override fun StructureND.cos(): DoubleTensor = tensor.map { cos(it) } + override fun StructureND.cos(): DoubleTensor = asDoubleTensor().map { cos(it) } - override fun StructureND.acos(): DoubleTensor = tensor.map { acos(it) } + override fun StructureND.acos(): DoubleTensor = asDoubleTensor().map { acos(it) } - override fun StructureND.cosh(): DoubleTensor = tensor.map { cosh(it) } + override fun StructureND.cosh(): DoubleTensor = asDoubleTensor().map { cosh(it) } - override fun StructureND.acosh(): DoubleTensor = tensor.map { acosh(it) } + override fun StructureND.acosh(): DoubleTensor = asDoubleTensor().map { acosh(it) } - override fun StructureND.sin(): DoubleTensor = tensor.map { sin(it) } + override fun StructureND.sin(): DoubleTensor = asDoubleTensor().map { sin(it) } - override fun StructureND.asin(): DoubleTensor = tensor.map { asin(it) } + override fun StructureND.asin(): DoubleTensor = asDoubleTensor().map { asin(it) } - override fun StructureND.sinh(): DoubleTensor = tensor.map { sinh(it) } + override fun StructureND.sinh(): DoubleTensor = asDoubleTensor().map { sinh(it) } - override fun StructureND.asinh(): DoubleTensor = tensor.map { asinh(it) } + override fun StructureND.asinh(): DoubleTensor = asDoubleTensor().map { asinh(it) } - override fun StructureND.tan(): DoubleTensor = tensor.map { tan(it) } + override fun StructureND.tan(): DoubleTensor = asDoubleTensor().map { tan(it) } - override fun StructureND.atan(): DoubleTensor = tensor.map { atan(it) } + override fun StructureND.atan(): DoubleTensor = asDoubleTensor().map { atan(it) } - override fun StructureND.tanh(): DoubleTensor = tensor.map { tanh(it) } + override fun StructureND.tanh(): DoubleTensor = asDoubleTensor().map { tanh(it) } - override fun StructureND.atanh(): DoubleTensor = tensor.map { atanh(it) } + override fun StructureND.atanh(): DoubleTensor = asDoubleTensor().map { atanh(it) } - override fun StructureND.ceil(): DoubleTensor = tensor.map { ceil(it) } + override fun power(arg: StructureND, pow: Number): StructureND = if (pow is Int) { + arg.map { it.pow(pow) } + } else { + arg.map { it.pow(pow.toDouble()) } + } - override fun StructureND.floor(): DoubleTensor = tensor.map { floor(it) } + override fun StructureND.ceil(): DoubleTensor = asDoubleTensor().map { ceil(it) } + + override fun StructureND.floor(): DoubleTensor = asDoubleTensor().map { floor(it) } override fun StructureND.inv(): DoubleTensor = invLU(1e-9) @@ -770,7 +776,7 @@ public open class DoubleTensorAlgebra : * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. */ public fun StructureND.luFactor(epsilon: Double): Pair = - computeLU(tensor, epsilon) + computeLU(asDoubleTensor(), epsilon) ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") /** @@ -809,7 +815,7 @@ public open class DoubleTensorAlgebra : val pTensor = luTensor.zeroesLike() pTensor .matrixSequence() - .zip(pivotsTensor.tensor.vectorSequence()) + .zip(pivotsTensor.asIntTensor().vectorSequence()) .forEach { (p, pivot) -> pivInit(p.as2D(), pivot.as1D(), n) } val lTensor = luTensor.zeroesLike() @@ -817,7 +823,7 @@ public open class DoubleTensorAlgebra : lTensor.matrixSequence() .zip(uTensor.matrixSequence()) - .zip(luTensor.tensor.matrixSequence()) + .zip(luTensor.asDoubleTensor().matrixSequence()) .forEach { (pairLU, lu) -> val (l, u) = pairLU luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) @@ -841,12 +847,12 @@ public open class DoubleTensorAlgebra : */ public fun StructureND.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) - checkPositiveDefinite(tensor, epsilon) + checkPositiveDefinite(asDoubleTensor(), epsilon) val n = shape.last() val lTensor = zeroesLike() - for ((a, l) in tensor.matrixSequence().zip(lTensor.matrixSequence())) + for ((a, l) in asDoubleTensor().matrixSequence().zip(lTensor.matrixSequence())) for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) return lTensor @@ -858,13 +864,13 @@ public open class DoubleTensorAlgebra : checkSquareMatrix(shape) val qTensor = zeroesLike() val rTensor = zeroesLike() - tensor.matrixSequence() + asDoubleTensor().matrixSequence() .zip( (qTensor.matrixSequence() .zip(rTensor.matrixSequence())) ).forEach { (matrix, qr) -> val (q, r) = qr - qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) + qrHelper(matrix.toTensor(), q.toTensor(), r.as2D()) } return qTensor to rTensor @@ -887,14 +893,14 @@ public open class DoubleTensorAlgebra : * @return a triple `Triple(U, S, V)`. */ public fun StructureND.svd(epsilon: Double): Triple { - val size = tensor.dimension - val commonShape = tensor.shape.sliceArray(0 until size - 2) - val (n, m) = tensor.shape.sliceArray(size - 2 until size) + val size = asDoubleTensor().dimension + val commonShape = asDoubleTensor().shape.sliceArray(0 until size - 2) + val (n, m) = asDoubleTensor().shape.sliceArray(size - 2 until size) val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) val sTensor = zeros(commonShape + intArrayOf(min(n, m))) val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - val matrices = tensor.matrices + val matrices = asDoubleTensor().matrices val uTensors = uTensor.matrices val sTensorVectors = sTensor.vectors val vTensors = vTensor.matrices @@ -931,7 +937,7 @@ public open class DoubleTensorAlgebra : * @return a pair `eigenvalues to eigenvectors`. */ public fun StructureND.symEigSvd(epsilon: Double): Pair { - checkSymmetric(tensor, epsilon) + checkSymmetric(asDoubleTensor(), epsilon) fun MutableStructure2D.cleanSym(n: Int) { for (i in 0 until n) { @@ -945,7 +951,7 @@ public open class DoubleTensorAlgebra : } } - val (u, s, v) = tensor.svd(epsilon) + val (u, s, v) = asDoubleTensor().svd(epsilon) val shp = s.shape + intArrayOf(1) val utv = u.transpose() matmul v val n = s.shape.last() @@ -958,7 +964,7 @@ public open class DoubleTensorAlgebra : } public fun StructureND.symEigJacobi(maxIteration: Int, epsilon: Double): Pair { - checkSymmetric(tensor, epsilon) + checkSymmetric(asDoubleTensor(), epsilon) val size = this.dimension val eigenvectors = zeros(this.shape) @@ -966,7 +972,7 @@ public open class DoubleTensorAlgebra : var eigenvalueStart = 0 var eigenvectorStart = 0 - for (matrix in tensor.matrixSequence()) { + for (matrix in asDoubleTensor().matrixSequence()) { val matrix2D = matrix.as2D() val (d, v) = matrix2D.jacobiHelper(maxIteration, epsilon) @@ -1111,9 +1117,9 @@ public open class DoubleTensorAlgebra : * @return the determinant. */ public fun StructureND.detLU(epsilon: Double = 1e-9): DoubleTensor { - checkSquareMatrix(tensor.shape) - val luTensor = tensor.copy() - val pivotsTensor = tensor.setUpPivots() + checkSquareMatrix(asDoubleTensor().shape) + val luTensor = asDoubleTensor().copy() + val pivotsTensor = asDoubleTensor().setUpPivots() val n = shape.size @@ -1169,14 +1175,14 @@ public open class DoubleTensorAlgebra : * @return triple of `P`, `L` and `U` tensors. */ public fun StructureND.lu(epsilon: Double = 1e-9): Triple { - val (lu, pivots) = tensor.luFactor(epsilon) + val (lu, pivots) = asDoubleTensor().luFactor(epsilon) return luPivot(lu, pivots) } override fun StructureND.lu(): Triple = lu(1e-9) } -public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra -public val DoubleField.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra +public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra +public val DoubleField.tensorAlgebra: DoubleTensorAlgebra get() = DoubleTensorAlgebra diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt index 0c8ddcf87..194f2bd18 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt @@ -39,7 +39,7 @@ public open class IntTensorAlgebra : TensorAlgebra { @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.map(transform: IntRing.(Int) -> Int): IntTensor { - val tensor = this.tensor + val tensor = this.asIntTensor() //TODO remove additional copy val sourceArray = tensor.copyArray() val array = IntArray(tensor.numElements) { IntRing.transform(sourceArray[it]) } @@ -53,7 +53,7 @@ public open class IntTensorAlgebra : TensorAlgebra { @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.mapIndexed(transform: IntRing.(index: IntArray, Int) -> Int): IntTensor { - val tensor = this.tensor + val tensor = this.asIntTensor() //TODO remove additional copy val sourceArray = tensor.copyArray() val array = IntArray(tensor.numElements) { IntRing.transform(tensor.indices.index(it), sourceArray[it]) } @@ -73,9 +73,9 @@ public open class IntTensorAlgebra : TensorAlgebra { require(left.shape.contentEquals(right.shape)) { "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" } - val leftTensor = left.tensor + val leftTensor = left.asIntTensor() val leftArray = leftTensor.copyArray() - val rightTensor = right.tensor + val rightTensor = right.asIntTensor() val rightArray = rightTensor.copyArray() val array = IntArray(leftTensor.numElements) { IntRing.transform(leftArray[it], rightArray[it]) } return IntTensor( @@ -84,8 +84,8 @@ public open class IntTensorAlgebra : TensorAlgebra { ) } - override fun StructureND.valueOrNull(): Int? = if (tensor.shape contentEquals intArrayOf(1)) - tensor.mutableBuffer.array()[tensor.bufferStart] else null + override fun StructureND.valueOrNull(): Int? = if (asIntTensor().shape contentEquals intArrayOf(1)) + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart] else null override fun StructureND.value(): Int = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") @@ -119,10 +119,10 @@ public open class IntTensorAlgebra : TensorAlgebra { ) override operator fun Tensor.get(i: Int): IntTensor { - val lastShape = tensor.shape.drop(1).toIntArray() + val lastShape = asIntTensor().shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart - return IntTensor(newShape, tensor.mutableBuffer.array(), newStart) + val newStart = newShape.reduce(Int::times) * i + asIntTensor().bufferStart + return IntTensor(newShape, asIntTensor().mutableBuffer.array(), newStart) } /** @@ -145,8 +145,8 @@ public open class IntTensorAlgebra : TensorAlgebra { * @return tensor with the `input` tensor shape and filled with [value]. */ public fun Tensor.fullLike(value: Int): IntTensor { - val shape = tensor.shape - val buffer = IntArray(tensor.numElements) { value } + val shape = asIntTensor().shape + val buffer = IntArray(asIntTensor().numElements) { value } return IntTensor(shape, buffer) } @@ -163,7 +163,7 @@ public open class IntTensorAlgebra : TensorAlgebra { * * @return tensor filled with the scalar value `0`, with the same shape as `input` tensor. */ - public fun StructureND.zeroesLike(): IntTensor = tensor.fullLike(0) + public fun StructureND.zeroesLike(): IntTensor = asIntTensor().fullLike(0) /** * Returns a tensor filled with the scalar value `1`, with the shape defined by the variable argument [shape]. @@ -178,7 +178,7 @@ public open class IntTensorAlgebra : TensorAlgebra { * * @return tensor filled with the scalar value `1`, with the same shape as `input` tensor. */ - public fun Tensor.onesLike(): IntTensor = tensor.fullLike(1) + public fun Tensor.onesLike(): IntTensor = asIntTensor().fullLike(1) /** * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. @@ -202,145 +202,145 @@ public open class IntTensorAlgebra : TensorAlgebra { * @return a copy of the `input` tensor with a copied buffer. */ public fun StructureND.copy(): IntTensor = - IntTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) + IntTensor(asIntTensor().shape, asIntTensor().mutableBuffer.array().copyOf(), asIntTensor().bufferStart) override fun Int.plus(arg: StructureND): IntTensor { - val resBuffer = IntArray(arg.tensor.numElements) { i -> - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + this + val resBuffer = IntArray(arg.asIntTensor().numElements) { i -> + arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] + this } return IntTensor(arg.shape, resBuffer) } - override fun StructureND.plus(arg: Int): IntTensor = arg + tensor + override fun StructureND.plus(arg: Int): IntTensor = arg + asIntTensor() override fun StructureND.plus(arg: StructureND): IntTensor { - checkShapesCompatible(tensor, arg.tensor) - val resBuffer = IntArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] + arg.tensor.mutableBuffer.array()[i] + checkShapesCompatible(asIntTensor(), arg.asIntTensor()) + val resBuffer = IntArray(asIntTensor().numElements) { i -> + asIntTensor().mutableBuffer.array()[i] + arg.asIntTensor().mutableBuffer.array()[i] } - return IntTensor(tensor.shape, resBuffer) + return IntTensor(asIntTensor().shape, resBuffer) } override fun Tensor.plusAssign(value: Int) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += value + for (i in 0 until asIntTensor().numElements) { + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] += value } } override fun Tensor.plusAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg.tensor) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asIntTensor(), arg.asIntTensor()) + for (i in 0 until asIntTensor().numElements) { + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] += + arg.asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] } } override fun Int.minus(arg: StructureND): IntTensor { - val resBuffer = IntArray(arg.tensor.numElements) { i -> - this - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + val resBuffer = IntArray(arg.asIntTensor().numElements) { i -> + this - arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] } return IntTensor(arg.shape, resBuffer) } override fun StructureND.minus(arg: Int): IntTensor { - val resBuffer = IntArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] - arg + val resBuffer = IntArray(asIntTensor().numElements) { i -> + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] - arg } - return IntTensor(tensor.shape, resBuffer) + return IntTensor(asIntTensor().shape, resBuffer) } override fun StructureND.minus(arg: StructureND): IntTensor { - checkShapesCompatible(tensor, arg) - val resBuffer = IntArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] - arg.tensor.mutableBuffer.array()[i] + checkShapesCompatible(asIntTensor(), arg) + val resBuffer = IntArray(asIntTensor().numElements) { i -> + asIntTensor().mutableBuffer.array()[i] - arg.asIntTensor().mutableBuffer.array()[i] } - return IntTensor(tensor.shape, resBuffer) + return IntTensor(asIntTensor().shape, resBuffer) } override fun Tensor.minusAssign(value: Int) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value + for (i in 0 until asIntTensor().numElements) { + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] -= value } } override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asIntTensor(), arg) + for (i in 0 until asIntTensor().numElements) { + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] -= + arg.asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] } } override fun Int.times(arg: StructureND): IntTensor { - val resBuffer = IntArray(arg.tensor.numElements) { i -> - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] * this + val resBuffer = IntArray(arg.asIntTensor().numElements) { i -> + arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] * this } return IntTensor(arg.shape, resBuffer) } - override fun StructureND.times(arg: Int): IntTensor = arg * tensor + override fun StructureND.times(arg: Int): IntTensor = arg * asIntTensor() override fun StructureND.times(arg: StructureND): IntTensor { - checkShapesCompatible(tensor, arg) - val resBuffer = IntArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] * - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + checkShapesCompatible(asIntTensor(), arg) + val resBuffer = IntArray(asIntTensor().numElements) { i -> + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] * + arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] } - return IntTensor(tensor.shape, resBuffer) + return IntTensor(asIntTensor().shape, resBuffer) } override fun Tensor.timesAssign(value: Int) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value + for (i in 0 until asIntTensor().numElements) { + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] *= value } } override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + checkShapesCompatible(asIntTensor(), arg) + for (i in 0 until asIntTensor().numElements) { + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] *= + arg.asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] } } override fun StructureND.unaryMinus(): IntTensor { - val resBuffer = IntArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() + val resBuffer = IntArray(asIntTensor().numElements) { i -> + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i].unaryMinus() } - return IntTensor(tensor.shape, resBuffer) + return IntTensor(asIntTensor().shape, resBuffer) } override fun Tensor.transpose(i: Int, j: Int): IntTensor { - val ii = tensor.minusIndex(i) - val jj = tensor.minusIndex(j) - checkTranspose(tensor.dimension, ii, jj) - val n = tensor.numElements + val ii = asIntTensor().minusIndex(i) + val jj = asIntTensor().minusIndex(j) + checkTranspose(asIntTensor().dimension, ii, jj) + val n = asIntTensor().numElements val resBuffer = IntArray(n) - val resShape = tensor.shape.copyOf() + val resShape = asIntTensor().shape.copyOf() resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } val resTensor = IntTensor(resShape, resBuffer) for (offset in 0 until n) { - val oldMultiIndex = tensor.indices.index(offset) + val oldMultiIndex = asIntTensor().indices.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } val linearIndex = resTensor.indices.offset(newMultiIndex) resTensor.mutableBuffer.array()[linearIndex] = - tensor.mutableBuffer.array()[tensor.bufferStart + offset] + asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + offset] } return resTensor } override fun Tensor.view(shape: IntArray): IntTensor { - checkView(tensor, shape) - return IntTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) + checkView(asIntTensor(), shape) + return IntTensor(shape, asIntTensor().mutableBuffer.array(), asIntTensor().bufferStart) } override fun Tensor.viewAs(other: StructureND): IntTensor = - tensor.view(other.shape) + asIntTensor().view(other.shape) override fun diagonalEmbedding( diagonalEntries: Tensor, @@ -374,8 +374,8 @@ public open class IntTensorAlgebra : TensorAlgebra { diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() val resTensor = zeros(resShape) - for (i in 0 until diagonalEntries.tensor.numElements) { - val multiIndex = diagonalEntries.tensor.indices.index(i) + for (i in 0 until diagonalEntries.asIntTensor().numElements) { + val multiIndex = diagonalEntries.asIntTensor().indices.index(i) var offset1 = 0 var offset2 = abs(realOffset) @@ -391,19 +391,19 @@ public open class IntTensorAlgebra : TensorAlgebra { resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] } - return resTensor.tensor + return resTensor.asIntTensor() } private infix fun Tensor.eq( other: Tensor, ): Boolean { - checkShapesCompatible(tensor, other) - val n = tensor.numElements - if (n != other.tensor.numElements) { + checkShapesCompatible(asIntTensor(), other) + val n = asIntTensor().numElements + if (n != other.asIntTensor().numElements) { return false } for (i in 0 until n) { - if (tensor.mutableBuffer[tensor.bufferStart + i] != other.tensor.mutableBuffer[other.tensor.bufferStart + i]) { + if (asIntTensor().mutableBuffer[asIntTensor().bufferStart + i] != other.asIntTensor().mutableBuffer[other.asIntTensor().bufferStart + i]) { return false } } @@ -422,7 +422,7 @@ public open class IntTensorAlgebra : TensorAlgebra { check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape val resBuffer = tensors.flatMap { - it.tensor.mutableBuffer.array().drop(it.tensor.bufferStart).take(it.tensor.numElements) + it.asIntTensor().mutableBuffer.array().drop(it.asIntTensor().bufferStart).take(it.asIntTensor().numElements) }.toIntArray() return IntTensor(resShape, resBuffer, 0) } @@ -436,7 +436,7 @@ public open class IntTensorAlgebra : TensorAlgebra { public fun Tensor.rowsByIndices(indices: IntArray): IntTensor = stack(indices.map { this[it] }) private inline fun StructureND.fold(foldFunction: (IntArray) -> Int): Int = - foldFunction(tensor.copyArray()) + foldFunction(asIntTensor().copyArray()) private inline fun StructureND.foldDim( dim: Int, @@ -459,35 +459,35 @@ public open class IntTensorAlgebra : TensorAlgebra { val prefix = index.take(dim).toIntArray() val suffix = index.takeLast(dimension - dim - 1).toIntArray() resTensor[index] = foldFunction(IntArray(shape[dim]) { i -> - tensor[prefix + intArrayOf(i) + suffix] + asIntTensor()[prefix + intArrayOf(i) + suffix] }) } return resTensor } - override fun StructureND.sum(): Int = tensor.fold { it.sum() } + override fun StructureND.sum(): Int = asIntTensor().fold { it.sum() } override fun StructureND.sum(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> x.sum() }.toIntTensor() + foldDim(dim, keepDim) { x -> x.sum() }.asIntTensor() override fun StructureND.min(): Int = this.fold { it.minOrNull()!! } override fun StructureND.min(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> x.minOrNull()!! }.toIntTensor() + foldDim(dim, keepDim) { x -> x.minOrNull()!! }.asIntTensor() override fun StructureND.max(): Int = this.fold { it.maxOrNull()!! } override fun StructureND.max(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.toIntTensor() + foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.asIntTensor() override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = foldDim(dim, keepDim) { x -> x.withIndex().maxByOrNull { it.value }?.index!! - }.toIntTensor() + }.asIntTensor() } -public val Int.Companion.tensorAlgebra: IntTensorAlgebra.Companion get() = IntTensorAlgebra -public val IntRing.tensorAlgebra: IntTensorAlgebra.Companion get() = IntTensorAlgebra +public val Int.Companion.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra +public val IntRing.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index e997dfcca..62cc85396 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -58,7 +58,7 @@ internal fun DoubleTensorAlgebra.checkSymmetric( internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { checkSymmetric(tensor, epsilon) for (mat in tensor.matrixSequence()) - check(mat.asTensor().detLU().value() > 0.0) { - "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" + check(mat.toTensor().detLU().value() > 0.0) { + "Tensor contains matrices which are not positive definite ${mat.toTensor().detLU().value()}" } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index c19b8bf95..e7704b257 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -13,16 +13,17 @@ import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.IntTensor import space.kscience.kmath.tensors.core.TensorLinearStructure -internal fun BufferedTensor.asTensor(): IntTensor = +internal fun BufferedTensor.toTensor(): IntTensor = IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) -internal fun BufferedTensor.asTensor(): DoubleTensor = +internal fun BufferedTensor.toTensor(): DoubleTensor = DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) internal fun StructureND.copyToBufferedTensor(): BufferedTensor = BufferedTensor( this.shape, - TensorLinearStructure(this.shape).asSequence().map(this::get).toMutableList().asMutableBuffer(), 0 + TensorLinearStructure(this.shape).asSequence().map(this::get).toMutableList().asMutableBuffer(), + 0 ) internal fun StructureND.toBufferedTensor(): BufferedTensor = when (this) { @@ -34,17 +35,3 @@ internal fun StructureND.toBufferedTensor(): BufferedTensor = when (th } else -> this.copyToBufferedTensor() } - -@PublishedApi -internal val StructureND.tensor: DoubleTensor - get() = when (this) { - is DoubleTensor -> this - else -> this.toBufferedTensor().asTensor() - } - -@PublishedApi -internal val StructureND.tensor: IntTensor - get() = when (this) { - is IntTensor -> this - else -> this.toBufferedTensor().asTensor() - } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 968efa468..1c914d474 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -5,18 +5,26 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.StructureND import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.tensor +import space.kscience.kmath.tensors.core.internal.toBufferedTensor +import space.kscience.kmath.tensors.core.internal.toTensor /** * Casts [Tensor] of [Double] to [DoubleTensor] */ -public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor +public fun StructureND.asDoubleTensor(): DoubleTensor = when (this) { + is DoubleTensor -> this + else -> this.toBufferedTensor().toTensor() +} /** * Casts [Tensor] of [Int] to [IntTensor] */ -public fun Tensor.toIntTensor(): IntTensor = this.tensor +public fun StructureND.asIntTensor(): IntTensor = when (this) { + is IntTensor -> this + else -> this.toBufferedTensor().toTensor() +} /** * Returns a copy-protected [DoubleArray] of tensor elements diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 5e5ef95be..61248cbb8 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -14,9 +14,9 @@ import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.toDoubleArray import space.kscience.kmath.tensors.core.internal.array -import space.kscience.kmath.tensors.core.internal.asTensor import space.kscience.kmath.tensors.core.internal.matrixSequence import space.kscience.kmath.tensors.core.internal.toBufferedTensor +import space.kscience.kmath.tensors.core.internal.toTensor import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -56,7 +56,7 @@ internal class TestDoubleTensor { assertEquals(tensor[intArrayOf(0, 1, 0)], 109.56) tensor.matrixSequence().forEach { - val a = it.asTensor() + val a = it.toTensor() val secondRow = a[1].as1D() val secondColumn = a.transpose(0, 1)[1].as1D() assertEquals(secondColumn[0], 77.89) @@ -75,10 +75,10 @@ internal class TestDoubleTensor { // map to tensors val bufferedTensorArray = ndArray.toBufferedTensor() // strides are flipped so data copied - val tensorArray = bufferedTensorArray.asTensor() // data not contiguous so copied again + val tensorArray = bufferedTensorArray.toTensor() // data not contiguous so copied again - val tensorArrayPublic = ndArray.toDoubleTensor() // public API, data copied twice - val sharedTensorArray = tensorArrayPublic.toDoubleTensor() // no data copied by matching type + val tensorArrayPublic = ndArray.asDoubleTensor() // public API, data copied twice + val sharedTensorArray = tensorArrayPublic.asDoubleTensor() // no data copied by matching type assertTrue(tensorArray.mutableBuffer.array() contentEquals sharedTensorArray.mutableBuffer.array()) From 3729faf49bfde2c4158d2ac446f93a37a1057daa Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 5 Sep 2022 23:24:01 +0300 Subject: [PATCH 171/174] Rename Tensor::get to Tensor::getTensor to avoid name clash. --- .../space/kscience/kmath/tensors/PCA.kt | 6 ++--- .../tensors/linearSystemSolvingWithLUP.kt | 2 +- .../kscience/kmath/tensors/neuralNetwork.kt | 2 +- .../space/kscience/kmath/misc/cumulative.kt | 18 +++++++++++---- .../kmath/multik/MultikTensorAlgebra.kt | 8 ++++++- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 5 +++- .../kmath/tensorflow/TensorFlowAlgebra.kt | 7 +++++- .../kmath/tensors/api/TensorAlgebra.kt | 21 +++++++++++++++-- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 23 +++++++++++++++---- .../kmath/tensors/core/IntTensorAlgebra.kt | 9 ++++++-- .../kmath/tensors/core/internal/linUtils.kt | 8 +++---- .../kmath/tensors/core/TestDoubleTensor.kt | 11 +++++---- 12 files changed, 90 insertions(+), 30 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index c4d0ed93e..e5d1ef9f8 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -58,7 +58,7 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with // and find out eigenvector of it val (_, evecs) = covMatrix.symEig() - val v = evecs[0] + val v = evecs.getTensor(0) println("Eigenvector:\n$v") // reduce dimension of dataset @@ -68,7 +68,7 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with // we can restore original data from reduced data; // for example, find 7th element of dataset. val n = 7 - val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean - println("Original value:\n${dataset[n]}") + val restored = (datasetReduced.getTensor(n) dot v.view(intArrayOf(1, 2))) * std + mean + println("Original value:\n${dataset.getTensor(n)}") println("Restored value:\n$restored") } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt index a08fe4106..bafdf9b21 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt @@ -66,7 +66,7 @@ fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear val n = l.shape[0] val x = zeros(intArrayOf(n)) for (i in 0 until n) { - x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).value()) / l[intArrayOf(i, i)] + x[intArrayOf(i)] = (b[intArrayOf(i)] - l.getTensor(i).dot(x).value()) / l[intArrayOf(i, i)] } return x } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt index 502f6d53f..7289d86c4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt @@ -197,7 +197,7 @@ fun main() = BroadcastDoubleTensorAlgebra { val y = fromArray( intArrayOf(sampleSize, 1), DoubleArray(sampleSize) { i -> - if (x[i].sum() > 0.0) { + if (x.getTensor(i).sum() > 0.0) { 1.0 } else { 0.0 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt index 6ccb487c3..c05f1a6a9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.misc import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer import kotlin.jvm.JvmName /** @@ -42,8 +43,8 @@ public inline fun List.cumulative(initial: R, crossinline operation: ( /** * Cumulative sum with custom space */ -public fun Iterable.cumulativeSum(group: Ring): Iterable = - group { cumulative(zero) { element: T, sum: T -> sum + element } } +public fun Iterable.cumulativeSum(ring: Ring): Iterable = + ring { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") public fun Iterable.cumulativeSum(): Iterable = cumulative(0.0) { element, sum -> sum + element } @@ -54,8 +55,8 @@ public fun Iterable.cumulativeSum(): Iterable = cumulative(0) { elemen @JvmName("cumulativeSumOfLong") public fun Iterable.cumulativeSum(): Iterable = cumulative(0L) { element, sum -> sum + element } -public fun Sequence.cumulativeSum(group: Ring): Sequence = - group { cumulative(zero) { element: T, sum: T -> sum + element } } +public fun Sequence.cumulativeSum(ring: Ring): Sequence = + ring { cumulative(zero) { element: T, sum: T -> sum + element } } @JvmName("cumulativeSumOfDouble") public fun Sequence.cumulativeSum(): Sequence = cumulative(0.0) { element, sum -> sum + element } @@ -77,3 +78,12 @@ public fun List.cumulativeSum(): List = cumulative(0) { element, sum - @JvmName("cumulativeSumOfLong") public fun List.cumulativeSum(): List = cumulative(0L) { element, sum -> sum + element } + + +public fun Buffer.cumulativeSum(ring: Ring): Buffer = with(ring) { + var accumulator: T = zero + return bufferFactory(size) { + accumulator += get(it) + accumulator + } +} diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index c6266c985..e32221dbf 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -185,7 +185,7 @@ public abstract class MultikTensorAlgebra>( override fun StructureND.unaryMinus(): MultikTensor = asMultik().array.unaryMinus().wrap() - override fun Tensor.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() + override fun Tensor.getTensor(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() override fun Tensor.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() @@ -246,6 +246,12 @@ public abstract class MultikTensorAlgebra>( return multikMath.minDN(asMultik().array, dim).wrap() } + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor { + if (keepDim) TODO("keepDim not implemented") + val res = multikMath.argMinDN(asMultik().array, dim) + return with(MultikIntAlgebra(multikEngine)) { res.wrap() } + } + override fun StructureND.max(): T? = asMultik().array.max() override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index 18068eaec..efd3ded70 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -95,7 +95,7 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe } override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() - override fun Tensor.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() + override fun Tensor.getTensor(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() override fun Tensor.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() override fun StructureND.dot(other: StructureND): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() @@ -111,6 +111,9 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun Tensor.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() override fun Tensor.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = + ndBase.get().argmin(ndArray, keepDim, dim).asIntStructure() + override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = ndBase.get().argmax(ndArray, keepDim, dim).asIntStructure() diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index c6eaa7266..346750f88 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -184,7 +184,7 @@ public abstract class TensorFlowAlgebra> internal c override fun StructureND.unaryMinus(): TensorFlowOutput = operate(ops.math::neg) - override fun Tensor.get(i: Int): Tensor = operate { + override fun Tensor.getTensor(i: Int): Tensor = operate { StridedSliceHelper.stridedSlice(ops.scope(), it, Indices.at(i.toLong())) } @@ -238,6 +238,11 @@ public abstract class TensorFlowAlgebra> internal c ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) } + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = IntTensorFlowOutput( + graph, + ops.math.argMin(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() + ).actualTensor + override fun StructureND.max(): T = operate { ops.max(it, ops.constant(intArrayOf())) }.value() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index dbc42f7c7..7615af2ea 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -166,7 +166,11 @@ public interface TensorAlgebra> : RingOpsND { * @param i index of the extractable tensor * @return subtensor of the original tensor with index [i] */ - public operator fun Tensor.get(i: Int): Tensor + public fun Tensor.getTensor(i: Int): Tensor + + public fun Tensor.getTensor(first: Int, second: Int): Tensor { + return getTensor(first).getTensor(second) + } /** * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. @@ -286,6 +290,19 @@ public interface TensorAlgebra> : RingOpsND { */ public fun StructureND.min(dim: Int, keepDim: Boolean): Tensor + /** + * Returns the index of minimum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. + */ + public fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor + /** * Returns the maximum value of all elements in the input tensor or null if there are no values */ @@ -320,4 +337,4 @@ public interface TensorAlgebra> : RingOpsND { override fun add(left: StructureND, right: StructureND): Tensor = left + right override fun multiply(left: StructureND, right: StructureND): Tensor = left * right -} +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 096c97324..8acb15251 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -24,6 +24,7 @@ import kotlin.math.* /** * Implementation of basic operations over double tensors and basic algebra operations on them. */ +@OptIn(PerformancePitfall::class) public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, AnalyticTensorAlgebra, @@ -120,7 +121,7 @@ public open class DoubleTensorAlgebra : TensorLinearStructure(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() ) - override operator fun Tensor.get(i: Int): DoubleTensor { + override fun Tensor.getTensor(i: Int): DoubleTensor { val lastShape = asDoubleTensor().shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) val newStart = newShape.reduce(Int::times) * i + asDoubleTensor().bufferStart @@ -204,7 +205,11 @@ public open class DoubleTensorAlgebra : * @return a copy of the `input` tensor with a copied buffer. */ public fun StructureND.copy(): DoubleTensor = - DoubleTensor(asDoubleTensor().shape, asDoubleTensor().mutableBuffer.array().copyOf(), asDoubleTensor().bufferStart) + DoubleTensor( + asDoubleTensor().shape, + asDoubleTensor().mutableBuffer.array().copyOf(), + asDoubleTensor().bufferStart + ) override fun Double.plus(arg: StructureND): DoubleTensor { val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> @@ -413,7 +418,10 @@ public open class DoubleTensorAlgebra : @UnstableKMathAPI public infix fun StructureND.matmul(other: StructureND): DoubleTensor { if (asDoubleTensor().shape.size == 1 && other.shape.size == 1) { - return DoubleTensor(intArrayOf(1), doubleArrayOf(asDoubleTensor().times(other).asDoubleTensor().mutableBuffer.array().sum())) + return DoubleTensor( + intArrayOf(1), + doubleArrayOf(asDoubleTensor().times(other).asDoubleTensor().mutableBuffer.array().sum()) + ) } var newThis = asDoubleTensor().copy() @@ -592,7 +600,8 @@ public open class DoubleTensorAlgebra : check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape val resBuffer = tensors.flatMap { - it.asDoubleTensor().mutableBuffer.array().drop(it.asDoubleTensor().bufferStart).take(it.asDoubleTensor().numElements) + it.asDoubleTensor().mutableBuffer.array().drop(it.asDoubleTensor().bufferStart) + .take(it.asDoubleTensor().numElements) }.toDoubleArray() return DoubleTensor(resShape, resBuffer, 0) } @@ -603,7 +612,7 @@ public open class DoubleTensorAlgebra : * @param indices the [IntArray] of 1-dimensional indices * @return tensor with rows corresponding to row by [indices] */ - public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) + public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { getTensor(it) }) private inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = foldFunction(asDoubleTensor().copyArray()) @@ -645,6 +654,10 @@ public open class DoubleTensorAlgebra : override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = foldDim(dim, keepDim) { x -> x.minOrNull()!! }.asDoubleTensor() + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDim(dim, keepDim) { x -> + x.withIndex().minByOrNull { it.value }?.index!! + }.asIntTensor() + override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt index 194f2bd18..3ddbd3301 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt @@ -118,7 +118,7 @@ public open class IntTensorAlgebra : TensorAlgebra { TensorLinearStructure(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray() ) - override operator fun Tensor.get(i: Int): IntTensor { + override fun Tensor.getTensor(i: Int): IntTensor { val lastShape = asIntTensor().shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) val newStart = newShape.reduce(Int::times) * i + asIntTensor().bufferStart @@ -433,7 +433,7 @@ public open class IntTensorAlgebra : TensorAlgebra { * @param indices the [IntArray] of 1-dimensional indices * @return tensor with rows corresponding to row by [indices] */ - public fun Tensor.rowsByIndices(indices: IntArray): IntTensor = stack(indices.map { this[it] }) + public fun Tensor.rowsByIndices(indices: IntArray): IntTensor = stack(indices.map { getTensor(it) }) private inline fun StructureND.fold(foldFunction: (IntArray) -> Int): Int = foldFunction(asIntTensor().copyArray()) @@ -475,6 +475,11 @@ public open class IntTensorAlgebra : TensorAlgebra { override fun StructureND.min(dim: Int, keepDim: Boolean): IntTensor = foldDim(dim, keepDim) { x -> x.minOrNull()!! }.asIntTensor() + override fun StructureND.argMin(dim: Int, keepDim: Boolean): IntTensor = + foldDim(dim, keepDim) { x -> + x.withIndex().minByOrNull { it.value }?.index!! + }.asIntTensor() + override fun StructureND.max(): Int = this.fold { it.maxOrNull()!! } override fun StructureND.max(dim: Int, keepDim: Boolean): IntTensor = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 49d67c205..ec529590f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -257,13 +257,13 @@ internal fun DoubleTensorAlgebra.qrHelper( val qT = q.transpose(0, 1) for (j in 0 until n) { - val v = matrixT[j] + val v = matrixT.getTensor(j) val vv = v.as1D() if (j > 0) { for (i in 0 until j) { - r[i, j] = (qT[i] dot matrixT[j]).value() + r[i, j] = (qT.getTensor(i) dot matrixT.getTensor(j)).value() for (k in 0 until n) { - val qTi = qT[i].as1D() + val qTi = qT.getTensor(i).as1D() vv[k] = vv[k] - r[i, j] * qTi[k] } } @@ -313,7 +313,7 @@ internal fun DoubleTensorAlgebra.svdHelper( val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) for (i in 0 until u.shape[0]) { for (j in 0 until v.shape[0]) { - outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() + outerProduct[i * v.shape[0] + j] = u.getTensor(i).value() * v.getTensor(j).value() } } a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 61248cbb8..efdf6ba81 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -36,17 +36,18 @@ internal class TestDoubleTensor { val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) assertEquals(tensor[intArrayOf(0, 1)], 5.8) assertTrue( - tensor.elements().map { it.second }.toList().toDoubleArray() contentEquals tensor.mutableBuffer.toDoubleArray() + tensor.elements().map { it.second }.toList() + .toDoubleArray() contentEquals tensor.mutableBuffer.toDoubleArray() ) } @Test fun testGet() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) - val matrix = tensor[0].as2D() + val matrix = tensor.getTensor(0).as2D() assertEquals(matrix[0, 1], 5.8) - val vector = tensor[0][1].as1D() + val vector = tensor.getTensor(0, 1).as1D() assertEquals(vector[0], 58.4) matrix[0, 1] = 77.89 @@ -57,8 +58,8 @@ internal class TestDoubleTensor { tensor.matrixSequence().forEach { val a = it.toTensor() - val secondRow = a[1].as1D() - val secondColumn = a.transpose(0, 1)[1].as1D() + val secondRow = a.getTensor(1).as1D() + val secondColumn = a.transpose(0, 1).getTensor(1).as1D() assertEquals(secondColumn[0], 77.89) assertEquals(secondRow[1], secondColumn[1]) } From b5d04ba02cd325d71120819563db8a305a54688b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Sep 2022 15:27:38 +0300 Subject: [PATCH 172/174] Global refactor of tensors --- CHANGELOG.md | 1 + build.gradle.kts | 15 +- .../kscience/kmath/tensors/OLSWithSVD.kt | 2 +- .../space/kscience/kmath/tensors/PCA.kt | 2 +- .../tensors/linearSystemSolvingWithLUP.kt | 2 +- .../kscience/kmath/tensors/neuralNetwork.kt | 19 +- .../space/kscience/kmath/nd/StructureND.kt | 17 +- .../space/kscience/kmath/structures/Buffer.kt | 1 - .../kscience/kmath/structures/DoubleBuffer.kt | 5 - .../kscience/kmath/structures/IntBuffer.kt | 3 +- .../kmath/structures/NumberNDFieldTest.kt | 4 +- kmath-for-real/build.gradle.kts | 16 +- .../kscience/kmath/real/DoubleMatrixTest.kt | 2 +- .../kmath/multik/MultikTensorAlgebra.kt | 32 +- .../kscience/kmath/nd4j/Nd4jTensorAlgebra.kt | 2 +- .../kmath/tensorflow/TensorFlowAlgebra.kt | 2 +- kmath-tensors/build.gradle.kts | 6 + .../kmath/tensors/api/TensorAlgebra.kt | 2 +- .../core/BroadcastDoubleTensorAlgebra.kt | 38 +- .../kmath/tensors/core/BufferedTensor.kt | 14 +- .../kmath/tensors/core/DoubleTensor.kt | 82 ++- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 653 +++++++----------- .../kscience/kmath/tensors/core/IntTensor.kt | 88 ++- .../kmath/tensors/core/IntTensorAlgebra.kt | 307 ++++---- .../tensors/core/internal/broadcastUtils.kt | 21 +- .../kmath/tensors/core/internal/checks.kt | 17 +- .../core/internal/doubleTensorHelpers.kt | 189 +++++ .../tensors/core/internal/intTensorHelpers.kt | 64 ++ .../kmath/tensors/core/internal/linUtils.kt | 94 +-- .../tensors/core/internal/tensorCastsUtils.kt | 37 - .../kmath/tensors/core/internal/utils.kt | 35 +- .../kmath/tensors/core/tensorCasts.kt | 46 -- .../kmath/tensors/core/tensorTransform.kt | 55 ++ .../kmath/tensors/core/TestBroadcasting.kt | 29 +- .../core/TestDoubleAnalyticTensorAlgebra.kt | 87 ++- .../core/TestDoubleLinearOpsAlgebra.kt | 19 +- .../kmath/tensors/core/TestDoubleTensor.kt | 17 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 108 +-- .../tensors/core/offsetBufferEquality.kt | 24 + .../src/commonMain/kotlin/bufferEquality.kt | 20 + 40 files changed, 1183 insertions(+), 994 deletions(-) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt create mode 100644 kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt create mode 100644 test-utils/src/commonMain/kotlin/bufferEquality.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index acec30836..feb925436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Algebra now has an obligatory `bufferFactory` (#477). ### Changed +- Major refactor of tensors (only minor API changes) - Kotlin 1.7.20 - `LazyStructure` `deffered` -> `async` to comply with coroutines code style - Default `dot` operation in tensor algebra no longer support broadcasting. Instead `matmul` operation is added to `DoubleTensorAlgebra`. diff --git a/build.gradle.kts b/build.gradle.kts index 890824d65..120b0f35d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,10 @@ +import space.kscience.gradle.isInDevelopment import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useSPCTeam plugins { id("space.kscience.gradle.project") - id("org.jetbrains.kotlinx.kover") version "0.5.0" + id("org.jetbrains.kotlinx.kover") version "0.6.0" } allprojects { @@ -14,7 +15,7 @@ allprojects { } group = "space.kscience" - version = "0.3.1-dev-3" + version = "0.3.1-dev-4" } subprojects { @@ -75,8 +76,14 @@ ksciencePublish { useApache2Licence() useSPCTeam() } - github("kmath", "SciProgCentre", addToRelease = false) - space("https://maven.pkg.jetbrains.space/mipt-npm/p/sci/dev") + github("kmath", "SciProgCentre") + space( + if (isInDevelopment) { + "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/dev" + } else { + "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/release" + } + ) sonatype() } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 8082ed8e2..d0b24de70 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -52,7 +52,7 @@ fun main() { // inverse Sigma matrix can be restored from singular values with diagonalEmbedding function val sigma = diagonalEmbedding(singValues.map{ if (abs(it) < 1e-3) 0.0 else 1.0/it }) - val alphaOLS = v dot sigma dot u.transpose() dot y + val alphaOLS = v dot sigma dot u.transposed() dot y println("Estimated alpha:\n" + "$alphaOLS") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index e5d1ef9f8..1768be283 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -27,7 +27,7 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with println("y:\n$y") // stack them into single dataset - val dataset = stack(listOf(x, y)).transpose() + val dataset = stack(listOf(x, y)).transposed() // normalize both x and y val xMean = x.mean() diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt index bafdf9b21..64cc138d7 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt @@ -75,7 +75,7 @@ fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear // solveLT(l, b) function can be easily adapted for upper triangular matrix by the permutation matrix revMat // create it by placing ones on side diagonal - val revMat = u.zeroesLike() + val revMat = zeroesLike(u) val n = revMat.shape[0] for (i in 0 until n) { revMat[intArrayOf(i, n - 1 - i)] = 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt index 7289d86c4..84d6dcd22 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt @@ -3,16 +3,14 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -@file:OptIn(PerformancePitfall::class) - package space.kscience.kmath.tensors -import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.operations.asIterable import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.copyArray +import space.kscience.kmath.tensors.core.toDoubleTensor import kotlin.math.sqrt const val seed = 100500L @@ -82,9 +80,9 @@ class Dense( } override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - val gradInput = outputError dot weights.transpose() + val gradInput = outputError dot weights.transposed() - val gradW = input.transpose() dot outputError + val gradW = input.transposed() dot outputError val gradBias = outputError.mean(dim = 0, keepDim = false) * input.shape[0].toDouble() weights -= learningRate * gradW @@ -109,12 +107,11 @@ fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double { } // neural network class -@OptIn(ExperimentalStdlibApi::class) class NeuralNetwork(private val layers: List) { private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { - val onesForAnswers = yPred.zeroesLike() - yTrue.copyArray().forEachIndexed { index, labelDouble -> + val onesForAnswers = zeroesLike(yPred) + yTrue.source.asIterable().forEachIndexed { index, labelDouble -> val label = labelDouble.toInt() onesForAnswers[intArrayOf(index, label)] = 1.0 } @@ -166,7 +163,7 @@ class NeuralNetwork(private val layers: List) { for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { train(xBatch, yBatch) } - println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).asDouble())}") + println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).toDoubleTensor())}") } } @@ -233,7 +230,7 @@ fun main() = BroadcastDoubleTensorAlgebra { val prediction = model.predict(xTest) // process raw prediction via argMax - val predictionLabels = prediction.argMax(1, true).asDouble() + val predictionLabels = prediction.argMax(1, true).toDoubleTensor() // find out accuracy val acc = accuracy(yTest, predictionLabels) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index aece10c2e..b2da083bb 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -237,19 +237,4 @@ public interface MutableStructureND : StructureND { */ public operator fun MutableStructureND.set(vararg index: Int, value: T) { set(index, value) -} - -/** - * Transform a structure element-by element in place. - */ -@OptIn(PerformancePitfall::class) -public inline fun MutableStructureND.mapInPlace(action: (index: IntArray, t: T) -> T): Unit = - elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } - -public inline fun StructureND.zip( - struct: StructureND, - crossinline block: (T, T) -> T, -): StructureND { - require(shape.contentEquals(struct.shape)) { "Shape mismatch in structure combination" } - return StructureND.auto(shape) { block(this[it], struct[it]) } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 2f9f8a8e0..5cfafe5a5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -114,7 +114,6 @@ public interface Buffer { * * The [size] is specified, and each element is calculated by calling the specified [initializer] function. */ - @Suppress("UNCHECKED_CAST") public inline fun auto(size: Int, initializer: (Int) -> T): Buffer = auto(T::class, size, initializer) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index e39c22158..4dd9003f3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -47,11 +47,6 @@ public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = */ public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles) -/** - * Simplified [DoubleBuffer] to array comparison - */ -public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) - /** * Returns a new [DoubleArray] containing all the elements of this [Buffer]. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index 8477fc13b..f80ad0ff7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -24,8 +24,7 @@ public value class IntBuffer(public val array: IntArray) : MutableBuffer { override operator fun iterator(): IntIterator = array.iterator() - override fun copy(): MutableBuffer = - IntBuffer(array.copyOf()) + override fun copy(): IntBuffer = IntBuffer(array.copyOf()) } /** diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt index 62c4811e8..a54af571e 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt @@ -74,7 +74,9 @@ class NumberNDFieldTest { @Test fun combineTest() { - val division = array1.zip(array2, Double::div) + algebra { + val division = zip(array1, array2) { l, r -> l / r } + } } object L2Norm : Norm, Double> { diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 308b8d732..1e964d99c 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -2,13 +2,13 @@ plugins { id("space.kscience.gradle.mpp") } -kscience{ +kscience { native() -} - -kotlin.sourceSets.commonMain { dependencies { - api(project(":kmath-core")) + api(projects.kmathCore) + } + dependencies("commonTest") { + implementation(projects.testUtils) } } @@ -24,21 +24,21 @@ readme { feature( id = "DoubleVector", ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt" - ){ + ) { "Numpy-like operations for Buffers/Points" } feature( id = "DoubleMatrix", ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt" - ){ + ) { "Numpy-like operations for 2d real structures" } feature( id = "grids", ref = "src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt" - ){ + ) { "Uniform grid generators" } } diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt index 89e55c6d4..0d016116d 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.algebra -import space.kscience.kmath.structures.contentEquals +import space.kscience.kmath.testutils.contentEquals import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt index e32221dbf..194c5fcee 100644 --- a/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ b/kmath-multik/src/commonMain/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt @@ -72,6 +72,20 @@ public abstract class MultikTensorAlgebra>( } } + /** + * Transform a structure element-by element in place. + */ + public inline fun MutableStructureND.mapIndexedInPlace(operation: (index: IntArray, t: T) -> T): Unit { + if (this is MultikTensor) { + array.multiIndices.iterator().forEach { + set(it, operation(it, get(it))) + } + } else { + indices.forEach { set(it, operation(it, get(it))) } + } + } + + @OptIn(PerformancePitfall::class) override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException @@ -121,7 +135,7 @@ public abstract class MultikTensorAlgebra>( if (this is MultikTensor) { array.plusAssign(value) } else { - mapInPlace { _, t -> elementAlgebra.add(t, value) } + mapIndexedInPlace { _, t -> elementAlgebra.add(t, value) } } } @@ -129,7 +143,7 @@ public abstract class MultikTensorAlgebra>( if (this is MultikTensor) { array.plusAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.add(t, arg[index]) } + mapIndexedInPlace { index, t -> elementAlgebra.add(t, arg[index]) } } } @@ -145,7 +159,7 @@ public abstract class MultikTensorAlgebra>( if (this is MultikTensor) { array.minusAssign(value) } else { - mapInPlace { _, t -> elementAlgebra.run { t - value } } + mapIndexedInPlace { _, t -> elementAlgebra.run { t - value } } } } @@ -153,7 +167,7 @@ public abstract class MultikTensorAlgebra>( if (this is MultikTensor) { array.minusAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.run { t - arg[index] } } + mapIndexedInPlace { index, t -> elementAlgebra.run { t - arg[index] } } } } @@ -170,7 +184,7 @@ public abstract class MultikTensorAlgebra>( if (this is MultikTensor) { array.timesAssign(value) } else { - mapInPlace { _, t -> elementAlgebra.multiply(t, value) } + mapIndexedInPlace { _, t -> elementAlgebra.multiply(t, value) } } } @@ -178,7 +192,7 @@ public abstract class MultikTensorAlgebra>( if (this is MultikTensor) { array.timesAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.multiply(t, arg[index]) } + mapIndexedInPlace { index, t -> elementAlgebra.multiply(t, arg[index]) } } } @@ -187,7 +201,7 @@ public abstract class MultikTensorAlgebra>( override fun Tensor.getTensor(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() - override fun Tensor.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() + override fun Tensor.transposed(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() override fun Tensor.view(shape: IntArray): MultikTensor { require(shape.all { it > 0 }) @@ -283,7 +297,7 @@ public abstract class MultikDivisionTensorAlgebra>( if (this is MultikTensor) { array.divAssign(value) } else { - mapInPlace { _, t -> elementAlgebra.divide(t, value) } + mapIndexedInPlace { _, t -> elementAlgebra.divide(t, value) } } } @@ -291,7 +305,7 @@ public abstract class MultikDivisionTensorAlgebra>( if (this is MultikTensor) { array.divAssign(arg.asMultik().array) } else { - mapInPlace { index, t -> elementAlgebra.divide(t, arg[index]) } + mapIndexedInPlace { index, t -> elementAlgebra.divide(t, arg[index]) } } } } \ No newline at end of file diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index efd3ded70..c1772683f 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -96,7 +96,7 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() override fun Tensor.getTensor(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() - override fun Tensor.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() + override fun Tensor.transposed(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() override fun StructureND.dot(other: StructureND): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() override fun StructureND.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt index 346750f88..74fcf2d7d 100644 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt @@ -188,7 +188,7 @@ public abstract class TensorFlowAlgebra> internal c StridedSliceHelper.stridedSlice(ops.scope(), it, Indices.at(i.toLong())) } - override fun Tensor.transpose(i: Int, j: Int): Tensor = operate { + override fun Tensor.transposed(i: Int, j: Int): Tensor = operate { ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) } diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 78ea4ba42..1060b37b4 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -25,6 +25,12 @@ kotlin.sourceSets { api(project(":kmath-stat")) } } + + commonTest{ + dependencies{ + implementation(projects.testUtils) + } + } } readme { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 7615af2ea..70b985a54 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -180,7 +180,7 @@ public interface TensorAlgebra> : RingOpsND { * @param j the second dimension to be transposed * @return transposed tensor */ - public fun Tensor.transpose(i: Int = -2, j: Int = -1): Tensor + public fun Tensor.transposed(i: Int = -2, j: Int = -1): Tensor /** * Returns a new tensor with the same data as the self tensor but of a different shape. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index 31e5b6e69..f337a2175 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.broadcastTensors import space.kscience.kmath.tensors.core.internal.broadcastTo @@ -22,8 +22,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> - newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i] + val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> + newThis.source[i] + newOther.source[i] } return DoubleTensor(newThis.shape, resBuffer) } @@ -31,8 +31,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun Tensor.plusAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) for (i in 0 until asDoubleTensor().indices.linearSize) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] += - newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] + asDoubleTensor().source[i] += newOther.source[i] } } @@ -40,17 +39,16 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> - newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i] + val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> + newThis.source[i] - newOther.source[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun Tensor.minusAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until asDoubleTensor().indices.linearSize) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] -= - newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] + for (i in 0 until indices.linearSize) { + asDoubleTensor().source[i] -= newOther.source[i] } } @@ -58,18 +56,16 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> - newThis.mutableBuffer.array()[newThis.bufferStart + i] * - newOther.mutableBuffer.array()[newOther.bufferStart + i] + val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> + newThis.source[i] * newOther.source[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun Tensor.timesAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until asDoubleTensor().indices.linearSize) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] *= - newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] + for (i in 0 until indices.linearSize) { + asDoubleTensor().source[+i] *= newOther.source[i] } } @@ -77,18 +73,16 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(asDoubleTensor(), arg.asDoubleTensor()) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> - newThis.mutableBuffer.array()[newOther.bufferStart + i] / - newOther.mutableBuffer.array()[newOther.bufferStart + i] + val resBuffer = DoubleBuffer(newThis.indices.linearSize) { i -> + newThis.source[i] / newOther.source[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun Tensor.divAssign(arg: StructureND) { val newOther = broadcastTo(arg.asDoubleTensor(), asDoubleTensor().shape) - for (i in 0 until asDoubleTensor().indices.linearSize) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] /= - newOther.mutableBuffer.array()[asDoubleTensor().bufferStart + i] + for (i in 0 until indices.linearSize) { + asDoubleTensor().source[i] /= newOther.source[i] } } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 98e6ab430..0b043db56 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -13,12 +13,12 @@ import space.kscience.kmath.tensors.api.Tensor /** * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] */ -public open class BufferedTensor internal constructor( +public abstract class BufferedTensor( override val shape: IntArray, - @PublishedApi internal val mutableBuffer: MutableBuffer, - @PublishedApi internal val bufferStart: Int, ) : Tensor { + public abstract val source: MutableBuffer + /** * Buffer strides based on [TensorLinearStructure] implementation */ @@ -27,14 +27,8 @@ public open class BufferedTensor internal constructor( /** * Number of elements in tensor */ - public val numElements: Int - get() = indices.linearSize + public val linearSize: Int get() = indices.linearSize - override fun get(index: IntArray): T = mutableBuffer[bufferStart + indices.offset(index)] - - override fun set(index: IntArray, value: T) { - mutableBuffer[bufferStart + indices.offset(index)] = value - } @PerformancePitfall override fun elements(): Sequence> = indices.asSequence().map { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt index e8239caf4..e9589eb0a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt @@ -5,16 +5,88 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.core.internal.toPrettyString +public class OffsetDoubleBuffer( + private val source: DoubleBuffer, + private val offset: Int, + override val size: Int, +) : MutableBuffer { + + init { + require(offset >= 0) { "Offset must be non-negative" } + require(size >= 0) { "Size must be non-negative" } + require(offset + size <= source.size) { "Maximum index must be inside source dimension" } + } + + override fun set(index: Int, value: Double) { + require(index in 0 until size) { "Index must be in [0, size)" } + source[index + offset] = value + } + + override fun get(index: Int): Double = source[index + offset] + + /** + * Copy only a part of buffer that belongs to this tensor + */ + override fun copy(): DoubleBuffer = source.array.copyOfRange(offset, offset + size).asBuffer() + + override fun iterator(): Iterator = iterator { + for (i in indices) { + yield(get(i)) + } + } + + override fun toString(): String = Buffer.toString(this) + + public fun view(addOffset: Int, newSize: Int = size - addOffset): OffsetDoubleBuffer = + OffsetDoubleBuffer(source, offset + addOffset, newSize) +} + +public fun OffsetDoubleBuffer.slice(range: IntRange): OffsetDoubleBuffer = view(range.first, range.last - range.first) + +/** + * Map only operable content of the offset buffer + */ +public inline fun OffsetDoubleBuffer.map(operation: (Double) -> Double): DoubleBuffer = + DoubleBuffer(size) { operation(get(it)) } + +public inline fun OffsetDoubleBuffer.zip( + other: OffsetDoubleBuffer, + operation: (l: Double, r: Double) -> Double, +): DoubleBuffer { + require(size == other.size) { "The sizes of zipped buffers must be the same" } + return DoubleBuffer(size) { operation(get(it), other[it]) } +} + +/** + * map in place + */ +public inline fun OffsetDoubleBuffer.mapInPlace(operation: (Double) -> Double) { + indices.forEach { set(it, operation(get(it))) } +} + /** * Default [BufferedTensor] implementation for [Double] values */ -public class DoubleTensor @PublishedApi internal constructor( +public class DoubleTensor( shape: IntArray, - buffer: DoubleArray, - offset: Int = 0 -) : BufferedTensor(shape, DoubleBuffer(buffer), offset) { + override val source: OffsetDoubleBuffer, +) : BufferedTensor(shape) { + + init { + require(linearSize == source.size) { "Source buffer size must be equal tensor size" } + } + + public constructor(shape: IntArray, buffer: DoubleBuffer) : this(shape, OffsetDoubleBuffer(buffer, 0, buffer.size)) + + override fun get(index: IntArray): Double = this.source[indices.offset(index)] + + override fun set(index: IntArray, value: Double) { + source[indices.offset(index)] = value + } + + override fun toString(): String = toPrettyString() } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 8acb15251..d758c49a1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -12,8 +12,7 @@ import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.indices +import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.tensors.api.Tensor @@ -41,56 +40,64 @@ public open class DoubleTensorAlgebra : * @param transform the function to be applied to each element of the tensor. * @return the resulting tensor after applying the function. */ - @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.map(transform: DoubleField.(Double) -> Double): DoubleTensor { - val tensor = this.asDoubleTensor() + val tensor = asDoubleTensor() //TODO remove additional copy - val sourceArray = tensor.copyArray() - val array = DoubleArray(tensor.numElements) { DoubleField.transform(sourceArray[it]) } + val array = DoubleBuffer(tensor.source.size) { DoubleField.transform(tensor.source[it]) } return DoubleTensor( tensor.shape, array, - tensor.bufferStart ) } - @PerformancePitfall + public inline fun Tensor.mapInPlace(operation: (Double) -> Double) { + if (this is DoubleTensor) { + source.mapInPlace(operation) + } else { + indices.forEach { set(it, operation(get(it))) } + } + } + + public inline fun Tensor.mapIndexedInPlace(operation: (IntArray, Double) -> Double) { + indices.forEach { set(it, operation(it, get(it))) } + } + @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor { val tensor = this.asDoubleTensor() //TODO remove additional copy - val sourceArray = tensor.copyArray() - val array = DoubleArray(tensor.numElements) { DoubleField.transform(tensor.indices.index(it), sourceArray[it]) } - return DoubleTensor( - tensor.shape, - array, - tensor.bufferStart - ) + val buffer = DoubleBuffer(tensor.source.size) { + DoubleField.transform(tensor.indices.index(it), tensor.source[it]) + } + return DoubleTensor(tensor.shape, buffer) } - @PerformancePitfall - override fun zip( + @Suppress("OVERRIDE_BY_INLINE") + final override inline fun zip( left: StructureND, right: StructureND, transform: DoubleField.(Double, Double) -> Double, ): DoubleTensor { - require(left.shape.contentEquals(right.shape)) { - "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" - } + checkShapesCompatible(left, right) + val leftTensor = left.asDoubleTensor() - val leftArray = leftTensor.copyArray() val rightTensor = right.asDoubleTensor() - val rightArray = rightTensor.copyArray() - val array = DoubleArray(leftTensor.numElements) { DoubleField.transform(leftArray[it], rightArray[it]) } - return DoubleTensor( - leftTensor.shape, - array - ) + val buffer = DoubleBuffer(leftTensor.source.size) { + DoubleField.transform(leftTensor.source[it], rightTensor.source[it]) + } + return DoubleTensor(leftTensor.shape, buffer) } - override fun StructureND.valueOrNull(): Double? = if (asDoubleTensor().shape contentEquals intArrayOf(1)) - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart] else null + + public inline fun StructureND.reduceElements(transform: (DoubleBuffer) -> Double): Double = + transform(asDoubleTensor().source.copy()) + //TODO do we need protective copy? + + override fun StructureND.valueOrNull(): Double? { + val dt = asDoubleTensor() + return if (dt.shape contentEquals intArrayOf(1)) dt.source[0] else null + } override fun StructureND.value(): Double = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") @@ -99,14 +106,14 @@ public open class DoubleTensorAlgebra : * Constructs a tensor with the specified shape and data. * * @param shape the desired shape for the tensor. - * @param buffer one-dimensional data array. - * @return tensor with the [shape] shape and [buffer] data. + * @param array one-dimensional data array. + * @return tensor with the [shape] shape and [array] data. */ - public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { - checkEmptyShape(shape) - checkEmptyDoubleBuffer(buffer) - checkBufferShapeConsistency(shape, buffer) - return DoubleTensor(shape, buffer, 0) + public fun fromArray(shape: IntArray, array: DoubleArray): DoubleTensor { + checkNotEmptyShape(shape) + checkEmptyDoubleBuffer(array) + checkBufferShapeConsistency(shape, array) + return DoubleTensor(shape, array.asBuffer()) } /** @@ -122,10 +129,10 @@ public open class DoubleTensorAlgebra : ) override fun Tensor.getTensor(i: Int): DoubleTensor { - val lastShape = asDoubleTensor().shape.drop(1).toIntArray() + val dt = asDoubleTensor() + val lastShape = shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - val newStart = newShape.reduce(Int::times) * i + asDoubleTensor().bufferStart - return DoubleTensor(newShape, asDoubleTensor().mutableBuffer.array(), newStart) + return DoubleTensor(newShape, dt.source.view(newShape.reduce(Int::times) * i)) } /** @@ -136,8 +143,8 @@ public open class DoubleTensorAlgebra : * @return tensor with the [shape] shape and filled with [value]. */ public fun full(value: Double, shape: IntArray): DoubleTensor { - checkEmptyShape(shape) - val buffer = DoubleArray(shape.reduce(Int::times)) { value } + checkNotEmptyShape(shape) + val buffer = DoubleBuffer(shape.reduce(Int::times)) { value } return DoubleTensor(shape, buffer) } @@ -147,9 +154,9 @@ public open class DoubleTensorAlgebra : * @param value the value to fill the output tensor with. * @return tensor with the `input` tensor shape and filled with [value]. */ - public fun Tensor.fullLike(value: Double): DoubleTensor { - val shape = asDoubleTensor().shape - val buffer = DoubleArray(asDoubleTensor().numElements) { value } + public fun fullLike(structureND: StructureND<*>, value: Double): DoubleTensor { + val shape = structureND.shape + val buffer = DoubleBuffer(structureND.indices.linearSize) { value } return DoubleTensor(shape, buffer) } @@ -166,7 +173,7 @@ public open class DoubleTensorAlgebra : * * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. */ - public fun StructureND.zeroesLike(): DoubleTensor = asDoubleTensor().fullLike(0.0) + public fun zeroesLike(structureND: StructureND<*>): DoubleTensor = fullLike(structureND, 0.0) /** * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. @@ -181,7 +188,7 @@ public open class DoubleTensorAlgebra : * * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor. */ - public fun Tensor.onesLike(): DoubleTensor = asDoubleTensor().fullLike(1.0) + public fun onesLike(structureND: StructureND<*>): DoubleTensor = fullLike(structureND, 1.0) /** * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. @@ -191,7 +198,7 @@ public open class DoubleTensorAlgebra : */ public fun eye(n: Int): DoubleTensor { val shape = intArrayOf(n, n) - val buffer = DoubleArray(n * n) { 0.0 } + val buffer = DoubleBuffer(n * n) { 0.0 } val res = DoubleTensor(shape, buffer) for (i in 0 until n) { res[intArrayOf(i, i)] = 1.0 @@ -199,192 +206,102 @@ public open class DoubleTensorAlgebra : return res } - /** - * Return a copy of the tensor. - * - * @return a copy of the `input` tensor with a copied buffer. - */ - public fun StructureND.copy(): DoubleTensor = - DoubleTensor( - asDoubleTensor().shape, - asDoubleTensor().mutableBuffer.array().copyOf(), - asDoubleTensor().bufferStart - ) + override fun Double.plus(arg: StructureND): DoubleTensor = arg.map { this@plus + it } - override fun Double.plus(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> - arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] + this - } - return DoubleTensor(arg.shape, resBuffer) - } + override fun StructureND.plus(arg: Double): DoubleTensor = map { it + arg } - override fun StructureND.plus(arg: Double): DoubleTensor = arg + asDoubleTensor() - - override fun StructureND.plus(arg: StructureND): DoubleTensor { - checkShapesCompatible(asDoubleTensor(), arg.asDoubleTensor()) - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[i] + arg.asDoubleTensor().mutableBuffer.array()[i] - } - return DoubleTensor(asDoubleTensor().shape, resBuffer) - } + override fun StructureND.plus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l + r } override fun Tensor.plusAssign(value: Double) { - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] += value - } + mapInPlace { it + value } } override fun Tensor.plusAssign(arg: StructureND) { checkShapesCompatible(asDoubleTensor(), arg.asDoubleTensor()) - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] += - arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] + mapIndexedInPlace { index, value -> + value + arg[index] } } - override fun Double.minus(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> - this - arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] - } - return DoubleTensor(arg.shape, resBuffer) - } + override fun Double.minus(arg: StructureND): DoubleTensor = arg.map { this@minus - it } - override fun StructureND.minus(arg: Double): DoubleTensor { - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] - arg - } - return DoubleTensor(asDoubleTensor().shape, resBuffer) - } + override fun StructureND.minus(arg: Double): DoubleTensor = map { it - arg } - override fun StructureND.minus(arg: StructureND): DoubleTensor { - checkShapesCompatible(asDoubleTensor(), arg) - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[i] - arg.asDoubleTensor().mutableBuffer.array()[i] - } - return DoubleTensor(asDoubleTensor().shape, resBuffer) - } + override fun StructureND.minus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l + r } override fun Tensor.minusAssign(value: Double) { - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] -= value - } + mapInPlace { it - value } } override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(asDoubleTensor(), arg) - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] -= - arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] - } + checkShapesCompatible(this, arg) + mapIndexedInPlace { index, value -> value - arg[index] } } - override fun Double.times(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> - arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] * this - } - return DoubleTensor(arg.shape, resBuffer) - } + override fun Double.times(arg: StructureND): DoubleTensor = arg.map { this@times * it } override fun StructureND.times(arg: Double): DoubleTensor = arg * asDoubleTensor() - override fun StructureND.times(arg: StructureND): DoubleTensor { - checkShapesCompatible(asDoubleTensor(), arg) - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] * - arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] - } - return DoubleTensor(asDoubleTensor().shape, resBuffer) - } + override fun StructureND.times(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l * r } override fun Tensor.timesAssign(value: Double) { - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] *= value - } + mapInPlace { it * value } } override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(asDoubleTensor(), arg) - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] *= - arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] - } + checkShapesCompatible(this, arg) + mapIndexedInPlace { index, value -> value * arg[index] } } - override fun Double.div(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.asDoubleTensor().numElements) { i -> - this / arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] - } - return DoubleTensor(arg.shape, resBuffer) - } + override fun Double.div(arg: StructureND): DoubleTensor = arg.map { this@div / it } - override fun StructureND.div(arg: Double): DoubleTensor { - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] / arg - } - return DoubleTensor(shape, resBuffer) - } + override fun StructureND.div(arg: Double): DoubleTensor = map { it / arg } - override fun StructureND.div(arg: StructureND): DoubleTensor { - checkShapesCompatible(asDoubleTensor(), arg) - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] / - arg.asDoubleTensor().mutableBuffer.array()[arg.asDoubleTensor().bufferStart + i] - } - return DoubleTensor(asDoubleTensor().shape, resBuffer) - } + override fun StructureND.div(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l / r } override fun Tensor.divAssign(value: Double) { - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] /= value - } + mapInPlace { it / value } } override fun Tensor.divAssign(arg: StructureND) { checkShapesCompatible(asDoubleTensor(), arg) - for (i in 0 until asDoubleTensor().numElements) { - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] /= - arg.asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i] - } + mapIndexedInPlace { index, value -> value / arg[index] } } - override fun StructureND.unaryMinus(): DoubleTensor { - val resBuffer = DoubleArray(asDoubleTensor().numElements) { i -> - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + i].unaryMinus() - } - return DoubleTensor(asDoubleTensor().shape, resBuffer) - } + override fun StructureND.unaryMinus(): DoubleTensor = map { -it } - override fun Tensor.transpose(i: Int, j: Int): DoubleTensor { - val ii = asDoubleTensor().minusIndex(i) - val jj = asDoubleTensor().minusIndex(j) - checkTranspose(asDoubleTensor().dimension, ii, jj) - val n = asDoubleTensor().numElements + override fun Tensor.transposed(i: Int, j: Int): DoubleTensor { + // TODO change strides instead of changing content + val dt = asDoubleTensor() + val ii = dt.minusIndex(i) + val jj = dt.minusIndex(j) + checkTranspose(dt.dimension, ii, jj) + val n = dt.linearSize val resBuffer = DoubleArray(n) - val resShape = asDoubleTensor().shape.copyOf() + val resShape = dt.shape.copyOf() resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } - val resTensor = DoubleTensor(resShape, resBuffer) + val resTensor = DoubleTensor(resShape, resBuffer.asBuffer()) for (offset in 0 until n) { - val oldMultiIndex = asDoubleTensor().indices.index(offset) + val oldMultiIndex = dt.indices.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } val linearIndex = resTensor.indices.offset(newMultiIndex) - resTensor.mutableBuffer.array()[linearIndex] = - asDoubleTensor().mutableBuffer.array()[asDoubleTensor().bufferStart + offset] + resTensor.source[linearIndex] = dt.source[offset] } return resTensor } override fun Tensor.view(shape: IntArray): DoubleTensor { checkView(asDoubleTensor(), shape) - return DoubleTensor(shape, asDoubleTensor().mutableBuffer.array(), asDoubleTensor().bufferStart) + return DoubleTensor(shape, asDoubleTensor().source) } override fun Tensor.viewAs(other: StructureND): DoubleTensor = - asDoubleTensor().view(other.shape) + view(other.shape) /** * Broadcasting Matrix product of two tensors. @@ -417,28 +334,28 @@ public open class DoubleTensorAlgebra : */ @UnstableKMathAPI public infix fun StructureND.matmul(other: StructureND): DoubleTensor { - if (asDoubleTensor().shape.size == 1 && other.shape.size == 1) { - return DoubleTensor( - intArrayOf(1), - doubleArrayOf(asDoubleTensor().times(other).asDoubleTensor().mutableBuffer.array().sum()) - ) + if (shape.size == 1 && other.shape.size == 1) { + return DoubleTensor(intArrayOf(1), DoubleBuffer(times(other).sum())) } - var newThis = asDoubleTensor().copy() - var newOther = other.copy() - var penultimateDim = false var lastDim = false - if (asDoubleTensor().shape.size == 1) { + + //TODO do we need protective copy here? + var newThis: DoubleTensor = copyToTensor() + var newOther: DoubleTensor = other.copyToTensor() + + if (shape.size == 1) { penultimateDim = true - newThis = asDoubleTensor().view(intArrayOf(1) + asDoubleTensor().shape) - } - if (other.shape.size == 1) { - lastDim = true - newOther = other.asDoubleTensor().view(other.shape + intArrayOf(1)) + newThis = newThis.view(intArrayOf(1) + shape) } - val broadcastTensors = broadcastOuterTensors(newThis.asDoubleTensor(), newOther.asDoubleTensor()) + if (other.shape.size == 1) { + lastDim = true + newOther = newOther.view(other.shape + intArrayOf(1)) + } + + val broadcastTensors = broadcastOuterTensors(newThis, newOther) newThis = broadcastTensors[0] newOther = broadcastTensors[1] @@ -452,12 +369,20 @@ public open class DoubleTensorAlgebra : val resShape = newThis.shape.sliceArray(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) val resSize = resShape.reduce { acc, i -> acc * i } - val resTensor = DoubleTensor(resShape, DoubleArray(resSize)) + val resTensor = DoubleTensor(resShape, DoubleArray(resSize).asBuffer()) - for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { - val (a, b) = ab - dotTo(a, b, res, l, m1, n) + val resMatrices = resTensor.matrices + val newThisMatrices = newThis.matrices + val newOtherMatrices = newOther.matrices + + for (i in resMatrices.indices) { + dotTo(newThisMatrices[i], newOtherMatrices[i], resMatrices[i], l, m1, n) } +// +// for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { +// val (a, b) = ab +// dotTo(a, b, res, l, m1, n) +// } return if (penultimateDim) { resTensor.view(resTensor.shape.dropLast(2).toIntArray() + intArrayOf(resTensor.shape.last())) @@ -503,10 +428,10 @@ public open class DoubleTensorAlgebra : diagonalEntries.shape.slice(lessDim until greaterDim - 1).toIntArray() + intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() - val resTensor = zeros(resShape) + val resTensor: DoubleTensor = zeros(resShape) - for (i in 0 until diagonalEntries.asDoubleTensor().numElements) { - val multiIndex = diagonalEntries.asDoubleTensor().indices.index(i) + for (i in 0 until diagonalEntries.indices.linearSize) { + val multiIndex = diagonalEntries.indices.index(i) var offset1 = 0 var offset2 = abs(realOffset) @@ -522,7 +447,7 @@ public open class DoubleTensorAlgebra : resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] } - return resTensor.asDoubleTensor() + return resTensor } /** @@ -542,23 +467,20 @@ public open class DoubleTensorAlgebra : * @param other the tensor to compare with `input` tensor. * @return true if two tensors have the same shape and elements, false otherwise. */ - public infix fun Tensor.eq(other: Tensor): Boolean = asDoubleTensor().eq(other, 1e-5) + public infix fun Tensor.eq(other: Tensor): Boolean = eq(other, 1e-5) private fun Tensor.eq( other: Tensor, eqFunction: (Double, Double) -> Boolean, ): Boolean { + //TODO optimize tensor conversion checkShapesCompatible(asDoubleTensor(), other) - val n = asDoubleTensor().numElements - if (n != other.asDoubleTensor().numElements) { + val n = asDoubleTensor().linearSize + if (n != other.asDoubleTensor().linearSize) { return false } for (i in 0 until n) { - if (!eqFunction( - asDoubleTensor().mutableBuffer[asDoubleTensor().bufferStart + i], - other.asDoubleTensor().mutableBuffer[other.asDoubleTensor().bufferStart + i] - ) - ) { + if (!eqFunction(asDoubleTensor().source[i], other.asDoubleTensor().source[i])) { return false } } @@ -586,7 +508,7 @@ public open class DoubleTensorAlgebra : * with `0.0` mean and `1.0` standard deviation. */ public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = - DoubleTensor(asDoubleTensor().shape, getRandomNormals(asDoubleTensor().shape.reduce(Int::times), seed)) + DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) /** * Concatenates a sequence of tensors with equal shapes along the first dimension. @@ -599,11 +521,12 @@ public open class DoubleTensorAlgebra : val shape = tensors[0].shape check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape - val resBuffer = tensors.flatMap { - it.asDoubleTensor().mutableBuffer.array().drop(it.asDoubleTensor().bufferStart) - .take(it.asDoubleTensor().numElements) - }.toDoubleArray() - return DoubleTensor(resShape, resBuffer, 0) +// val resBuffer: List = tensors.flatMap { +// it.asDoubleTensor().source.array.drop(it.asDoubleTensor().bufferStart) +// .take(it.asDoubleTensor().linearSize) +// } + val resBuffer = tensors.map { it.asDoubleTensor().source }.concat() + return DoubleTensor(resShape, resBuffer) } /** @@ -614,14 +537,12 @@ public open class DoubleTensorAlgebra : */ public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { getTensor(it) }) - private inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = - foldFunction(asDoubleTensor().copyArray()) - private inline fun StructureND.foldDim( + private inline fun StructureND.foldDimToDouble( dim: Int, keepDim: Boolean, - foldFunction: (DoubleArray) -> R, - ): BufferedTensor { + foldFunction: (DoubleArray) -> Double, + ): DoubleTensor { check(dim < dimension) { "Dimension $dim out of range $dimension" } val resShape = if (keepDim) { shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() @@ -630,9 +551,37 @@ public open class DoubleTensorAlgebra : } val resNumElements = resShape.reduce(Int::times) val init = foldFunction(DoubleArray(1) { 0.0 }) - val resTensor = BufferedTensor( + val resTensor = DoubleTensor( resShape, - MutableBuffer.auto(resNumElements) { init }, 0 + DoubleBuffer(resNumElements) { init } + ) + val dt = asDoubleTensor() + for (index in resTensor.indices) { + val prefix = index.take(dim).toIntArray() + val suffix = index.takeLast(dimension - dim - 1).toIntArray() + resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> + dt[prefix + intArrayOf(i) + suffix] + }) + } + return resTensor + } + + private inline fun StructureND.foldDimToInt( + dim: Int, + keepDim: Boolean, + foldFunction: (DoubleArray) -> Int, + ): IntTensor { + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val resShape = if (keepDim) { + shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() + } else { + shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() + } + val resNumElements = resShape.reduce(Int::times) + val init = foldFunction(DoubleArray(1) { 0.0 }) + val resTensor = IntTensor( + resShape, + IntBuffer(resNumElements) { init } ) for (index in resTensor.indices) { val prefix = index.take(dim).toIntArray() @@ -644,68 +593,71 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun StructureND.sum(): Double = asDoubleTensor().fold { it.sum() } + + override fun StructureND.sum(): Double = reduceElements { it.array.sum() } override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.sum() }.asDoubleTensor() + foldDimToDouble(dim, keepDim) { x -> x.sum() } - override fun StructureND.min(): Double = this.fold { it.minOrNull()!! } + override fun StructureND.min(): Double = reduceElements { it.array.min() } override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.minOrNull()!! }.asDoubleTensor() + foldDimToDouble(dim, keepDim) { x -> x.minOrNull()!! } - override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDim(dim, keepDim) { x -> - x.withIndex().minByOrNull { it.value }?.index!! - }.asIntTensor() + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDimToInt(dim, keepDim) { x -> + x.withIndex().minBy { it.value }.index + } - override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } + override fun StructureND.max(): Double = reduceElements { it.array.max() } override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.asDoubleTensor() + foldDimToDouble(dim, keepDim) { x -> x.maxOrNull()!! } override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> - x.withIndex().maxByOrNull { it.value }?.index!! - }.asIntTensor() + foldDimToInt(dim, keepDim) { x -> + x.withIndex().maxBy { it.value }.index + } - override fun StructureND.mean(): Double = this.fold { it.sum() / asDoubleTensor().numElements } + override fun StructureND.mean(): Double = sum() / indices.linearSize - override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = foldDim(dim, keepDim) { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - arr.sum() / shape[dim] - }.asDoubleTensor() + override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = + foldDimToDouble(dim, keepDim) { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + arr.sum() / shape[dim] + } - override fun StructureND.std(): Double = fold { arr -> - val mean = arr.sum() / asDoubleTensor().numElements - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (asDoubleTensor().numElements - 1)) + override fun StructureND.std(): Double = reduceElements { arr -> + val mean = arr.array.sum() / indices.linearSize + sqrt(arr.array.sumOf { (it - mean) * (it - mean) } / (indices.linearSize - 1)) } - override fun StructureND.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + override fun StructureND.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDimToDouble( dim, keepDim ) { arr -> check(dim < dimension) { "Dimension $dim out of range $dimension" } val mean = arr.sum() / shape[dim] sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) - }.asDoubleTensor() - - override fun StructureND.variance(): Double = fold { arr -> - val mean = arr.sum() / asDoubleTensor().numElements - arr.sumOf { (it - mean) * (it - mean) } / (asDoubleTensor().numElements - 1) } - override fun StructureND.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + override fun StructureND.variance(): Double = reduceElements { arr -> + val linearSize = indices.linearSize + val mean = arr.array.sum() / linearSize + arr.array.sumOf { (it - mean) * (it - mean) } / (linearSize - 1) + } + + override fun StructureND.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDimToDouble( dim, keepDim ) { arr -> check(dim < dimension) { "Dimension $dim out of range $dimension" } val mean = arr.sum() / shape[dim] arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) - }.asDoubleTensor() + } - private fun cov(x: DoubleTensor, y: DoubleTensor): Double { + private fun cov(x: StructureND, y: StructureND): Double { val n = x.shape[0] return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1) } @@ -725,45 +677,45 @@ public open class DoubleTensorAlgebra : check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" } val resTensor = DoubleTensor( intArrayOf(n, n), - DoubleArray(n * n) { 0.0 } + DoubleBuffer(n * n) { 0.0 } ) for (i in 0 until n) { for (j in 0 until n) { - resTensor[intArrayOf(i, j)] = cov(tensors[i].asDoubleTensor(), tensors[j].asDoubleTensor()) + resTensor[intArrayOf(i, j)] = cov(tensors[i], tensors[j]) } } return resTensor } - override fun StructureND.exp(): DoubleTensor = asDoubleTensor().map { exp(it) } + override fun StructureND.exp(): DoubleTensor = map { exp(it) } - override fun StructureND.ln(): DoubleTensor = asDoubleTensor().map { ln(it) } + override fun StructureND.ln(): DoubleTensor = map { ln(it) } - override fun StructureND.sqrt(): DoubleTensor = asDoubleTensor().map { sqrt(it) } + override fun StructureND.sqrt(): DoubleTensor = map { sqrt(it) } - override fun StructureND.cos(): DoubleTensor = asDoubleTensor().map { cos(it) } + override fun StructureND.cos(): DoubleTensor = map { cos(it) } - override fun StructureND.acos(): DoubleTensor = asDoubleTensor().map { acos(it) } + override fun StructureND.acos(): DoubleTensor = map { acos(it) } - override fun StructureND.cosh(): DoubleTensor = asDoubleTensor().map { cosh(it) } + override fun StructureND.cosh(): DoubleTensor = map { cosh(it) } - override fun StructureND.acosh(): DoubleTensor = asDoubleTensor().map { acosh(it) } + override fun StructureND.acosh(): DoubleTensor = map { acosh(it) } - override fun StructureND.sin(): DoubleTensor = asDoubleTensor().map { sin(it) } + override fun StructureND.sin(): DoubleTensor = map { sin(it) } - override fun StructureND.asin(): DoubleTensor = asDoubleTensor().map { asin(it) } + override fun StructureND.asin(): DoubleTensor = map { asin(it) } - override fun StructureND.sinh(): DoubleTensor = asDoubleTensor().map { sinh(it) } + override fun StructureND.sinh(): DoubleTensor = map { sinh(it) } - override fun StructureND.asinh(): DoubleTensor = asDoubleTensor().map { asinh(it) } + override fun StructureND.asinh(): DoubleTensor = map { asinh(it) } - override fun StructureND.tan(): DoubleTensor = asDoubleTensor().map { tan(it) } + override fun StructureND.tan(): DoubleTensor = map { tan(it) } - override fun StructureND.atan(): DoubleTensor = asDoubleTensor().map { atan(it) } + override fun StructureND.atan(): DoubleTensor = map { atan(it) } - override fun StructureND.tanh(): DoubleTensor = asDoubleTensor().map { tanh(it) } + override fun StructureND.tanh(): DoubleTensor = map { tanh(it) } - override fun StructureND.atanh(): DoubleTensor = asDoubleTensor().map { atanh(it) } + override fun StructureND.atanh(): DoubleTensor = map { atanh(it) } override fun power(arg: StructureND, pow: Number): StructureND = if (pow is Int) { arg.map { it.pow(pow) } @@ -771,9 +723,9 @@ public open class DoubleTensorAlgebra : arg.map { it.pow(pow.toDouble()) } } - override fun StructureND.ceil(): DoubleTensor = asDoubleTensor().map { ceil(it) } + override fun StructureND.ceil(): DoubleTensor = map { ceil(it) } - override fun StructureND.floor(): DoubleTensor = asDoubleTensor().map { floor(it) } + override fun StructureND.floor(): DoubleTensor = map { floor(it) } override fun StructureND.inv(): DoubleTensor = invLU(1e-9) @@ -789,7 +741,7 @@ public open class DoubleTensorAlgebra : * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. */ public fun StructureND.luFactor(epsilon: Double): Pair = - computeLU(asDoubleTensor(), epsilon) + computeLU(this, epsilon) ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") /** @@ -825,14 +777,14 @@ public open class DoubleTensorAlgebra : ) { "Inappropriate shapes of input tensors" } val n = luTensor.shape.last() - val pTensor = luTensor.zeroesLike() + val pTensor = zeroesLike(luTensor) pTensor .matrixSequence() .zip(pivotsTensor.asIntTensor().vectorSequence()) .forEach { (p, pivot) -> pivInit(p.as2D(), pivot.as1D(), n) } - val lTensor = luTensor.zeroesLike() - val uTensor = luTensor.zeroesLike() + val lTensor = zeroesLike(luTensor) + val uTensor = zeroesLike(luTensor) lTensor.matrixSequence() .zip(uTensor.matrixSequence()) @@ -863,7 +815,7 @@ public open class DoubleTensorAlgebra : checkPositiveDefinite(asDoubleTensor(), epsilon) val n = shape.last() - val lTensor = zeroesLike() + val lTensor = zeroesLike(this) for ((a, l) in asDoubleTensor().matrixSequence().zip(lTensor.matrixSequence())) for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) @@ -875,15 +827,17 @@ public open class DoubleTensorAlgebra : override fun StructureND.qr(): Pair { checkSquareMatrix(shape) - val qTensor = zeroesLike() - val rTensor = zeroesLike() + val qTensor = zeroesLike(this) + val rTensor = zeroesLike(this) + + //TODO replace with cycle asDoubleTensor().matrixSequence() .zip( (qTensor.matrixSequence() .zip(rTensor.matrixSequence())) ).forEach { (matrix, qr) -> val (q, r) = qr - qrHelper(matrix.toTensor(), q.toTensor(), r.as2D()) + qrHelper(matrix, q, r.as2D()) } return qTensor to rTensor @@ -906,14 +860,14 @@ public open class DoubleTensorAlgebra : * @return a triple `Triple(U, S, V)`. */ public fun StructureND.svd(epsilon: Double): Triple { - val size = asDoubleTensor().dimension - val commonShape = asDoubleTensor().shape.sliceArray(0 until size - 2) - val (n, m) = asDoubleTensor().shape.sliceArray(size - 2 until size) + val size = dimension + val commonShape = shape.sliceArray(0 until size - 2) + val (n, m) = shape.sliceArray(size - 2 until size) val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) val sTensor = zeros(commonShape + intArrayOf(min(n, m))) val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - val matrices = asDoubleTensor().matrices + val matrices: VirtualBuffer = asDoubleTensor().matrices val uTensors = uTensor.matrices val sTensorVectors = sTensor.vectors val vTensors = vTensor.matrices @@ -928,14 +882,12 @@ public open class DoubleTensorAlgebra : val matrixSize = matrix.shape.reduce { acc, i -> acc * i } val curMatrix = DoubleTensor( matrix.shape, - matrix.mutableBuffer.array() - .slice(matrix.bufferStart until matrix.bufferStart + matrixSize) - .toDoubleArray() + matrix.source.view(0, matrixSize) ) svdHelper(curMatrix, usv, m, n, epsilon) } - return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) + return Triple(uTensor.transposed(), sTensor, vTensor.transposed()) } override fun StructureND.symEig(): Pair = @@ -950,6 +902,7 @@ public open class DoubleTensorAlgebra : * @return a pair `eigenvalues to eigenvectors`. */ public fun StructureND.symEigSvd(epsilon: Double): Pair { + //TODO optimize conversion checkSymmetric(asDoubleTensor(), epsilon) fun MutableStructure2D.cleanSym(n: Int) { @@ -964,9 +917,9 @@ public open class DoubleTensorAlgebra : } } - val (u, s, v) = asDoubleTensor().svd(epsilon) + val (u, s, v) = svd(epsilon) val shp = s.shape + intArrayOf(1) - val utv = u.transpose() matmul v + val utv = u.transposed() matmul v val n = s.shape.last() for (matrix in utv.matrixSequence()) { matrix.as2D().cleanSym(n) @@ -977,6 +930,7 @@ public open class DoubleTensorAlgebra : } public fun StructureND.symEigJacobi(maxIteration: Int, epsilon: Double): Pair { + //TODO optimize conversion checkSymmetric(asDoubleTensor(), epsilon) val size = this.dimension @@ -991,12 +945,12 @@ public open class DoubleTensorAlgebra : for (i in 0 until matrix2D.rowNum) { for (j in 0 until matrix2D.colNum) { - eigenvectors.mutableBuffer.array()[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j] + eigenvectors.source[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j] } } for (i in 0 until matrix2D.rowNum) { - eigenvalues.mutableBuffer.array()[eigenvalueStart + i] = d[i] + eigenvalues.source[eigenvalueStart + i] = d[i] } eigenvalueStart += this.shape.last() @@ -1006,121 +960,6 @@ public open class DoubleTensorAlgebra : return eigenvalues to eigenvectors } - private fun MutableStructure2D.jacobiHelper( - maxIteration: Int, - epsilon: Double, - ): Pair, Structure2D> { - val n = this.shape[0] - val A_ = this.copy() - val V = eye(n) - val D = DoubleTensor(intArrayOf(n), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() - val B = DoubleTensor(intArrayOf(n), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() - val Z = zeros(intArrayOf(n)).as1D() - - // assume that buffered tensor is square matrix - operator fun BufferedTensor.get(i: Int, j: Int): Double { - return this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] - } - - operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { - this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] = value - } - - fun maxOffDiagonal(matrix: BufferedTensor): Double { - var maxOffDiagonalElement = 0.0 - for (i in 0 until n - 1) { - for (j in i + 1 until n) { - maxOffDiagonalElement = max(maxOffDiagonalElement, abs(matrix[i, j])) - } - } - return maxOffDiagonalElement - } - - fun rotate(a: BufferedTensor, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { - val g = a[i, j] - val h = a[k, l] - a[i, j] = g - s * (h + g * tau) - a[k, l] = h + s * (g - h * tau) - } - - fun jacobiIteration( - a: BufferedTensor, - v: BufferedTensor, - d: MutableStructure1D, - z: MutableStructure1D, - ) { - for (ip in 0 until n - 1) { - for (iq in ip + 1 until n) { - val g = 100.0 * abs(a[ip, iq]) - - if (g <= epsilon * abs(d[ip]) && g <= epsilon * abs(d[iq])) { - a[ip, iq] = 0.0 - continue - } - - var h = d[iq] - d[ip] - val t = when { - g <= epsilon * abs(h) -> (a[ip, iq]) / h - else -> { - val theta = 0.5 * h / (a[ip, iq]) - val denominator = abs(theta) + sqrt(1.0 + theta * theta) - if (theta < 0.0) -1.0 / denominator else 1.0 / denominator - } - } - - val c = 1.0 / sqrt(1 + t * t) - val s = t * c - val tau = s / (1.0 + c) - h = t * a[ip, iq] - z[ip] -= h - z[iq] += h - d[ip] -= h - d[iq] += h - a[ip, iq] = 0.0 - - for (j in 0 until ip) { - rotate(a, s, tau, j, ip, j, iq) - } - for (j in (ip + 1) until iq) { - rotate(a, s, tau, ip, j, j, iq) - } - for (j in (iq + 1) until n) { - rotate(a, s, tau, ip, j, iq, j) - } - for (j in 0 until n) { - rotate(v, s, tau, j, ip, j, iq) - } - } - } - } - - fun updateDiagonal( - d: MutableStructure1D, - z: MutableStructure1D, - b: MutableStructure1D, - ) { - for (ip in 0 until d.size) { - b[ip] += z[ip] - d[ip] = b[ip] - z[ip] = 0.0 - } - } - - var sm = maxOffDiagonal(A_) - for (iteration in 0 until maxIteration) { - if (sm < epsilon) { - break - } - - jacobiIteration(A_, V, D, Z) - updateDiagonal(D, Z, B) - sm = maxOffDiagonal(A_) - } - - // TODO sort eigenvalues - return D to V.as2D() - } - /** * Computes the determinant of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. @@ -1130,15 +969,16 @@ public open class DoubleTensorAlgebra : * @return the determinant. */ public fun StructureND.detLU(epsilon: Double = 1e-9): DoubleTensor { - checkSquareMatrix(asDoubleTensor().shape) - val luTensor = asDoubleTensor().copy() - val pivotsTensor = asDoubleTensor().setUpPivots() + checkSquareMatrix(shape) + //TODO check for unnecessary copies + val luTensor = copyToTensor() + val pivotsTensor = setUpPivots() val n = shape.size val detTensorShape = IntArray(n - 1) { i -> shape[i] } detTensorShape[n - 2] = 1 - val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } + val resBuffer = DoubleBuffer(detTensorShape.reduce(Int::times)) { 0.0 } val detTensor = DoubleTensor( detTensorShape, @@ -1164,8 +1004,9 @@ public open class DoubleTensorAlgebra : */ public fun StructureND.invLU(epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = luFactor(epsilon) - val invTensor = luTensor.zeroesLike() + val invTensor = zeroesLike(luTensor) + //TODO replace sequence with a cycle val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) for ((luP, invMatrix) in seq) { val (lu, pivots) = luP @@ -1188,7 +1029,7 @@ public open class DoubleTensorAlgebra : * @return triple of `P`, `L` and `U` tensors. */ public fun StructureND.lu(epsilon: Double = 1e-9): Triple { - val (lu, pivots) = asDoubleTensor().luFactor(epsilon) + val (lu, pivots) = luFactor(epsilon) return luPivot(lu, pivots) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt index a2b942bf0..ed96b6c8f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt @@ -5,17 +5,87 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.structures.IntBuffer -import space.kscience.kmath.tensors.core.internal.array +import space.kscience.kmath.structures.* /** * Default [BufferedTensor] implementation for [Int] values */ -public class IntTensor @PublishedApi internal constructor( - shape: IntArray, - buffer: IntArray, - offset: Int = 0, -) : BufferedTensor(shape, IntBuffer(buffer), offset) { - public fun asDouble(): DoubleTensor = - DoubleTensor(shape, mutableBuffer.array().map { it.toDouble() }.toDoubleArray(), bufferStart) +public class OffsetIntBuffer( + private val source: IntBuffer, + private val offset: Int, + override val size: Int, +) : MutableBuffer { + + init { + require(offset >= 0) { "Offset must be non-negative" } + require(size >= 0) { "Size must be non-negative" } + require(offset + size <= source.size) { "Maximum index must be inside source dimension" } + } + + override fun set(index: Int, value: Int) { + require(index in 0 until size) { "Index must be in [0, size)" } + source[index + offset] = value + } + + override fun get(index: Int): Int = source[index + offset] + + /** + * Copy only a part of buffer that belongs to this tensor + */ + override fun copy(): IntBuffer = source.array.copyOfRange(offset, offset + size).asBuffer() + + override fun iterator(): Iterator = iterator { + for (i in indices) { + yield(get(i)) + } + } + + override fun toString(): String = Buffer.toString(this) + + public fun view(addOffset: Int, newSize: Int = size - addOffset): OffsetIntBuffer = + OffsetIntBuffer(source, offset + addOffset, newSize) +} + +public fun OffsetIntBuffer.slice(range: IntRange): OffsetIntBuffer = view(range.first, range.last - range.first) + +/** + * Map only operable content of the offset buffer + */ +public inline fun OffsetIntBuffer.map(operation: (Int) -> Int): IntBuffer = + IntBuffer(size) { operation(get(it)) } + +public inline fun OffsetIntBuffer.zip( + other: OffsetIntBuffer, + operation: (l: Int, r: Int) -> Int, +): IntBuffer { + require(size == other.size) { "The sizes of zipped buffers must be the same" } + return IntBuffer(size) { operation(get(it), other[it]) } +} + +/** + * map in place + */ +public inline fun OffsetIntBuffer.mapInPlace(operation: (Int) -> Int) { + indices.forEach { set(it, operation(get(it))) } +} + +/** + * Default [BufferedTensor] implementation for [Int] values + */ +public class IntTensor( + shape: IntArray, + override val source: OffsetIntBuffer, +) : BufferedTensor(shape) { + + init { + require(linearSize == source.size) { "Source buffer size must be equal tensor size" } + } + + public constructor(shape: IntArray, buffer: IntBuffer) : this(shape, OffsetIntBuffer(buffer, 0, buffer.size)) + + override fun get(index: IntArray): Int = this.source[indices.offset(index)] + + override fun set(index: IntArray, value: Int) { + source[indices.offset(index)] = value + } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt index 3ddbd3301..7c18fe533 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt @@ -11,7 +11,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.* import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.api.* import space.kscience.kmath.tensors.core.internal.* import kotlin.math.* @@ -23,10 +23,6 @@ public open class IntTensorAlgebra : TensorAlgebra { public companion object : IntTensorAlgebra() - override fun StructureND.dot(other: StructureND): Tensor { - TODO("Not yet implemented") - } - override val elementAlgebra: IntRing get() = IntRing @@ -36,56 +32,64 @@ public open class IntTensorAlgebra : TensorAlgebra { * @param transform the function to be applied to each element of the tensor. * @return the resulting tensor after applying the function. */ - @PerformancePitfall @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.map(transform: IntRing.(Int) -> Int): IntTensor { val tensor = this.asIntTensor() //TODO remove additional copy - val sourceArray = tensor.copyArray() - val array = IntArray(tensor.numElements) { IntRing.transform(sourceArray[it]) } + val array = IntBuffer(tensor.source.size) { IntRing.transform(tensor.source[it]) } return IntTensor( tensor.shape, array, - tensor.bufferStart ) } - @PerformancePitfall + public inline fun Tensor.mapInPlace(operation: (Int) -> Int) { + if (this is IntTensor) { + source.mapInPlace(operation) + } else { + indices.forEach { set(it, operation(get(it))) } + } + } + + public inline fun Tensor.mapIndexedInPlace(operation: (IntArray, Int) -> Int) { + indices.forEach { set(it, operation(it, get(it))) } + } + @Suppress("OVERRIDE_BY_INLINE") final override inline fun StructureND.mapIndexed(transform: IntRing.(index: IntArray, Int) -> Int): IntTensor { val tensor = this.asIntTensor() //TODO remove additional copy - val sourceArray = tensor.copyArray() - val array = IntArray(tensor.numElements) { IntRing.transform(tensor.indices.index(it), sourceArray[it]) } - return IntTensor( - tensor.shape, - array, - tensor.bufferStart - ) + val buffer = IntBuffer(tensor.source.size) { + IntRing.transform(tensor.indices.index(it), tensor.source[it]) + } + return IntTensor(tensor.shape, buffer) } - @PerformancePitfall - override fun zip( + @Suppress("OVERRIDE_BY_INLINE") + final override inline fun zip( left: StructureND, right: StructureND, transform: IntRing.(Int, Int) -> Int, ): IntTensor { - require(left.shape.contentEquals(right.shape)) { - "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" - } + checkShapesCompatible(left, right) + val leftTensor = left.asIntTensor() - val leftArray = leftTensor.copyArray() val rightTensor = right.asIntTensor() - val rightArray = rightTensor.copyArray() - val array = IntArray(leftTensor.numElements) { IntRing.transform(leftArray[it], rightArray[it]) } - return IntTensor( - leftTensor.shape, - array - ) + val buffer = IntBuffer(leftTensor.source.size) { + IntRing.transform(leftTensor.source[it], rightTensor.source[it]) + } + return IntTensor(leftTensor.shape, buffer) } - override fun StructureND.valueOrNull(): Int? = if (asIntTensor().shape contentEquals intArrayOf(1)) - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart] else null + + public inline fun StructureND.reduceElements(transform: (IntBuffer) -> Int): Int = + transform(asIntTensor().source.copy()) + //TODO do we need protective copy? + + override fun StructureND.valueOrNull(): Int? { + val dt = asIntTensor() + return if (dt.shape contentEquals intArrayOf(1)) dt.source[0] else null + } override fun StructureND.value(): Int = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") @@ -94,16 +98,16 @@ public open class IntTensorAlgebra : TensorAlgebra { * Constructs a tensor with the specified shape and data. * * @param shape the desired shape for the tensor. - * @param buffer one-dimensional data array. - * @return tensor with the [shape] shape and [buffer] data. + * @param array one-dimensional data array. + * @return tensor with the [shape] shape and [array] data. */ - public fun fromArray(shape: IntArray, buffer: IntArray): IntTensor { - checkEmptyShape(shape) - check(buffer.isNotEmpty()) { "Illegal empty buffer provided" } - check(buffer.size == shape.reduce(Int::times)) { - "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" + public fun fromArray(shape: IntArray, array: IntArray): IntTensor { + checkNotEmptyShape(shape) + check(array.isNotEmpty()) { "Illegal empty buffer provided" } + check(array.size == shape.reduce(Int::times)) { + "Inconsistent shape ${shape.toList()} for buffer of size ${array.size} provided" } - return IntTensor(shape, buffer, 0) + return IntTensor(shape, array.asBuffer()) } /** @@ -119,10 +123,10 @@ public open class IntTensorAlgebra : TensorAlgebra { ) override fun Tensor.getTensor(i: Int): IntTensor { - val lastShape = asIntTensor().shape.drop(1).toIntArray() + val dt = asIntTensor() + val lastShape = shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - val newStart = newShape.reduce(Int::times) * i + asIntTensor().bufferStart - return IntTensor(newShape, asIntTensor().mutableBuffer.array(), newStart) + return IntTensor(newShape, dt.source.view(newShape.reduce(Int::times) * i)) } /** @@ -133,8 +137,8 @@ public open class IntTensorAlgebra : TensorAlgebra { * @return tensor with the [shape] shape and filled with [value]. */ public fun full(value: Int, shape: IntArray): IntTensor { - checkEmptyShape(shape) - val buffer = IntArray(shape.reduce(Int::times)) { value } + checkNotEmptyShape(shape) + val buffer = IntBuffer(shape.reduce(Int::times)) { value } return IntTensor(shape, buffer) } @@ -144,9 +148,9 @@ public open class IntTensorAlgebra : TensorAlgebra { * @param value the value to fill the output tensor with. * @return tensor with the `input` tensor shape and filled with [value]. */ - public fun Tensor.fullLike(value: Int): IntTensor { - val shape = asIntTensor().shape - val buffer = IntArray(asIntTensor().numElements) { value } + public fun fullLike(structureND: StructureND<*>, value: Int): IntTensor { + val shape = structureND.shape + val buffer = IntBuffer(structureND.indices.linearSize) { value } return IntTensor(shape, buffer) } @@ -163,7 +167,7 @@ public open class IntTensorAlgebra : TensorAlgebra { * * @return tensor filled with the scalar value `0`, with the same shape as `input` tensor. */ - public fun StructureND.zeroesLike(): IntTensor = asIntTensor().fullLike(0) + public fun zeroesLike(structureND: StructureND): IntTensor = fullLike(structureND.asIntTensor(), 0) /** * Returns a tensor filled with the scalar value `1`, with the shape defined by the variable argument [shape]. @@ -178,7 +182,7 @@ public open class IntTensorAlgebra : TensorAlgebra { * * @return tensor filled with the scalar value `1`, with the same shape as `input` tensor. */ - public fun Tensor.onesLike(): IntTensor = asIntTensor().fullLike(1) + public fun onesLike(structureND: Tensor<*>): IntTensor = fullLike(structureND, 1) /** * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. @@ -188,7 +192,7 @@ public open class IntTensorAlgebra : TensorAlgebra { */ public fun eye(n: Int): IntTensor { val shape = intArrayOf(n, n) - val buffer = IntArray(n * n) { 0 } + val buffer = IntBuffer(n * n) { 0 } val res = IntTensor(shape, buffer) for (i in 0 until n) { res[intArrayOf(i, i)] = 1 @@ -196,151 +200,92 @@ public open class IntTensorAlgebra : TensorAlgebra { return res } - /** - * Return a copy of the tensor. - * - * @return a copy of the `input` tensor with a copied buffer. - */ - public fun StructureND.copy(): IntTensor = - IntTensor(asIntTensor().shape, asIntTensor().mutableBuffer.array().copyOf(), asIntTensor().bufferStart) + override fun Int.plus(arg: StructureND): IntTensor = arg.map { this@plus + it } - override fun Int.plus(arg: StructureND): IntTensor { - val resBuffer = IntArray(arg.asIntTensor().numElements) { i -> - arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] + this - } - return IntTensor(arg.shape, resBuffer) - } + override fun StructureND.plus(arg: Int): IntTensor = map { it + arg } - override fun StructureND.plus(arg: Int): IntTensor = arg + asIntTensor() - - override fun StructureND.plus(arg: StructureND): IntTensor { - checkShapesCompatible(asIntTensor(), arg.asIntTensor()) - val resBuffer = IntArray(asIntTensor().numElements) { i -> - asIntTensor().mutableBuffer.array()[i] + arg.asIntTensor().mutableBuffer.array()[i] - } - return IntTensor(asIntTensor().shape, resBuffer) - } + override fun StructureND.plus(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l + r } override fun Tensor.plusAssign(value: Int) { - for (i in 0 until asIntTensor().numElements) { - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] += value - } + mapInPlace { it + value } } override fun Tensor.plusAssign(arg: StructureND) { checkShapesCompatible(asIntTensor(), arg.asIntTensor()) - for (i in 0 until asIntTensor().numElements) { - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] += - arg.asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] + mapIndexedInPlace { index, value -> + value + arg[index] } } - override fun Int.minus(arg: StructureND): IntTensor { - val resBuffer = IntArray(arg.asIntTensor().numElements) { i -> - this - arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] - } - return IntTensor(arg.shape, resBuffer) - } + override fun Int.minus(arg: StructureND): IntTensor = arg.map { this@minus - it } - override fun StructureND.minus(arg: Int): IntTensor { - val resBuffer = IntArray(asIntTensor().numElements) { i -> - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] - arg - } - return IntTensor(asIntTensor().shape, resBuffer) - } + override fun StructureND.minus(arg: Int): IntTensor = map { it - arg } - override fun StructureND.minus(arg: StructureND): IntTensor { - checkShapesCompatible(asIntTensor(), arg) - val resBuffer = IntArray(asIntTensor().numElements) { i -> - asIntTensor().mutableBuffer.array()[i] - arg.asIntTensor().mutableBuffer.array()[i] - } - return IntTensor(asIntTensor().shape, resBuffer) - } + override fun StructureND.minus(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l + r } override fun Tensor.minusAssign(value: Int) { - for (i in 0 until asIntTensor().numElements) { - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] -= value - } + mapInPlace { it - value } } override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(asIntTensor(), arg) - for (i in 0 until asIntTensor().numElements) { - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] -= - arg.asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] - } + checkShapesCompatible(this, arg) + mapIndexedInPlace { index, value -> value - arg[index] } } - override fun Int.times(arg: StructureND): IntTensor { - val resBuffer = IntArray(arg.asIntTensor().numElements) { i -> - arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] * this - } - return IntTensor(arg.shape, resBuffer) - } + override fun Int.times(arg: StructureND): IntTensor = arg.map { this@times * it } override fun StructureND.times(arg: Int): IntTensor = arg * asIntTensor() - override fun StructureND.times(arg: StructureND): IntTensor { - checkShapesCompatible(asIntTensor(), arg) - val resBuffer = IntArray(asIntTensor().numElements) { i -> - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] * - arg.asIntTensor().mutableBuffer.array()[arg.asIntTensor().bufferStart + i] - } - return IntTensor(asIntTensor().shape, resBuffer) - } + override fun StructureND.times(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l * r } override fun Tensor.timesAssign(value: Int) { - for (i in 0 until asIntTensor().numElements) { - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] *= value - } + mapInPlace { it * value } } override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(asIntTensor(), arg) - for (i in 0 until asIntTensor().numElements) { - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] *= - arg.asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i] - } + checkShapesCompatible(this, arg) + mapIndexedInPlace { index, value -> value * arg[index] } } - override fun StructureND.unaryMinus(): IntTensor { - val resBuffer = IntArray(asIntTensor().numElements) { i -> - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + i].unaryMinus() - } - return IntTensor(asIntTensor().shape, resBuffer) - } + override fun StructureND.unaryMinus(): IntTensor = map { -it } - override fun Tensor.transpose(i: Int, j: Int): IntTensor { - val ii = asIntTensor().minusIndex(i) - val jj = asIntTensor().minusIndex(j) - checkTranspose(asIntTensor().dimension, ii, jj) - val n = asIntTensor().numElements + override fun Tensor.transposed(i: Int, j: Int): IntTensor { + // TODO change strides instead of changing content + val dt = asIntTensor() + val ii = dt.minusIndex(i) + val jj = dt.minusIndex(j) + checkTranspose(dt.dimension, ii, jj) + val n = dt.linearSize val resBuffer = IntArray(n) - val resShape = asIntTensor().shape.copyOf() + val resShape = dt.shape.copyOf() resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } - val resTensor = IntTensor(resShape, resBuffer) + val resTensor = IntTensor(resShape, resBuffer.asBuffer()) for (offset in 0 until n) { - val oldMultiIndex = asIntTensor().indices.index(offset) + val oldMultiIndex = dt.indices.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } val linearIndex = resTensor.indices.offset(newMultiIndex) - resTensor.mutableBuffer.array()[linearIndex] = - asIntTensor().mutableBuffer.array()[asIntTensor().bufferStart + offset] + resTensor.source[linearIndex] = dt.source[offset] } return resTensor } override fun Tensor.view(shape: IntArray): IntTensor { checkView(asIntTensor(), shape) - return IntTensor(shape, asIntTensor().mutableBuffer.array(), asIntTensor().bufferStart) + return IntTensor(shape, asIntTensor().source) } override fun Tensor.viewAs(other: StructureND): IntTensor = - asIntTensor().view(other.shape) + view(other.shape) + + override fun StructureND.dot(other: StructureND): IntTensor { + return if (dimension in 0..2 && other.dimension in 0..2) TODO("not implemented") + else error("Only vectors and matrices are allowed in non-broadcasting dot operation") + } override fun diagonalEmbedding( diagonalEntries: Tensor, @@ -374,7 +319,7 @@ public open class IntTensorAlgebra : TensorAlgebra { diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() val resTensor = zeros(resShape) - for (i in 0 until diagonalEntries.asIntTensor().numElements) { + for (i in 0 until diagonalEntries.asIntTensor().linearSize) { val multiIndex = diagonalEntries.asIntTensor().indices.index(i) var offset1 = 0 @@ -394,16 +339,27 @@ public open class IntTensorAlgebra : TensorAlgebra { return resTensor.asIntTensor() } - private infix fun Tensor.eq( + /** + * Compares element-wise two int tensors + * + * @param other the tensor to compare with `input` tensor. + * @param epsilon permissible error when comparing two Int values. + * @return true if two tensors have the same shape and elements, false otherwise. + */ + public fun Tensor.eq(other: Tensor): Boolean = + asIntTensor().eq(other) { x, y -> x == y } + + private fun Tensor.eq( other: Tensor, + eqFunction: (Int, Int) -> Boolean, ): Boolean { checkShapesCompatible(asIntTensor(), other) - val n = asIntTensor().numElements - if (n != other.asIntTensor().numElements) { + val n = asIntTensor().linearSize + if (n != other.asIntTensor().linearSize) { return false } for (i in 0 until n) { - if (asIntTensor().mutableBuffer[asIntTensor().bufferStart + i] != other.asIntTensor().mutableBuffer[other.asIntTensor().bufferStart + i]) { + if (!eqFunction(asIntTensor().source[i], other.asIntTensor().source[i])) { return false } } @@ -421,10 +377,12 @@ public open class IntTensorAlgebra : TensorAlgebra { val shape = tensors[0].shape check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape - val resBuffer = tensors.flatMap { - it.asIntTensor().mutableBuffer.array().drop(it.asIntTensor().bufferStart).take(it.asIntTensor().numElements) - }.toIntArray() - return IntTensor(resShape, resBuffer, 0) +// val resBuffer: List = tensors.flatMap { +// it.asIntTensor().source.array.drop(it.asIntTensor().bufferStart) +// .take(it.asIntTensor().linearSize) +// } + val resBuffer = tensors.map { it.asIntTensor().source }.concat() + return IntTensor(resShape, resBuffer) } /** @@ -435,14 +393,11 @@ public open class IntTensorAlgebra : TensorAlgebra { */ public fun Tensor.rowsByIndices(indices: IntArray): IntTensor = stack(indices.map { getTensor(it) }) - private inline fun StructureND.fold(foldFunction: (IntArray) -> Int): Int = - foldFunction(asIntTensor().copyArray()) - - private inline fun StructureND.foldDim( + private inline fun StructureND.foldDimToInt( dim: Int, keepDim: Boolean, - foldFunction: (IntArray) -> R, - ): BufferedTensor { + foldFunction: (IntArray) -> Int, + ): IntTensor { check(dim < dimension) { "Dimension $dim out of range $dimension" } val resShape = if (keepDim) { shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() @@ -451,9 +406,9 @@ public open class IntTensorAlgebra : TensorAlgebra { } val resNumElements = resShape.reduce(Int::times) val init = foldFunction(IntArray(1) { 0 }) - val resTensor = BufferedTensor( + val resTensor = IntTensor( resShape, - MutableBuffer.auto(resNumElements) { init }, 0 + IntBuffer(resNumElements) { init } ) for (index in resTensor.indices) { val prefix = index.take(dim).toIntArray() @@ -465,31 +420,33 @@ public open class IntTensorAlgebra : TensorAlgebra { return resTensor } - override fun StructureND.sum(): Int = asIntTensor().fold { it.sum() } + + override fun StructureND.sum(): Int = reduceElements { it.array.sum() } override fun StructureND.sum(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> x.sum() }.asIntTensor() + foldDimToInt(dim, keepDim) { x -> x.sum() } - override fun StructureND.min(): Int = this.fold { it.minOrNull()!! } + override fun StructureND.min(): Int = reduceElements { it.array.min() } override fun StructureND.min(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> x.minOrNull()!! }.asIntTensor() + foldDimToInt(dim, keepDim) { x -> x.minOrNull()!! } - override fun StructureND.argMin(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> - x.withIndex().minByOrNull { it.value }?.index!! - }.asIntTensor() + override fun StructureND.argMin(dim: Int, keepDim: Boolean): Tensor = foldDimToInt(dim, keepDim) { x -> + x.withIndex().minBy { it.value }.index + } - override fun StructureND.max(): Int = this.fold { it.maxOrNull()!! } + override fun StructureND.max(): Int = reduceElements { it.array.max() } override fun StructureND.max(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.asIntTensor() + foldDimToInt(dim, keepDim) { x -> x.max() } override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> - x.withIndex().maxByOrNull { it.value }?.index!! - }.asIntTensor() + foldDimToInt(dim, keepDim) { x -> + x.withIndex().maxBy { it.value }.index + } + + public fun StructureND.mean(): Double = sum().toDouble() / indices.linearSize } public val Int.Companion.tensorAlgebra: IntTensorAlgebra get() = IntTensorAlgebra diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt index ab97903e4..fee62c79c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors.core.internal +import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.tensors.core.DoubleTensor import kotlin.math.max @@ -24,8 +25,8 @@ internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTenso } val curLinearIndex = tensor.indices.offset(curMultiIndex) - resTensor.mutableBuffer.array()[linearIndex] = - tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex] + resTensor.source[linearIndex] = + tensor.source[curLinearIndex] } } @@ -63,7 +64,7 @@ internal fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor } val n = newShape.reduce { acc, i -> acc * i } - val resTensor = DoubleTensor(newShape, DoubleArray(n)) + val resTensor = DoubleTensor(newShape, DoubleArray(n).asBuffer()) for (i in tensor.shape.indices) { val curDim = tensor.shape[i] @@ -82,7 +83,7 @@ internal fun broadcastTensors(vararg tensors: DoubleTensor): List val n = totalShape.reduce { acc, i -> acc * i } return tensors.map { tensor -> - val resTensor = DoubleTensor(totalShape, DoubleArray(n)) + val resTensor = DoubleTensor(totalShape, DoubleArray(n).asBuffer()) multiIndexBroadCasting(tensor, resTensor, n) resTensor } @@ -106,17 +107,17 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List checkShapesCompatible(a: StructureND, b: StructureND) = +@PublishedApi +internal fun checkShapesCompatible(a: StructureND, b: StructureND): Unit = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } @@ -50,15 +52,14 @@ internal fun checkSquareMatrix(shape: IntArray) { internal fun DoubleTensorAlgebra.checkSymmetric( tensor: Tensor, epsilon: Double = 1e-6, -) = - check(tensor.eq(tensor.transpose(), epsilon)) { - "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" - } +) = check(tensor.eq(tensor.transposed(), epsilon)) { + "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" +} internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { checkSymmetric(tensor, epsilon) for (mat in tensor.matrixSequence()) - check(mat.toTensor().detLU().value() > 0.0) { - "Tensor contains matrices which are not positive definite ${mat.toTensor().detLU().value()}" + check(mat.asDoubleTensor().detLU().value() > 0.0) { + "Tensor contains matrices which are not positive definite ${mat.asDoubleTensor().detLU().value()}" } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt new file mode 100644 index 000000000..9c6f54d61 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt @@ -0,0 +1,189 @@ +/* + * Copyright 2018-2022 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.tensors.core.internal + +import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.Structure2D +import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.get +import space.kscience.kmath.operations.asSequence +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.VirtualBuffer +import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.indices +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.eye +import space.kscience.kmath.tensors.core.BufferedTensor +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.OffsetDoubleBuffer +import space.kscience.kmath.tensors.core.copyToTensor +import kotlin.math.abs +import kotlin.math.max +import kotlin.math.sqrt + + +internal fun MutableStructure2D.jacobiHelper( + maxIteration: Int, + epsilon: Double, +): Pair> { + val n = rowNum + val A_ = copyToTensor() + val V = eye(n) + val D = DoubleBuffer(n) { get(it, it) } + val B = DoubleBuffer(n) { get(it, it) } + val Z = DoubleBuffer(n) { 0.0 } + + // assume that buffered tensor is square matrix + operator fun DoubleTensor.get(i: Int, j: Int): Double { + return source[i * shape[0] + j] + } + + operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { + source[i * shape[0] + j] = value + } + + fun maxOffDiagonal(matrix: BufferedTensor): Double { + var maxOffDiagonalElement = 0.0 + for (i in 0 until n - 1) { + for (j in i + 1 until n) { + maxOffDiagonalElement = max(maxOffDiagonalElement, abs(matrix[i, j])) + } + } + return maxOffDiagonalElement + } + + fun rotate(a: BufferedTensor, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { + val g = a[i, j] + val h = a[k, l] + a[i, j] = g - s * (h + g * tau) + a[k, l] = h + s * (g - h * tau) + } + + fun jacobiIteration( + a: BufferedTensor, + v: BufferedTensor, + d: DoubleBuffer, + z: DoubleBuffer, + ) { + for (ip in 0 until n - 1) { + for (iq in ip + 1 until n) { + val g = 100.0 * abs(a[ip, iq]) + + if (g <= epsilon * abs(d[ip]) && g <= epsilon * abs(d[iq])) { + a[ip, iq] = 0.0 + continue + } + + var h = d[iq] - d[ip] + val t = when { + g <= epsilon * abs(h) -> (a[ip, iq]) / h + else -> { + val theta = 0.5 * h / (a[ip, iq]) + val denominator = abs(theta) + sqrt(1.0 + theta * theta) + if (theta < 0.0) -1.0 / denominator else 1.0 / denominator + } + } + + val c = 1.0 / sqrt(1 + t * t) + val s = t * c + val tau = s / (1.0 + c) + h = t * a[ip, iq] + z[ip] -= h + z[iq] += h + d[ip] -= h + d[iq] += h + a[ip, iq] = 0.0 + + for (j in 0 until ip) { + rotate(a, s, tau, j, ip, j, iq) + } + for (j in (ip + 1) until iq) { + rotate(a, s, tau, ip, j, j, iq) + } + for (j in (iq + 1) until n) { + rotate(a, s, tau, ip, j, iq, j) + } + for (j in 0 until n) { + rotate(v, s, tau, j, ip, j, iq) + } + } + } + } + + fun updateDiagonal( + d: DoubleBuffer, + z: DoubleBuffer, + b: DoubleBuffer, + ) { + for (ip in 0 until d.size) { + b[ip] += z[ip] + d[ip] = b[ip] + z[ip] = 0.0 + } + } + + var sm = maxOffDiagonal(A_) + for (iteration in 0 until maxIteration) { + if (sm < epsilon) { + break + } + + jacobiIteration(A_, V, D, Z) + updateDiagonal(D, Z, B) + sm = maxOffDiagonal(A_) + } + + // TODO sort eigenvalues + return D to V.as2D() +} + +/** + * Concatenate a list of arrays + */ +internal fun List.concat(): DoubleBuffer { + val array = DoubleArray(sumOf { it.size }) + var pointer = 0 + while (pointer < array.size) { + for (bufferIndex in indices) { + val buffer = get(bufferIndex) + for (innerIndex in buffer.indices) { + array[pointer] = buffer[innerIndex] + pointer++ + } + } + } + return array.asBuffer() +} + +internal val DoubleTensor.vectors: VirtualBuffer + get() { + val n = shape.size + val vectorOffset = shape[n - 1] + val vectorShape = intArrayOf(shape.last()) + + return VirtualBuffer(linearSize / vectorOffset) { index -> + val offset = index * vectorOffset + DoubleTensor(vectorShape, source.view(offset)) + } + } + + +internal fun DoubleTensor.vectorSequence(): Sequence = vectors.asSequence() + + +internal val DoubleTensor.matrices: VirtualBuffer + get(){ + val n = shape.size + check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } + val matrixOffset = shape[n - 1] * shape[n - 2] + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) + + return VirtualBuffer(linearSize / matrixOffset) { index -> + val offset = index * matrixOffset + DoubleTensor(matrixShape, source.view(offset)) + } +} + +internal fun DoubleTensor.matrixSequence(): Sequence = matrices.asSequence() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt new file mode 100644 index 000000000..93229c2d4 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2018-2022 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.tensors.core.internal + +import space.kscience.kmath.operations.asSequence +import space.kscience.kmath.structures.IntBuffer +import space.kscience.kmath.structures.VirtualBuffer +import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.indices +import space.kscience.kmath.tensors.core.IntTensor +import space.kscience.kmath.tensors.core.OffsetIntBuffer + +/** + * Concatenate a list of arrays + */ +internal fun List.concat(): IntBuffer { + val array = IntArray(sumOf { it.size }) + var pointer = 0 + while (pointer < array.size) { + for (bufferIndex in indices) { + val buffer = get(bufferIndex) + for (innerIndex in buffer.indices) { + array[pointer] = buffer[innerIndex] + pointer++ + } + } + } + return array.asBuffer() +} + + +internal val IntTensor.vectors: VirtualBuffer + get() { + val n = shape.size + val vectorOffset = shape[n - 1] + val vectorShape = intArrayOf(shape.last()) + + return VirtualBuffer(linearSize / vectorOffset) { index -> + val offset = index * vectorOffset + IntTensor(vectorShape, source.view(offset)) + } + } + + +internal fun IntTensor.vectorSequence(): Sequence = vectors.asSequence() + + +internal val IntTensor.matrices: VirtualBuffer + get(){ + val n = shape.size + check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } + val matrixOffset = shape[n - 1] * shape[n - 2] + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) + + return VirtualBuffer(linearSize / matrixOffset) { index -> + val offset = index * matrixOffset + IntTensor(matrixShape, source.view(offset)) + } + } + +internal fun IntTensor.matrixSequence(): Sequence = matrices.asSequence() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index ec529590f..9047ba29e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -5,75 +5,33 @@ package space.kscience.kmath.tensors.core.internal -import space.kscience.kmath.nd.MutableStructure1D -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.operations.asSequence +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.IntTensor +import space.kscience.kmath.structures.IntBuffer +import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.indices +import space.kscience.kmath.tensors.core.* import kotlin.math.abs import kotlin.math.min import kotlin.math.sqrt -internal val BufferedTensor.vectors: VirtualBuffer> - get() { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = intArrayOf(shape.last()) - - return VirtualBuffer(numElements / vectorOffset) { index -> - val offset = index * vectorOffset - BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) - } - } - - -internal fun BufferedTensor.vectorSequence(): Sequence> = vectors.asSequence() - -/** - * A random access alternative to [matrixSequence] - */ -internal val BufferedTensor.matrices: VirtualBuffer> - get() { - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) - - return VirtualBuffer(numElements / matrixOffset) { index -> - val offset = index * matrixOffset - BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) - } - } - -internal fun BufferedTensor.matrixSequence(): Sequence> = matrices.asSequence() - internal fun dotTo( a: BufferedTensor, b: BufferedTensor, res: BufferedTensor, l: Int, m: Int, n: Int, ) { - val aStart = a.bufferStart - val bStart = b.bufferStart - val resStart = res.bufferStart - - val aBuffer = a.mutableBuffer - val bBuffer = b.mutableBuffer - val resBuffer = res.mutableBuffer + val aBuffer = a.source + val bBuffer = b.source + val resBuffer = res.source for (i in 0 until l) { for (j in 0 until n) { var curr = 0.0 for (k in 0 until m) { - curr += aBuffer[aStart + i * m + k] * bBuffer[bStart + k * n + j] + curr += aBuffer[i * m + k] * bBuffer[k * n + j] } - resBuffer[resStart + i * n + j] = curr + resBuffer[i * n + j] = curr } } } @@ -129,7 +87,7 @@ internal fun luHelper( return false } -internal fun BufferedTensor.setUpPivots(): IntTensor { +internal fun StructureND.setUpPivots(): IntTensor { val n = this.shape.size val m = this.shape.last() val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } @@ -137,17 +95,17 @@ internal fun BufferedTensor.setUpPivots(): IntTensor { return IntTensor( pivotsShape, - IntArray(pivotsShape.reduce(Int::times)) { 0 } + IntBuffer(pivotsShape.reduce(Int::times)) { 0 } ) } internal fun DoubleTensorAlgebra.computeLU( - tensor: DoubleTensor, + tensor: StructureND, epsilon: Double, ): Pair? { checkSquareMatrix(tensor.shape) - val luTensor = tensor.copy() + val luTensor = tensor.copyToTensor() val pivotsTensor = tensor.setUpPivots() for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) @@ -253,8 +211,8 @@ internal fun DoubleTensorAlgebra.qrHelper( checkSquareMatrix(matrix.shape) val n = matrix.shape[0] val qM = q.as2D() - val matrixT = matrix.transpose(0, 1) - val qT = q.transpose(0, 1) + val matrixT = matrix.transposed(0, 1) + val qT = q.transposed(0, 1) for (j in 0 until n) { val v = matrixT.getTensor(j) @@ -280,10 +238,10 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10) var v: DoubleTensor val b: DoubleTensor if (n > m) { - b = a.transpose(0, 1).dot(a) + b = a.transposed(0, 1).dot(a) v = DoubleTensor(intArrayOf(m), getRandomUnitVector(m, 0)) } else { - b = a.dot(a.transpose(0, 1)) + b = a.dot(a.transposed(0, 1)) v = DoubleTensor(intArrayOf(n), getRandomUnitVector(n, 0)) } @@ -308,7 +266,7 @@ internal fun DoubleTensorAlgebra.svdHelper( val (matrixU, matrixS, matrixV) = USV for (k in 0 until min(n, m)) { - var a = matrix.copy() + var a = matrix.copyToTensor() for ((singularValue, u, v) in res.slice(0 until k)) { val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) for (i in 0 until u.shape[0]) { @@ -316,7 +274,7 @@ internal fun DoubleTensorAlgebra.svdHelper( outerProduct[i * v.shape[0] + j] = u.getTensor(i).value() * v.getTensor(j).value() } } - a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) + a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct.asBuffer())) } var v: DoubleTensor var u: DoubleTensor @@ -328,7 +286,7 @@ internal fun DoubleTensorAlgebra.svdHelper( u = u.times(1.0 / norm) } else { u = svd1d(a, epsilon) - v = matrix.transpose(0, 1).dot(u) + v = matrix.transposed(0, 1).dot(u) norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } v = v.times(1.0 / norm) } @@ -337,15 +295,15 @@ internal fun DoubleTensorAlgebra.svdHelper( } val s = res.map { it.first }.toDoubleArray() - val uBuffer = res.map { it.second }.flatMap { it.mutableBuffer.array().toList() }.toDoubleArray() - val vBuffer = res.map { it.third }.flatMap { it.mutableBuffer.array().toList() }.toDoubleArray() + val uBuffer = res.map { it.second.source }.concat() + val vBuffer = res.map { it.third.source }.concat() for (i in uBuffer.indices) { - matrixU.mutableBuffer.array()[matrixU.bufferStart + i] = uBuffer[i] + matrixU.source[i] = uBuffer[i] } for (i in s.indices) { - matrixS.mutableBuffer.array()[matrixS.bufferStart + i] = s[i] + matrixS.source[i] = s[i] } for (i in vBuffer.indices) { - matrixV.mutableBuffer.array()[matrixV.bufferStart + i] = vBuffer[i] + matrixV.source[i] = vBuffer[i] } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt deleted file mode 100644 index e7704b257..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2018-2022 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.tensors.core.internal - -import space.kscience.kmath.nd.MutableBufferND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.structures.asMutableBuffer -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.IntTensor -import space.kscience.kmath.tensors.core.TensorLinearStructure - -internal fun BufferedTensor.toTensor(): IntTensor = - IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) - -internal fun BufferedTensor.toTensor(): DoubleTensor = - DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) - -internal fun StructureND.copyToBufferedTensor(): BufferedTensor = - BufferedTensor( - this.shape, - TensorLinearStructure(this.shape).asSequence().map(this::get).toMutableList().asMutableBuffer(), - 0 - ) - -internal fun StructureND.toBufferedTensor(): BufferedTensor = when (this) { - is BufferedTensor -> this - is MutableBufferND -> if (this.indices == TensorLinearStructure(this.shape)) { - BufferedTensor(this.shape, this.buffer, 0) - } else { - this.copyToBufferedTensor() - } - else -> this.copyToBufferedTensor() -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt index 8a96d516f..daafdaa58 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt @@ -6,41 +6,25 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.as1D +import space.kscience.kmath.operations.DoubleBufferOps.Companion.map import space.kscience.kmath.operations.toMutableList import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.* +import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.tensors.core.BufferedTensor import space.kscience.kmath.tensors.core.DoubleTensor import kotlin.math.* -/** - * Returns a reference to [IntArray] containing all the elements of this [Buffer] or copy the data. - */ -internal fun Buffer.array(): IntArray = when (this) { - is IntBuffer -> array - else -> this.toIntArray() -} - -/** - * Returns a reference to [DoubleArray] containing all the elements of this [Buffer] or copy the data. - */ -@PublishedApi -internal fun Buffer.array(): DoubleArray = when (this) { - is DoubleBuffer -> array - else -> this.toDoubleArray() -} - -internal fun getRandomNormals(n: Int, seed: Long): DoubleArray { +internal fun getRandomNormals(n: Int, seed: Long): DoubleBuffer { val distribution = GaussianSampler(0.0, 1.0) val generator = RandomGenerator.default(seed) - return distribution.sample(generator).nextBufferBlocking(n).toDoubleArray() + return distribution.sample(generator).nextBufferBlocking(n) } -internal fun getRandomUnitVector(n: Int, seed: Long): DoubleArray { - val unnorm = getRandomNormals(n, seed) - val norm = sqrt(unnorm.sumOf { it * it }) - return unnorm.map { it / norm }.toDoubleArray() +internal fun getRandomUnitVector(n: Int, seed: Long): DoubleBuffer { + val unnorm: DoubleBuffer = getRandomNormals(n, seed) + val norm = sqrt(unnorm.array.sumOf { it * it }) + return unnorm.map { it / norm } } internal fun minusIndexFrom(n: Int, i: Int): Int = if (i >= 0) i else { @@ -71,6 +55,7 @@ internal fun format(value: Double, digits: Int = 4): String = buildString { append("e+") append(order) } + else -> { append('e') append(order) @@ -116,7 +101,7 @@ internal fun DoubleTensor.toPrettyString(): String = buildString { } offset += vectorSize - if (this@toPrettyString.numElements == offset) { + if (this@toPrettyString.linearSize == offset) { break } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt deleted file mode 100644 index 1c914d474..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2022 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.tensors.core - -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.toBufferedTensor -import space.kscience.kmath.tensors.core.internal.toTensor - -/** - * Casts [Tensor] of [Double] to [DoubleTensor] - */ -public fun StructureND.asDoubleTensor(): DoubleTensor = when (this) { - is DoubleTensor -> this - else -> this.toBufferedTensor().toTensor() -} - -/** - * Casts [Tensor] of [Int] to [IntTensor] - */ -public fun StructureND.asIntTensor(): IntTensor = when (this) { - is IntTensor -> this - else -> this.toBufferedTensor().toTensor() -} - -/** - * Returns a copy-protected [DoubleArray] of tensor elements - */ -public fun DoubleTensor.copyArray(): DoubleArray { - //TODO use ArrayCopy - return DoubleArray(numElements) { i -> - mutableBuffer[bufferStart + i] - } -} - -/** - * Returns a copy-protected [IntArray] of tensor elements - */ -public fun IntTensor.copyArray(): IntArray { - return IntArray(numElements) { i -> - mutableBuffer[bufferStart + i] - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt new file mode 100644 index 000000000..30a828d6a --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2018-2022 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.tensors.core + +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.tensors.api.Tensor + + +public fun StructureND.copyToTensor(): DoubleTensor = if (this is DoubleTensor) { + DoubleTensor(shape, source.copy()) +} else { + DoubleTensor( + shape, + TensorLinearStructure(this.shape).map(this::get).toDoubleArray().asBuffer(), + ) +} + +public fun StructureND.toDoubleTensor(): DoubleTensor { + return if (this is IntTensor) { + DoubleTensor( + shape, + DoubleBuffer(linearSize) { source[it].toDouble() } + ) + } else { + val tensor = DoubleTensorAlgebra.zeroesLike(this) + indices.forEach { + tensor[it] = get(it).toDouble() + } + return tensor + } +} + +/** + * Casts [Tensor] of [Double] to [DoubleTensor] + */ +public fun StructureND.asDoubleTensor(): DoubleTensor = when (this) { + is DoubleTensor -> this + else -> copyToTensor() +} + +/** + * Casts [Tensor] of [Int] to [IntTensor] + */ +public fun StructureND.asIntTensor(): IntTensor = when (this) { + is IntTensor -> this + else -> IntTensor( + this.shape, + TensorLinearStructure(this.shape).map(this::get).toIntArray().asBuffer() + ) +} \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 67d5f9a96..6a99b9ba8 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -6,7 +6,10 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.* +import space.kscience.kmath.tensors.core.internal.broadcastOuterTensors +import space.kscience.kmath.tensors.core.internal.broadcastShapes +import space.kscience.kmath.tensors.core.internal.broadcastTensors +import space.kscience.kmath.tensors.core.internal.broadcastTo import kotlin.test.Test import kotlin.test.assertTrue @@ -34,7 +37,7 @@ internal class TestBroadcasting { val res = broadcastTo(tensor2, tensor1.shape) assertTrue(res.shape contentEquals intArrayOf(2, 3)) - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) + assertTrue(res.source contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) } @Test @@ -49,9 +52,9 @@ internal class TestBroadcasting { assertTrue(res[1].shape contentEquals intArrayOf(1, 2, 3)) assertTrue(res[2].shape contentEquals intArrayOf(1, 2, 3)) - assertTrue(res[0].mutableBuffer.array() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].mutableBuffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - assertTrue(res[2].mutableBuffer.array() contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0)) + assertTrue(res[0].source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + assertTrue(res[1].source contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) + assertTrue(res[2].source contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0)) } @Test @@ -66,15 +69,15 @@ internal class TestBroadcasting { assertTrue(res[1].shape contentEquals intArrayOf(1, 1, 3)) assertTrue(res[2].shape contentEquals intArrayOf(1, 1, 1)) - assertTrue(res[0].mutableBuffer.array() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].mutableBuffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0)) - assertTrue(res[2].mutableBuffer.array() contentEquals doubleArrayOf(500.0)) + assertTrue(res[0].source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + assertTrue(res[1].source contentEquals doubleArrayOf(10.0, 20.0, 30.0)) + assertTrue(res[2].source contentEquals doubleArrayOf(500.0)) } @Test fun testBroadcastOuterTensorsShapes() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) {0.0}) - val tensor2 = fromArray(intArrayOf(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) {0.0}) + val tensor1 = fromArray(intArrayOf(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) { 0.0 }) + val tensor2 = fromArray(intArrayOf(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) { 0.0 }) val tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0)) val res = broadcastOuterTensors(tensor1, tensor2, tensor3) @@ -95,16 +98,16 @@ internal class TestBroadcasting { val tensor32 = tensor3 - tensor2 assertTrue(tensor21.shape contentEquals intArrayOf(2, 3)) - assertTrue(tensor21.mutableBuffer.array() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) + assertTrue(tensor21.source contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) assertTrue(tensor31.shape contentEquals intArrayOf(1, 2, 3)) assertTrue( - tensor31.mutableBuffer.array() + tensor31.source contentEquals doubleArrayOf(499.0, 498.0, 497.0, 496.0, 495.0, 494.0) ) assertTrue(tensor32.shape contentEquals intArrayOf(1, 1, 3)) - assertTrue(tensor32.mutableBuffer.array() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) + assertTrue(tensor32.source contentEquals doubleArrayOf(490.0, 480.0, 470.0)) } } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index c777273f3..4bc2e3bdb 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.asBuffer import kotlin.math.* import kotlin.test.Test import kotlin.test.assertTrue @@ -20,14 +21,14 @@ internal class TestDoubleAnalyticTensorAlgebra { 3.23, 133.7, 25.3, 100.3, 11.0, 12.012 ) - val tensor = DoubleTensor(shape, buffer) + val tensor = DoubleTensor(shape, buffer.asBuffer()) fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray { return this.map(transform).toDoubleArray() } fun expectedTensor(transform: (Double) -> Double): DoubleTensor { - return DoubleTensor(shape, buffer.fmap(transform)) + return DoubleTensor(shape, buffer.fmap(transform).asBuffer()) } @Test @@ -106,58 +107,74 @@ internal class TestDoubleAnalyticTensorAlgebra { 1.0, 2.0, -3.0, 4.0 ) - val tensor2 = DoubleTensor(shape2, buffer2) + val tensor2 = DoubleTensor(shape2, buffer2.asBuffer()) @Test fun testMin() = DoubleTensorAlgebra { assertTrue { tensor2.min() == -3.0 } - assertTrue { tensor2.min(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(-3.0, 2.0) - )} - assertTrue { tensor2.min(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(1.0, -3.0) - )} + assertTrue { + tensor2.min(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(-3.0, 2.0) + ) + } + assertTrue { + tensor2.min(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(1.0, -3.0) + ) + } } @Test fun testMax() = DoubleTensorAlgebra { assertTrue { tensor2.max() == 4.0 } - assertTrue { tensor2.max(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(1.0, 4.0) - )} - assertTrue { tensor2.max(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(2.0, 4.0) - )} + assertTrue { + tensor2.max(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(1.0, 4.0) + ) + } + assertTrue { + tensor2.max(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(2.0, 4.0) + ) + } } @Test fun testSum() = DoubleTensorAlgebra { assertTrue { tensor2.sum() == 4.0 } - assertTrue { tensor2.sum(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(-2.0, 6.0) - )} - assertTrue { tensor2.sum(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(3.0, 1.0) - )} + assertTrue { + tensor2.sum(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(-2.0, 6.0) + ) + } + assertTrue { + tensor2.sum(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(3.0, 1.0) + ) + } } @Test fun testMean() = DoubleTensorAlgebra { assertTrue { tensor2.mean() == 1.0 } - assertTrue { tensor2.mean(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(-1.0, 3.0) - )} - assertTrue { tensor2.mean(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(1.5, 0.5) - )} + assertTrue { + tensor2.mean(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(-1.0, 3.0) + ) + } + assertTrue { + tensor2.mean(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(1.5, 0.5) + ) + } } } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 5b226bd5d..1c23cff18 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -6,7 +6,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.svd1d import kotlin.math.abs import kotlin.test.Test @@ -142,11 +141,11 @@ internal class TestDoubleLinearOpsTensorAlgebra { @Test fun testCholesky() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 5), 0) - val sigma = (tensor matmul tensor.transpose()) + diagonalEmbedding( + val sigma = (tensor matmul tensor.transposed()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) ) val low = sigma.cholesky() - val sigmChol = low matmul low.transpose() + val sigmChol = low matmul low.transposed() assertTrue(sigma.eq(sigmChol)) } @@ -157,12 +156,12 @@ internal class TestDoubleLinearOpsTensorAlgebra { val res = svd1d(tensor2) assertTrue(res.shape contentEquals intArrayOf(2)) - assertTrue { abs(abs(res.mutableBuffer.array()[res.bufferStart]) - 0.386) < 0.01 } - assertTrue { abs(abs(res.mutableBuffer.array()[res.bufferStart + 1]) - 0.922) < 0.01 } + assertTrue { abs(abs(res.source[0]) - 0.386) < 0.01 } + assertTrue { abs(abs(res.source[1]) - 0.922) < 0.01 } } @Test - fun testSVD() = DoubleTensorAlgebra{ + fun testSVD() = DoubleTensorAlgebra { testSVDFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))) testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) } @@ -171,16 +170,16 @@ internal class TestDoubleLinearOpsTensorAlgebra { fun testBatchedSVD() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() - val tensorSVD = tensorU matmul (diagonalEmbedding(tensorS) matmul tensorV.transpose()) + val tensorSVD = tensorU matmul (diagonalEmbedding(tensorS) matmul tensorV.transposed()) assertTrue(tensor.eq(tensorSVD)) } @Test fun testBatchedSymEig() = DoubleTensorAlgebra { val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) - val tensorSigma = tensor + tensor.transpose() + val tensorSigma = tensor + tensor.transposed() val (tensorS, tensorV) = tensorSigma.symEig() - val tensorSigmaCalc = tensorV matmul (diagonalEmbedding(tensorS) matmul tensorV.transpose()) + val tensorSigmaCalc = tensorV matmul (diagonalEmbedding(tensorS) matmul tensorV.transposed()) assertTrue(tensorSigma.eq(tensorSigmaCalc)) } @@ -194,7 +193,7 @@ private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double val tensorSVD = svd.first .dot( diagonalEmbedding(svd.second) - .dot(svd.third.transpose()) + .dot(svd.third.transposed()) ) assertTrue(tensor.eq(tensorSVD, epsilon)) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index efdf6ba81..a36f32ac9 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -13,10 +13,7 @@ import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.toDoubleArray -import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.matrixSequence -import space.kscience.kmath.tensors.core.internal.toBufferedTensor -import space.kscience.kmath.tensors.core.internal.toTensor import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -37,7 +34,7 @@ internal class TestDoubleTensor { assertEquals(tensor[intArrayOf(0, 1)], 5.8) assertTrue( tensor.elements().map { it.second }.toList() - .toDoubleArray() contentEquals tensor.mutableBuffer.toDoubleArray() + .toDoubleArray() contentEquals tensor.source.toDoubleArray() ) } @@ -57,9 +54,9 @@ internal class TestDoubleTensor { assertEquals(tensor[intArrayOf(0, 1, 0)], 109.56) tensor.matrixSequence().forEach { - val a = it.toTensor() + val a = it.asDoubleTensor() val secondRow = a.getTensor(1).as1D() - val secondColumn = a.transpose(0, 1).getTensor(1).as1D() + val secondColumn = a.transposed(0, 1).getTensor(1).as1D() assertEquals(secondColumn[0], 77.89) assertEquals(secondRow[1], secondColumn[1]) } @@ -72,16 +69,16 @@ internal class TestDoubleTensor { val doubleArray = DoubleBuffer(doubleArrayOf(1.0, 2.0, 3.0)) // create ND buffers, no data is copied - val ndArray = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleArray) + val ndArray: MutableBufferND = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleArray) // map to tensors - val bufferedTensorArray = ndArray.toBufferedTensor() // strides are flipped so data copied - val tensorArray = bufferedTensorArray.toTensor() // data not contiguous so copied again + val bufferedTensorArray = ndArray.asDoubleTensor() // strides are flipped so data copied + val tensorArray = bufferedTensorArray.asDoubleTensor() // data not contiguous so copied again val tensorArrayPublic = ndArray.asDoubleTensor() // public API, data copied twice val sharedTensorArray = tensorArrayPublic.asDoubleTensor() // no data copied by matching type - assertTrue(tensorArray.mutableBuffer.array() contentEquals sharedTensorArray.mutableBuffer.array()) + assertTrue(tensorArray.source contentEquals sharedTensorArray.source) tensorArray[intArrayOf(0)] = 55.9 assertEquals(tensorArrayPublic[intArrayOf(0)], 1.0) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 28c327973..79b199471 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -6,9 +6,10 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.get import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.array import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -18,55 +19,55 @@ internal class TestDoubleTensorAlgebra { fun testDoublePlus() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(11.0, 12.0)) + assertTrue(res.source contentEquals doubleArrayOf(11.0, 12.0)) } @Test fun testDoubleDiv() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) - val res = 2.0/tensor - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) + val res = 2.0 / tensor + assertTrue(res.source contentEquals doubleArrayOf(1.0, 0.5)) } @Test fun testDivDouble() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) val res = tensor / 2.5 - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(4.0, 2.0)) + assertTrue(res.source contentEquals doubleArrayOf(4.0, 2.0)) } @Test fun testTranspose1x1() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(1), doubleArrayOf(0.0)) - val res = tensor.transpose(0, 0) + val res = tensor.transposed(0, 0) - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(0.0)) + assertTrue(res.source contentEquals doubleArrayOf(0.0)) assertTrue(res.shape contentEquals intArrayOf(1)) } @Test fun testTranspose3x2() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val res = tensor.transpose(1, 0) + val res = tensor.transposed(1, 0) - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0)) + assertTrue(res.source contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0)) assertTrue(res.shape contentEquals intArrayOf(2, 3)) } @Test fun testTranspose1x2x3() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val res01 = tensor.transpose(0, 1) - val res02 = tensor.transpose(-3, 2) - val res12 = tensor.transpose() + val res01 = tensor.transposed(0, 1) + val res02 = tensor.transposed(-3, 2) + val res12 = tensor.transposed() assertTrue(res01.shape contentEquals intArrayOf(2, 1, 3)) assertTrue(res02.shape contentEquals intArrayOf(3, 2, 1)) assertTrue(res12.shape contentEquals intArrayOf(1, 3, 2)) - assertTrue(res01.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res02.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) - assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) + assertTrue(res01.source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + assertTrue(res02.source contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) + assertTrue(res12.source contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) } @Test @@ -97,8 +98,8 @@ internal class TestDoubleTensorAlgebra { assignResult += tensorC assignResult += -39.4 - assertTrue(expected.mutableBuffer.array() contentEquals result.mutableBuffer.array()) - assertTrue(expected.mutableBuffer.array() contentEquals assignResult.mutableBuffer.array()) + assertTrue(expected.source contentEquals result.source) + assertTrue(expected.source contentEquals assignResult.source) } @Test @@ -111,26 +112,28 @@ internal class TestDoubleTensorAlgebra { val tensor5 = fromArray(intArrayOf(2, 3, 3), (1..18).map { 1 + it.toDouble() }.toDoubleArray()) val res12 = tensor1.dot(tensor2) - assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(140.0, 320.0)) + assertTrue(res12.source contentEquals doubleArrayOf(140.0, 320.0)) assertTrue(res12.shape contentEquals intArrayOf(2)) val res32 = tensor3.matmul(tensor2) - assertTrue(res32.mutableBuffer.array() contentEquals doubleArrayOf(-140.0)) + assertTrue(res32.source contentEquals doubleArrayOf(-140.0)) assertTrue(res32.shape contentEquals intArrayOf(1, 1)) val res22 = tensor2.dot(tensor2) - assertTrue(res22.mutableBuffer.array() contentEquals doubleArrayOf(1400.0)) + assertTrue(res22.source contentEquals doubleArrayOf(1400.0)) assertTrue(res22.shape contentEquals intArrayOf(1)) val res11 = tensor1.dot(tensor11) - assertTrue(res11.mutableBuffer.array() contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) + assertTrue(res11.source contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) assertTrue(res11.shape contentEquals intArrayOf(2, 2)) val res45 = tensor4.matmul(tensor5) - assertTrue(res45.mutableBuffer.array() contentEquals doubleArrayOf( - 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, - 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 - )) + assertTrue( + res45.source contentEquals doubleArrayOf( + 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, + 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 + ) + ) assertTrue(res45.shape contentEquals intArrayOf(2, 3, 3)) } @@ -140,31 +143,44 @@ internal class TestDoubleTensorAlgebra { val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor3 = zeros(intArrayOf(2, 3, 4, 5)) - assertTrue(diagonalEmbedding(tensor3, 0, 3, 4).shape contentEquals - intArrayOf(2, 3, 4, 5, 5)) - assertTrue(diagonalEmbedding(tensor3, 1, 3, 4).shape contentEquals - intArrayOf(2, 3, 4, 6, 6)) - assertTrue(diagonalEmbedding(tensor3, 2, 0, 3).shape contentEquals - intArrayOf(7, 2, 3, 7, 4)) + assertTrue( + diagonalEmbedding(tensor3, 0, 3, 4).shape contentEquals + intArrayOf(2, 3, 4, 5, 5) + ) + assertTrue( + diagonalEmbedding(tensor3, 1, 3, 4).shape contentEquals + intArrayOf(2, 3, 4, 6, 6) + ) + assertTrue( + diagonalEmbedding(tensor3, 2, 0, 3).shape contentEquals + intArrayOf(7, 2, 3, 7, 4) + ) val diagonal1 = diagonalEmbedding(tensor1, 0, 1, 0) assertTrue(diagonal1.shape contentEquals intArrayOf(3, 3)) - assertTrue(diagonal1.mutableBuffer.array() contentEquals - doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0)) + assertTrue( + diagonal1.source contentEquals + doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0) + ) val diagonal1Offset = diagonalEmbedding(tensor1, 1, 1, 0) assertTrue(diagonal1Offset.shape contentEquals intArrayOf(4, 4)) - assertTrue(diagonal1Offset.mutableBuffer.array() contentEquals - doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0)) + assertTrue( + diagonal1Offset.source contentEquals + doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0) + ) val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2) assertTrue(diagonal2.shape contentEquals intArrayOf(4, 2, 4)) - assertTrue(diagonal2.mutableBuffer.array() contentEquals - doubleArrayOf( - 0.0, 1.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, - 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 5.0, 0.0, - 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 6.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) + assertTrue( + diagonal2.source contentEquals + doubleArrayOf( + 0.0, 1.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, + 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 5.0, 0.0, + 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 6.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + ) + ) } @Test @@ -178,4 +194,14 @@ internal class TestDoubleTensorAlgebra { assertFalse(tensor1.eq(tensor3)) } + + @Test + fun testMap() = DoubleTensorAlgebra { + val tensor = one(5, 5, 5) + val l = tensor.getTensor(0).map { it + 1.0 } + val r = tensor.getTensor(1).map { it - 1.0 } + val res = l + r + assertTrue { intArrayOf(5, 5) contentEquals res.shape } + assertEquals(1.0, res[4, 4]) + } } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt new file mode 100644 index 000000000..e9fc7fb9c --- /dev/null +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/offsetBufferEquality.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2018-2022 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.tensors.core + +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.indices +import kotlin.jvm.JvmName + + +/** + * Simplified [DoubleBuffer] to array comparison + */ +public fun OffsetDoubleBuffer.contentEquals(vararg doubles: Double): Boolean = indices.all { get(it) == doubles[it] } + +@JvmName("contentEqualsArray") +public infix fun OffsetDoubleBuffer.contentEquals(otherArray: DoubleArray): Boolean = contentEquals(*otherArray) + +@JvmName("contentEqualsBuffer") +public infix fun OffsetDoubleBuffer.contentEquals(otherBuffer: Buffer): Boolean = + indices.all { get(it) == otherBuffer[it] } \ No newline at end of file diff --git a/test-utils/src/commonMain/kotlin/bufferEquality.kt b/test-utils/src/commonMain/kotlin/bufferEquality.kt new file mode 100644 index 000000000..9e4d9ec22 --- /dev/null +++ b/test-utils/src/commonMain/kotlin/bufferEquality.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2018-2022 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.testutils + +import space.kscience.kmath.structures.DoubleBuffer +import kotlin.jvm.JvmName + +/** + * Simplified [DoubleBuffer] to array comparison + */ +public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) + +@JvmName("contentEqualsArray") +public infix fun DoubleBuffer.contentEquals(otherArray: DoubleArray): Boolean = array.contentEquals(otherArray) + +@JvmName("contentEqualsBuffer") +public infix fun DoubleBuffer.contentEquals(otherBuffer: DoubleBuffer): Boolean = array.contentEquals(otherBuffer.array) \ No newline at end of file From 20886d6f6b366047e7d80cee76030f5413e60ed0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 11 Sep 2022 17:10:26 +0300 Subject: [PATCH 173/174] Global refactor of tensors --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 7 +++-- .../kmath/tensors/core/IntTensorAlgebra.kt | 5 ++-- .../tensors/core/TensorLinearStructure.kt | 8 +++--- .../core/internal/doubleTensorHelpers.kt | 27 +++++++++---------- .../tensors/core/internal/intTensorHelpers.kt | 2 +- .../kmath/tensors/core/tensorTransform.kt | 17 +++++++++--- .../kmath/tensors/core/TestDoubleTensor.kt | 23 +++++++--------- .../tensors/core/TestDoubleTensorAlgebra.kt | 7 ++--- 8 files changed, 52 insertions(+), 44 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index d758c49a1..f563d00ae 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -132,7 +132,10 @@ public open class DoubleTensorAlgebra : val dt = asDoubleTensor() val lastShape = shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - return DoubleTensor(newShape, dt.source.view(newShape.reduce(Int::times) * i)) + return DoubleTensor( + newShape, + dt.source.view(newShape.reduce(Int::times) * i, TensorLinearStructure.linearSizeOf(newShape)) + ) } /** @@ -227,7 +230,7 @@ public open class DoubleTensorAlgebra : override fun StructureND.minus(arg: Double): DoubleTensor = map { it - arg } - override fun StructureND.minus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l + r } + override fun StructureND.minus(arg: StructureND): DoubleTensor = zip(this, arg) { l, r -> l - r } override fun Tensor.minusAssign(value: Double) { mapInPlace { it - value } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt index 7c18fe533..124ccc668 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensorAlgebra.kt @@ -221,7 +221,7 @@ public open class IntTensorAlgebra : TensorAlgebra { override fun StructureND.minus(arg: Int): IntTensor = map { it - arg } - override fun StructureND.minus(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l + r } + override fun StructureND.minus(arg: StructureND): IntTensor = zip(this, arg) { l, r -> l - r } override fun Tensor.minusAssign(value: Int) { mapInPlace { it - value } @@ -283,8 +283,7 @@ public open class IntTensorAlgebra : TensorAlgebra { view(other.shape) override fun StructureND.dot(other: StructureND): IntTensor { - return if (dimension in 0..2 && other.dimension in 0..2) TODO("not implemented") - else error("Only vectors and matrices are allowed in non-broadcasting dot operation") + TODO("not implemented for integers") } override fun diagonalEmbedding( diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt index 3de1c9b1a..729fc0d13 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt @@ -15,14 +15,12 @@ import kotlin.math.max * @param shape the shape of the tensor. */ public class TensorLinearStructure(override val shape: IntArray) : Strides() { - override val strides: IntArray - get() = stridesFromShape(shape) + override val strides: IntArray get() = stridesFromShape(shape) override fun index(offset: Int): IntArray = indexFromOffset(offset, strides, shape.size) - override val linearSize: Int - get() = shape.reduce(Int::times) + override val linearSize: Int get() = linearSizeOf(shape) override fun equals(other: Any?): Boolean { if (this === other) return true @@ -41,6 +39,8 @@ public class TensorLinearStructure(override val shape: IntArray) : Strides() { public companion object { + public fun linearSizeOf(shape: IntArray): Int = shape.reduce(Int::times) + public fun stridesFromShape(shape: IntArray): IntArray { val nDim = shape.size val res = IntArray(nDim) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt index 9c6f54d61..c5910a436 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/doubleTensorHelpers.kt @@ -14,11 +14,8 @@ import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.indices +import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.eye -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.OffsetDoubleBuffer -import space.kscience.kmath.tensors.core.copyToTensor import kotlin.math.abs import kotlin.math.max import kotlin.math.sqrt @@ -165,7 +162,7 @@ internal val DoubleTensor.vectors: VirtualBuffer return VirtualBuffer(linearSize / vectorOffset) { index -> val offset = index * vectorOffset - DoubleTensor(vectorShape, source.view(offset)) + DoubleTensor(vectorShape, source.view(offset, vectorShape.first())) } } @@ -174,16 +171,18 @@ internal fun DoubleTensor.vectorSequence(): Sequence = vectors.asS internal val DoubleTensor.matrices: VirtualBuffer - get(){ - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) + get() { + val n = shape.size + check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } + val matrixOffset = shape[n - 1] * shape[n - 2] + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) - return VirtualBuffer(linearSize / matrixOffset) { index -> - val offset = index * matrixOffset - DoubleTensor(matrixShape, source.view(offset)) + val size = TensorLinearStructure.linearSizeOf(matrixShape) + + return VirtualBuffer(linearSize / matrixOffset) { index -> + val offset = index * matrixOffset + DoubleTensor(matrixShape, source.view(offset, size)) + } } -} internal fun DoubleTensor.matrixSequence(): Sequence = matrices.asSequence() \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt index 93229c2d4..db289a090 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/intTensorHelpers.kt @@ -40,7 +40,7 @@ internal val IntTensor.vectors: VirtualBuffer return VirtualBuffer(linearSize / vectorOffset) { index -> val offset = index * vectorOffset - IntTensor(vectorShape, source.view(offset)) + IntTensor(vectorShape, source.view(offset, vectorShape.first())) } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt index 30a828d6a..118624440 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorTransform.kt @@ -5,14 +5,20 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.DoubleBufferND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.tensors.api.Tensor +/** + * Create a mutable copy of given [StructureND]. + */ public fun StructureND.copyToTensor(): DoubleTensor = if (this is DoubleTensor) { DoubleTensor(shape, source.copy()) +} else if (this is DoubleBufferND && indices is TensorLinearStructure) { + DoubleTensor(shape, buffer.copy()) } else { DoubleTensor( shape, @@ -36,11 +42,14 @@ public fun StructureND.toDoubleTensor(): DoubleTensor { } /** - * Casts [Tensor] of [Double] to [DoubleTensor] + * Transforms [StructureND] of [Double] to [DoubleTensor]. Zero copy if possible, but is not guaranteed */ -public fun StructureND.asDoubleTensor(): DoubleTensor = when (this) { - is DoubleTensor -> this - else -> copyToTensor() +public fun StructureND.asDoubleTensor(): DoubleTensor = if (this is DoubleTensor) { + this +} else if (this is DoubleBufferND && indices is TensorLinearStructure) { + DoubleTensor(shape, buffer) +} else { + copyToTensor() } /** diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index a36f32ac9..c87cf2a68 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -6,10 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.MutableBufferND -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.toDoubleArray @@ -66,16 +63,16 @@ internal class TestDoubleTensor { fun testNoBufferProtocol() { // create buffer - val doubleArray = DoubleBuffer(doubleArrayOf(1.0, 2.0, 3.0)) + val doubleArray = DoubleBuffer(1.0, 2.0, 3.0) // create ND buffers, no data is copied - val ndArray: MutableBufferND = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleArray) + val ndArray: MutableBufferND = DoubleBufferND(DefaultStrides(intArrayOf(3)), doubleArray) // map to tensors - val bufferedTensorArray = ndArray.asDoubleTensor() // strides are flipped so data copied - val tensorArray = bufferedTensorArray.asDoubleTensor() // data not contiguous so copied again + val tensorArray = ndArray.asDoubleTensor() // Data is copied because of strides change. - val tensorArrayPublic = ndArray.asDoubleTensor() // public API, data copied twice + //protective copy + val tensorArrayPublic = ndArray.copyToTensor() // public API, data copied twice val sharedTensorArray = tensorArrayPublic.asDoubleTensor() // no data copied by matching type assertTrue(tensorArray.source contentEquals sharedTensorArray.source) @@ -83,11 +80,11 @@ internal class TestDoubleTensor { tensorArray[intArrayOf(0)] = 55.9 assertEquals(tensorArrayPublic[intArrayOf(0)], 1.0) - tensorArrayPublic[intArrayOf(0)] = 55.9 - assertEquals(sharedTensorArray[intArrayOf(0)], 55.9) - assertEquals(bufferedTensorArray[intArrayOf(0)], 1.0) + tensorArrayPublic[intArrayOf(0)] = 57.9 + assertEquals(sharedTensorArray[intArrayOf(0)], 57.9) + assertEquals(tensorArray[intArrayOf(0)], 55.9) - bufferedTensorArray[intArrayOf(0)] = 55.9 + tensorArray[intArrayOf(0)] = 55.9 assertEquals(ndArray[intArrayOf(0)], 1.0) } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 79b199471..67bebb9a7 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.get import space.kscience.kmath.operations.invoke +import space.kscience.kmath.testutils.assertBufferEquals import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -98,8 +99,8 @@ internal class TestDoubleTensorAlgebra { assignResult += tensorC assignResult += -39.4 - assertTrue(expected.source contentEquals result.source) - assertTrue(expected.source contentEquals assignResult.source) + assertBufferEquals(expected.source, result.source) + assertBufferEquals(expected.source, assignResult.source) } @Test @@ -202,6 +203,6 @@ internal class TestDoubleTensorAlgebra { val r = tensor.getTensor(1).map { it - 1.0 } val res = l + r assertTrue { intArrayOf(5, 5) contentEquals res.shape } - assertEquals(1.0, res[4, 4]) + assertEquals(2.0, res[4, 4]) } } From 2358f53cf7ae26220d0f7ae5bc99c8b54942d89b Mon Sep 17 00:00:00 2001 From: darksnake Date: Thu, 15 Sep 2022 17:42:37 +0300 Subject: [PATCH 174/174] Make Circle2D data class --- .../commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt index 5a25fef7d..162130908 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Circle2D.kt @@ -10,7 +10,7 @@ import kotlin.math.PI /** * A circle in 2D space */ -public class Circle2D( +public data class Circle2D( public val center: DoubleVector2D, public val radius: Double )