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] 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