Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
7 changed files with 10296 additions and 24 deletions
Showing only changes of commit 923c52737d - Show all commits

View File

@ -177,14 +177,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to sum of [other] copies of [this]. * The operation is equivalent to sum of [other] copies of [this].
*/ */
public override operator fun LabeledPolynomial<C>.times(other: Int): LabeledPolynomial<C> = public override operator fun LabeledPolynomial<C>.times(other: Int): LabeledPolynomial<C> =
if (other == 0) zero when(other) {
else LabeledPolynomial( 0 -> zero
1 -> this
else -> LabeledPolynomial(
coefficients coefficients
.toMutableMap() .toMutableMap()
.apply { .apply {
for (degs in keys) this[degs] = this[degs]!! * other for (degs in keys) this[degs] = this[degs]!! * other
} }
) )
}
/** /**
* Returns sum of the integer represented as a polynomial and the polynomial. * Returns sum of the integer represented as a polynomial and the polynomial.
@ -210,7 +213,7 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to subtraction [this] copies of unit polynomial from [other]. * The operation is equivalent to subtraction [this] copies of unit polynomial from [other].
*/ */
public override operator fun Int.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> = public override operator fun Int.minus(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) other if (this == 0) -other
else with(other.coefficients) { else with(other.coefficients) {
if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@minus.asConstant())) if (isEmpty()) LabeledPolynomialAsIs(mapOf(emptyMap<Symbol, UInt>() to this@minus.asConstant()))
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
@ -230,14 +233,17 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
* The operation is equivalent to sum of [this] copies of [other]. * The operation is equivalent to sum of [this] copies of [other].
*/ */
public override operator fun Int.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> = public override operator fun Int.times(other: LabeledPolynomial<C>): LabeledPolynomial<C> =
if (this == 0) zero when(this) {
else LabeledPolynomial( 0 -> zero
1 -> other
else -> LabeledPolynomial(
other.coefficients other.coefficients
.toMutableMap() .toMutableMap()
.apply { .apply {
for (degs in keys) this[degs] = this@times * this[degs]!! for (degs in keys) this[degs] = this@times * this[degs]!!
} }
) )
}
/** /**
* Converts the integer [value] to polynomial. * Converts the integer [value] to polynomial.
@ -360,8 +366,6 @@ public class LabeledPolynomialSpace<C, A : Ring<C>>(
else LabeledPolynomialAsIs( else LabeledPolynomialAsIs(
toMutableMap() toMutableMap()
.apply { .apply {
forEach { (degs, c) -> if(degs.isNotEmpty()) this[degs] = -c }
val degs = emptyMap<Symbol, UInt>() val degs = emptyMap<Symbol, UInt>()
this[degs] = getOrElse(degs) { constantZero } - other this[degs] = getOrElse(degs) { constantZero } - other

View File

@ -302,6 +302,7 @@ public class DSL1LabeledPolynomialTermSignatureBuilder {
* Declaring another power of the same variable will increase its degree by received degree. * Declaring another power of the same variable will increase its degree by received degree.
*/ */
public infix fun Symbol.inPowerOf(deg: UInt) { public infix fun Symbol.inPowerOf(deg: UInt) {
if (deg == 0u) return
signature[this] = signature.getOrElse(this) { 0u } + deg signature[this] = signature.getOrElse(this) { 0u } + deg
} }
/** /**

View File

@ -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<Symbol, UInt>() 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<Symbol, UInt>() 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<Symbol, UInt>() to 0,
),
Int.algebra {
LabeledPolynomial(
mapOf(x to 0u) to 5,
mapOf(z to 0u, t to 0u) to -5,
)
},
"test 4"
)
}
}

View File

@ -7,14 +7,19 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.test.misc.IntModuloRing
import space.kscience.kmath.test.misc.* import space.kscience.kmath.test.misc.Rational
import kotlin.test.* 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 { class NumberedPolynomialTest {
private val o = Rational(0) val o = Rational(0)
@Test @Test
fun test_Polynomial_Int_plus() { fun test_Polynomial_Int_plus() {
RationalField.numberedPolynomialSpace { RationalField.numberedPolynomialSpace {
@ -557,6 +562,7 @@ class NumberedPolynomialTest {
) )
assertEquals( assertEquals(
NumberedPolynomial( NumberedPolynomial(
listOf<UInt>() to Rational(0),
listOf(3u) to Rational(-8, 9), listOf(3u) to Rational(-8, 9),
listOf(0u, 4u) to Rational(-8, 7), listOf(0u, 4u) to Rational(-8, 7),
), ),
@ -650,6 +656,7 @@ class NumberedPolynomialTest {
) )
assertEquals( assertEquals(
NumberedPolynomial( NumberedPolynomial(
listOf<UInt>() to Rational(0),
listOf(3u) to Rational(-8, 9), listOf(3u) to Rational(-8, 9),
listOf(0u, 4u) to Rational(-8, 7), listOf(0u, 4u) to Rational(-8, 7),
), ),
@ -816,6 +823,7 @@ class NumberedPolynomialTest {
) )
assertEquals( assertEquals(
NumberedPolynomial( NumberedPolynomial(
listOf<UInt>() to Rational(0),
listOf(3u) to Rational(-8, 9), listOf(3u) to Rational(-8, 9),
listOf(0u, 4u) to Rational(-8, 7), listOf(0u, 4u) to Rational(-8, 7),
), ),

View File

@ -5,6 +5,8 @@
package space.kscience.kmath.test.misc 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.NumberedPolynomial
import space.kscience.kmath.functions.NumberedRationalFunction import space.kscience.kmath.functions.NumberedRationalFunction
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -28,6 +30,18 @@ fun assertEquals(
message message
) )
fun assertEquals(
expected: LabeledPolynomial<Double>,
actual: LabeledPolynomial<Double>,
absoluteTolerance: Double,
message: String? = null
) = assertContentEquals(
expected.coefficients,
actual.coefficients,
absoluteTolerance,
message
)
fun assertEquals( fun assertEquals(
expected: NumberedRationalFunction<Double>, expected: NumberedRationalFunction<Double>,
actual: NumberedRationalFunction<Double>, actual: NumberedRationalFunction<Double>,
@ -48,6 +62,26 @@ fun assertEquals(
) )
} }
fun assertEquals(
expected: LabeledRationalFunction<Double>,
actual: LabeledRationalFunction<Double>,
absoluteTolerance: Double,
message: String? = null
) {
assertEquals(
expected.numerator,
actual.numerator,
absoluteTolerance,
message
)
assertEquals(
expected.denominator,
actual.denominator,
absoluteTolerance,
message
)
}
inline fun <reified T : Throwable> assertFailsWithTypeAndMessage( inline fun <reified T : Throwable> assertFailsWithTypeAndMessage(
expectedMessage: String? = null, expectedMessage: String? = null,
assertionMessage: String? = null, assertionMessage: String? = null,