Feature: Polynomials and rational functions #469

Merged
lounres merged 132 commits from feature/polynomials into dev 2022-07-28 18:04:06 +03:00
30 changed files with 419 additions and 139 deletions
Showing only changes of commit d44a48bdb1 - Show all commits

View File

@ -6,9 +6,16 @@ plugins {
description = "Functions, integration and interpolation" description = "Functions, integration and interpolation"
kotlin.sourceSets.commonMain { kotlin.sourceSets {
dependencies { commonMain {
api(project(":kmath-core")) dependencies {
api(project(":kmath-core"))
}
}
commonTest {
dependencies {
api(projects.testUtilsFunctions)
}
} }
} }

View File

@ -7,7 +7,10 @@
package space.kscience.kmath.functions 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.* import kotlin.test.*

View File

@ -6,9 +6,9 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.test.misc.assertFailsWithTypeAndMessage import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage
import kotlin.test.Ignore import kotlin.test.Ignore
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -64,7 +64,7 @@ class ListPolynomialUtilTest {
) )
assertEquals( assertEquals(
Rational(25057, 21000), 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)), .substitute(RationalField, Rational(1, 5)),
"test 2" "test 2"
) )
@ -76,13 +76,13 @@ class ListPolynomialUtilTest {
) )
assertEquals( assertEquals(
Rational(4961, 4200), 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)), .substitute(RationalField, Rational(1, 5)),
"test 4" "test 4"
) )
assertEquals( assertEquals(
Rational(3511, 3000), 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)), .substitute(RationalField, Rational(1, 5)),
"test 5" "test 5"
) )
@ -233,7 +233,7 @@ class ListPolynomialUtilTest {
ListPolynomial( ListPolynomial(
Rational(-13, 9), Rational(-13, 9),
Rational(5, 3), Rational(5, 3),
Rational(-5, 4) , Rational(-5, 4),
Rational(0), Rational(0),
Rational(0), Rational(0),
Rational(0), Rational(0),

View File

@ -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" }
}

View File

@ -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 <C> Group<C>.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 <C> GroupOps<C>.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 <C> Group<C>.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 <C> GroupOps<C>.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 <C> Field<C>.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 <C> Field<C>.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 <C> Ring<C>.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 <C> RingOps<C>.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")
}

View File

@ -6,19 +6,17 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.algebra
import space.kscience.kmath.operations.invoke 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.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class LabeledConstructorsTest { class LabeledConstructorsTest {
val x by symbol
val y by symbol
val z by symbol
val t by symbol
@Test @Test
@UnstableKMathAPI @UnstableKMathAPI
fun testDSL1() { fun testDSL1() {

View File

@ -8,25 +8,22 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol import space.kscience.kmath.functions.testUtils.IntModuloRing
import space.kscience.kmath.test.misc.IntModuloRing import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.functions.testUtils.o
import space.kscience.kmath.test.misc.m import space.kscience.kmath.functions.testUtils.m
import kotlin.test.* 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: Тесты на конвертацию. // TODO: Тесты на конвертацию.
class LabeledPolynomialTest { 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 @Test
fun test_Variable_Int_plus() { fun test_Variable_Int_plus() {
RationalField.labeledPolynomialSpace { RationalField.labeledPolynomialSpace {

View File

@ -6,20 +6,18 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.expressions.symbol
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.test.misc.assertEquals
import kotlin.test.Ignore import kotlin.test.Ignore
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals 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 { class LabeledPolynomialUtilTest {
val x by symbol
val y by symbol
val iota by symbol
@Test @Test
fun test_Polynomial_substitute_Double() { fun test_Polynomial_substitute_Double() {
assertEquals( assertEquals(

View File

@ -7,10 +7,11 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.test.misc.IntModuloRing import space.kscience.kmath.functions.testUtils.IntModuloRing
import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.test.misc.RationalField import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.test.misc.m import space.kscience.kmath.functions.testUtils.m
import space.kscience.kmath.functions.testUtils.o
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertSame import kotlin.test.assertSame
@ -18,8 +19,6 @@ import kotlin.test.fail
class NumberedPolynomialTest { class NumberedPolynomialTest {
val o = Rational(0)
@Test @Test
fun test_Polynomial_Int_plus() { fun test_Polynomial_Int_plus() {
RationalField.numberedPolynomialSpace { RationalField.numberedPolynomialSpace {

View File

@ -6,19 +6,16 @@
package space.kscience.kmath.functions package space.kscience.kmath.functions
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.functions.testUtils.Rational
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.functions.testUtils.RationalField
import space.kscience.kmath.test.misc.Rational import space.kscience.kmath.functions.testUtils.assertFailsWithTypeAndMessage
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.Ignore
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import space.kscience.kmath.functions.testUtils.bufferOf
import space.kscience.kmath.functions.testUtils.assertEquals
fun <T> bufferOf(vararg elements: T): Buffer<T> = elements.asBuffer()
class NumberedPolynomialUtilTest { class NumberedPolynomialUtilTest {
@Test @Test
fun test_Polynomial_substitute_Double_Map() { fun test_Polynomial_substitute_Double_Map() {

View File

@ -26,6 +26,9 @@ include(
":kmath-core", ":kmath-core",
":kmath-coroutines", ":kmath-coroutines",
":kmath-functions", ":kmath-functions",
":test-utils-functions",
":kmath-polynomialX",
":test-utils-polynomialX",
":kmath-histograms", ":kmath-histograms",
":kmath-commons", ":kmath-commons",
":kmath-viktor", ":kmath-viktor",

View File

@ -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"))
}
}
}

View File

@ -5,40 +5,37 @@
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") @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 import space.kscience.kmath.operations.Ring
class IntModulo { public class IntModulo {
val residue: Int public val residue: Int
val modulus: Int public val modulus: Int
@PublishedApi @PublishedApi
internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) { internal constructor(residue: Int, modulus: Int, toCheckInput: Boolean = true) {
if (toCheckInput) { if (toCheckInput) {
require(modulus != 0) { "modulus can not be zero" } require(modulus != 0) { "modulus can not be zero" }
this.modulus = if (modulus < 0) -modulus else modulus this.modulus = if (modulus < 0) -modulus else modulus
this.residue = residue.mod(modulus) this.residue = residue.mod(this.modulus)
} else { } else {
this.residue = residue this.residue = residue
this.modulus = modulus 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 public operator fun unaryPlus(): IntModulo = this
operator fun unaryMinus(): IntModulo = public operator fun unaryMinus(): IntModulo =
IntModulo( IntModulo(
if (residue == 0) 0 else modulus - residue, if (residue == 0) 0 else modulus - residue,
modulus, modulus,
toCheckInput = false 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" } require(modulus == other.modulus) { "can not add two residue different modulo" }
return IntModulo( return IntModulo(
(residue + other.residue) % modulus, (residue + other.residue) % modulus,
@ -46,13 +43,13 @@ class IntModulo {
toCheckInput = false toCheckInput = false
) )
} }
operator fun plus(other: Int): IntModulo = public operator fun plus(other: Int): IntModulo =
IntModulo( IntModulo(
(residue + other) % modulus, (residue + other) % modulus,
modulus, modulus,
toCheckInput = false 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" } require(modulus == other.modulus) { "can not subtract two residue different modulo" }
return IntModulo( return IntModulo(
(residue - other.residue) % modulus, (residue - other.residue) % modulus,
@ -60,13 +57,13 @@ class IntModulo {
toCheckInput = false toCheckInput = false
) )
} }
operator fun minus(other: Int): IntModulo = public operator fun minus(other: Int): IntModulo =
IntModulo( IntModulo(
(residue - other) % modulus, (residue - other) % modulus,
modulus, modulus,
toCheckInput = false 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" } require(modulus == other.modulus) { "can not multiply two residue different modulo" }
return IntModulo( return IntModulo(
(residue * other.residue) % modulus, (residue * other.residue) % modulus,
@ -74,13 +71,13 @@ class IntModulo {
toCheckInput = false toCheckInput = false
) )
} }
operator fun times(other: Int): IntModulo = public operator fun times(other: Int): IntModulo =
IntModulo( IntModulo(
(residue * other) % modulus, (residue * other) % modulus,
modulus, modulus,
toCheckInput = false 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" } require(modulus == other.modulus) { "can not divide two residue different modulo" }
val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus) val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other.residue, modulus)
require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
@ -90,7 +87,7 @@ class IntModulo {
toCheckInput = false toCheckInput = false
) )
} }
operator fun div(other: Int): IntModulo { public operator fun div(other: Int): IntModulo {
val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus) val (reciprocalCandidate, gcdOfOtherResidueAndModulus) = bezoutIdentityWithGCD(other, modulus)
require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" } require(gcdOfOtherResidueAndModulus == 1) { "can not divide to residue that has non-trivial GCD with modulo" }
return IntModulo( return IntModulo(
@ -111,11 +108,11 @@ class IntModulo {
} }
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
class IntModuloRing : Ring<IntModulo> { public class IntModuloRing : Ring<IntModulo> {
val modulus: Int public val modulus: Int
constructor(modulus: Int) { public constructor(modulus: Int) {
require(modulus != 0) { "modulus can not be zero" } require(modulus != 0) { "modulus can not be zero" }
this.modulus = if (modulus < 0) -modulus else modulus this.modulus = if (modulus < 0) -modulus else modulus
} }
@ -123,7 +120,7 @@ class IntModuloRing : Ring<IntModulo> {
override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false) override inline val zero: IntModulo get() = IntModulo(0, modulus, toCheckInput = false)
override inline val one: IntModulo get() = IntModulo(1, 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 add(left: IntModulo, right: IntModulo): IntModulo = left + right
override inline fun multiply(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<IntModulo> {
override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg override inline fun IntModulo.plus(arg: IntModulo): IntModulo = this + arg
override inline fun IntModulo.minus(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 override inline fun IntModulo.times(arg: IntModulo): IntModulo = this * arg
inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg public inline fun IntModulo.div(arg: IntModulo): IntModulo = this / arg
} }
fun ListPolynomialSpace<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, ring.modulus) })
fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, modulus) })
fun IntModuloRing.m(arg: Int) = IntModulo(arg, modulus)
fun PolynomialSpaceOverRing<IntModulo, *, IntModuloRing>.m(arg: Int) = IntModulo(arg, ring.modulus)

View File

@ -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<IntModulo, IntModuloRing>.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, ring.modulus) })
public fun IntModuloRing.ListPolynomial(vararg coefs: Int): ListPolynomial<IntModulo> =
ListPolynomial(coefs.map { IntModulo(it, modulus) })
public fun IntModuloRing.m(arg: Int): IntModulo = IntModulo(arg, modulus)
public fun PolynomialSpaceOverRing<IntModulo, *, IntModuloRing>.m(arg: Int): IntModulo = IntModulo(arg, ring.modulus)

View File

@ -5,21 +5,21 @@
@file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress") @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.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Field import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.NumbersAddOps
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
class Rational { public class Rational {
companion object { public companion object {
val ZERO: Rational = Rational(0L) public val ZERO: Rational = Rational(0L)
val ONE: Rational = Rational(1L) public val ONE: Rational = Rational(1L)
} }
val numerator: Long public val numerator: Long
val denominator: Long public val denominator: Long
internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) { internal constructor(numerator: Long, denominator: Long, toCheckInput: Boolean = true) {
if (toCheckInput) { if (toCheckInput) {
@ -35,16 +35,16 @@ class Rational {
} }
} }
constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true) public constructor(numerator: Int, denominator: Int) : this(numerator.toLong(), denominator.toLong(), true)
constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true) public constructor(numerator: Int, denominator: Long) : this(numerator.toLong(), denominator, true)
constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true) public constructor(numerator: Long, denominator: Int) : this(numerator, denominator.toLong(), true)
constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true) public constructor(numerator: Long, denominator: Long) : this(numerator, denominator, true)
constructor(numerator: Int) : this(numerator.toLong(), 1L, false) public constructor(numerator: Int) : this(numerator.toLong(), 1L, false)
constructor(numerator: Long) : this(numerator, 1L, false) public constructor(numerator: Long) : this(numerator, 1L, false)
operator fun unaryPlus(): Rational = this public operator fun unaryPlus(): Rational = this
operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator) public operator fun unaryMinus(): Rational = Rational(-this.numerator, this.denominator)
operator fun plus(other: Rational): Rational { public operator fun plus(other: Rational): Rational {
val denominatorsGcd = gcd(denominator, other.denominator) val denominatorsGcd = gcd(denominator, other.denominator)
val dividedThisDenominator = denominator / denominatorsGcd val dividedThisDenominator = denominator / denominatorsGcd
val dividedOtherDenominator = other.denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd
@ -56,19 +56,19 @@ class Rational {
toCheckInput = false toCheckInput = false
) )
} }
operator fun plus(other: Int): Rational = public operator fun plus(other: Int): Rational =
Rational( Rational(
numerator + denominator * other.toLong(), numerator + denominator * other.toLong(),
denominator, denominator,
toCheckInput = false toCheckInput = false
) )
operator fun plus(other: Long): Rational = public operator fun plus(other: Long): Rational =
Rational( Rational(
numerator + denominator * other, numerator + denominator * other,
denominator, denominator,
toCheckInput = false toCheckInput = false
) )
operator fun minus(other: Rational): Rational { public operator fun minus(other: Rational): Rational {
val denominatorsGcd = gcd(denominator, other.denominator) val denominatorsGcd = gcd(denominator, other.denominator)
val dividedThisDenominator = denominator / denominatorsGcd val dividedThisDenominator = denominator / denominatorsGcd
val dividedOtherDenominator = other.denominator / denominatorsGcd val dividedOtherDenominator = other.denominator / denominatorsGcd
@ -80,19 +80,19 @@ class Rational {
toCheckInput = false toCheckInput = false
) )
} }
operator fun minus(other: Int): Rational = public operator fun minus(other: Int): Rational =
Rational( Rational(
numerator - denominator * other.toLong(), numerator - denominator * other.toLong(),
denominator, denominator,
toCheckInput = false toCheckInput = false
) )
operator fun minus(other: Long): Rational = public operator fun minus(other: Long): Rational =
Rational( Rational(
numerator - denominator * other, numerator - denominator * other,
denominator, denominator,
toCheckInput = false toCheckInput = false
) )
operator fun times(other: Rational): Rational { public operator fun times(other: Rational): Rational {
val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator) val thisDenominatorAndOtherNumeratorGcd = gcd(denominator, other.numerator)
val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator) val otherDenominatorAndThisNumeratorGcd = gcd(other.denominator, numerator)
return Rational( return Rational(
@ -101,7 +101,7 @@ class Rational {
toCheckInput = false toCheckInput = false
) )
} }
operator fun times(other: Int): Rational { public operator fun times(other: Int): Rational {
val other = other.toLong() val other = other.toLong()
val denominatorAndOtherGcd = gcd(denominator, other) val denominatorAndOtherGcd = gcd(denominator, other)
return Rational( return Rational(
@ -110,7 +110,7 @@ class Rational {
toCheckInput = false toCheckInput = false
) )
} }
operator fun times(other: Long): Rational { public operator fun times(other: Long): Rational {
val denominatorAndOtherGcd = gcd(denominator, other) val denominatorAndOtherGcd = gcd(denominator, other)
return Rational( return Rational(
numerator * (other / denominatorAndOtherGcd), numerator * (other / denominatorAndOtherGcd),
@ -118,7 +118,7 @@ class Rational {
toCheckInput = false toCheckInput = false
) )
} }
operator fun div(other: Rational): Rational { public operator fun div(other: Rational): Rational {
val denominatorsGcd = gcd(denominator, other.denominator) val denominatorsGcd = gcd(denominator, other.denominator)
val numeratorsGcd = gcd(numerator, other.numerator) val numeratorsGcd = gcd(numerator, other.numerator)
return Rational( return Rational(
@ -126,7 +126,7 @@ class Rational {
(denominator / denominatorsGcd) * (other.numerator / numeratorsGcd) (denominator / denominatorsGcd) * (other.numerator / numeratorsGcd)
) )
} }
operator fun div(other: Int): Rational { public operator fun div(other: Int): Rational {
val other = other.toLong() val other = other.toLong()
val numeratorAndOtherGcd = gcd(numerator, other) val numeratorAndOtherGcd = gcd(numerator, other)
return Rational( return Rational(
@ -135,7 +135,7 @@ class Rational {
toCheckInput = false toCheckInput = false
) )
} }
operator fun div(other: Long): Rational { public operator fun div(other: Long): Rational {
val numeratorAndOtherGcd = gcd(numerator, other) val numeratorAndOtherGcd = gcd(numerator, other)
return Rational( return Rational(
numerator / numeratorAndOtherGcd, numerator / numeratorAndOtherGcd,
@ -158,7 +158,7 @@ class Rational {
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE") @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE")
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
object RationalField : Field<Rational>, NumbersAddOps<Rational> { public object RationalField : Field<Rational>, NumbersAddOps<Rational> {
override inline val zero: Rational get() = Rational.ZERO override inline val zero: Rational get() = Rational.ZERO
override inline val one: Rational get() = Rational.ONE override inline val one: Rational get() = Rational.ONE

View File

@ -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 <reified T : Throwable> assertFailsWithTypeAndMessage(
expectedMessage: String? = null,
assertionMessage: String? = null,
block: () -> Unit
) {
assertEquals(
expectedMessage,
assertFailsWith(T::class, assertionMessage, block).message,
assertionMessage
)
}

View File

@ -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. * 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 import kotlin.math.abs
data class BezoutIdentityWithGCD<T>(val first: T, val second: T, val gcd: T) internal data class BezoutIdentityWithGCD<T>(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<Int> = internal fun bezoutIdentityWithGCD(a: Int, b: Int): BezoutIdentityWithGCD<Int> =
when { when {
a < 0 && b < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, -b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, -second, gcd) } 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) } a < 0 -> with(bezoutIdentityWithGCDInternalLogic(-a, b, 1, 0, 0, 1)) { BezoutIdentityWithGCD(-first, second, gcd) }

View File

@ -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"))
}
}
}

View File

@ -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 <T> bufferOf(vararg elements: T): Buffer<T> = elements.asBuffer()

View File

@ -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. * 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.LabeledPolynomial
import space.kscience.kmath.functions.LabeledRationalFunction import space.kscience.kmath.functions.LabeledRationalFunction
@ -13,36 +13,45 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
fun <T> assertContentEquals(expected: Map<T, Double>, actual: Map<T, Double>, absoluteTolerance: Double, message: String? = null) { public fun <T> assertContentEquals(
expected: Map<T, Double>,
actual: Map<T, Double>,
absoluteTolerance: Double,
message: String? = null
) {
assertEquals(expected.keys, actual.keys, message) assertEquals(expected.keys, actual.keys, message)
for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message) for ((key, expectedValue) in expected) assertEquals(expectedValue, actual[key]!!, absoluteTolerance, message)
} }
fun assertEquals( public fun assertEquals(
expected: NumberedPolynomial<Double>, expected: NumberedPolynomial<Double>,
actual: NumberedPolynomial<Double>, actual: NumberedPolynomial<Double>,
absoluteTolerance: Double, absoluteTolerance: Double,
message: String? = null message: String? = null
) = assertContentEquals( ) {
expected.coefficients, assertContentEquals(
actual.coefficients, expected.coefficients,
absoluteTolerance, actual.coefficients,
message absoluteTolerance,
) message
)
}
fun assertEquals( public fun assertEquals(
expected: LabeledPolynomial<Double>, expected: LabeledPolynomial<Double>,
actual: LabeledPolynomial<Double>, actual: LabeledPolynomial<Double>,
absoluteTolerance: Double, absoluteTolerance: Double,
message: String? = null message: String? = null
) = assertContentEquals( ) {
expected.coefficients, assertContentEquals(
actual.coefficients, expected.coefficients,
absoluteTolerance, actual.coefficients,
message absoluteTolerance,
) message
)
}
fun assertEquals( public fun assertEquals(
expected: NumberedRationalFunction<Double>, expected: NumberedRationalFunction<Double>,
actual: NumberedRationalFunction<Double>, actual: NumberedRationalFunction<Double>,
absoluteTolerance: Double, absoluteTolerance: Double,
@ -62,7 +71,7 @@ fun assertEquals(
) )
} }
fun assertEquals( public fun assertEquals(
expected: LabeledRationalFunction<Double>, expected: LabeledRationalFunction<Double>,
actual: LabeledRationalFunction<Double>, actual: LabeledRationalFunction<Double>,
absoluteTolerance: Double, absoluteTolerance: Double,
@ -82,13 +91,15 @@ fun assertEquals(
) )
} }
inline fun <reified T : Throwable> assertFailsWithTypeAndMessage( // FIXME: Don't understand why but the same function from test-utils-functions module can not be used
public inline fun <reified T : Throwable> assertFailsWithTypeAndMessage(
expectedMessage: String? = null, expectedMessage: String? = null,
assertionMessage: String? = null, assertionMessage: String? = null,
block: () -> Unit block: () -> Unit
) = ) {
assertEquals( assertEquals(
expectedMessage, expectedMessage,
assertFailsWith(T::class, assertionMessage, block).message, assertFailsWith(T::class, assertionMessage, block).message,
assertionMessage assertionMessage
) )
}

View File

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