From 1e4692d5cf9ca97c5e9ad6add5d95d9d19b4c1a8 Mon Sep 17 00:00:00 2001 From: Iaroslav Date: Wed, 12 Aug 2020 21:18:47 +0700 Subject: [PATCH 1/2] Fix scalar multiplication in BigInt, implement testers for fields, rings and spaces and apply them to ComplexFieldTest, BigIntAlgebraTest and RealFieldTest --- .../scientifik/kmath/operations/BigInt.kt | 3 +- .../kmath/operations/BigIntAlgebraTest.kt | 6 +++- .../kmath/operations/ComplexFieldTest.kt | 4 +++ .../kmath/operations/RealFieldTest.kt | 10 +++--- .../operations/internal/AlgebraicVerifier.kt | 9 +++++ .../operations/internal/FieldVerifier.kt | 24 ++++++++++++++ .../kmath/operations/internal/RingVerifier.kt | 28 ++++++++++++++++ .../operations/internal/SpaceVerifier.kt | 33 +++++++++++++++++++ 8 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/AlgebraicVerifier.kt create mode 100644 kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/FieldVerifier.kt create mode 100644 kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/RingVerifier.kt create mode 100644 kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/SpaceVerifier.kt diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt index fd7719157..07163750b 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt @@ -22,8 +22,9 @@ object BigIntField : Field { override val one: BigInt = BigInt.ONE override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b) + override fun number(value: Number): BigInt = value.toLong().toBigInt() - override fun multiply(a: BigInt, k: Number): BigInt = a.times(k.toLong()) + override fun multiply(a: BigInt, k: Number): BigInt = a.times(number(k)) override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt index c22d2f27b..d140f1017 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt @@ -1,9 +1,13 @@ package scientifik.kmath.operations +import scientifik.kmath.operations.internal.RingVerifier import kotlin.test.Test import kotlin.test.assertEquals -class BigIntAlgebraTest { +internal class BigIntAlgebraTest { + @Test + fun verify() = BigIntField { RingVerifier(this, +"42", +"10", +"-12", 10).verify() } + @Test fun testKBigIntegerRingSum() { val res = BigIntField { diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/ComplexFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/ComplexFieldTest.kt index 40fb0434d..2c480ebea 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/ComplexFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/ComplexFieldTest.kt @@ -1,5 +1,6 @@ package scientifik.kmath.operations +import scientifik.kmath.operations.internal.FieldVerifier import kotlin.math.PI import kotlin.math.abs import kotlin.test.Test @@ -7,6 +8,9 @@ import kotlin.test.assertEquals import kotlin.test.assertTrue internal class ComplexFieldTest { + @Test + fun verify() = ComplexField { FieldVerifier(this, 42.0 * i, 66.0 + 28 * i, 2.0 + 0 * i, 5).verify() } + @Test fun testAddition() { assertEquals(Complex(42, 42), ComplexField { Complex(16, 16) + Complex(26, 26) }) diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt index 9dfa3bdd1..a168b4afd 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt @@ -1,14 +1,16 @@ package scientifik.kmath.operations +import scientifik.kmath.operations.internal.FieldVerifier import kotlin.test.Test import kotlin.test.assertEquals -class RealFieldTest { +internal class RealFieldTest { + @Test + fun verify() = FieldVerifier(RealField, 42.0, 66.0, 2.0, 5).verify() + @Test fun testSqrt() { - val sqrt = RealField { - sqrt(25 * one) - } + val sqrt = RealField { sqrt(25 * one) } assertEquals(5.0, sqrt) } } diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/AlgebraicVerifier.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/AlgebraicVerifier.kt new file mode 100644 index 000000000..cb097d46e --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/AlgebraicVerifier.kt @@ -0,0 +1,9 @@ +package scientifik.kmath.operations.internal + +import scientifik.kmath.operations.Algebra + +internal interface AlgebraicVerifier where A : Algebra { + val algebra: A + + fun verify() +} diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/FieldVerifier.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/FieldVerifier.kt new file mode 100644 index 000000000..973fd00b1 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/FieldVerifier.kt @@ -0,0 +1,24 @@ +package scientifik.kmath.operations.internal + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.invoke +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +internal class FieldVerifier(override val algebra: Field, a: T, b: T, c: T, x: Number) : + RingVerifier(algebra, a, b, c, x) { + + override fun verify() { + super.verify() + + algebra { + assertNotEquals(a / b, b / a, "Division in $algebra is not anti-commutative.") + assertNotEquals((a / b) / c, a / (b / c), "Division in $algebra is associative.") + assertEquals((a + b) / c, (a / c) + (b / c), "Division in $algebra is not right-distributive.") + assertEquals(a, a / one, "$one in $algebra is not neutral division element.") + assertEquals(one, one / a * a, "$algebra does not provide single reciprocal element.") + assertEquals(zero / a, zero, "$zero in $algebra is not left neutral element for division.") + assertEquals(-one, a / (-a), "Division by sign reversal element in $algebra does not give ${-one}.") + } + } +} diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/RingVerifier.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/RingVerifier.kt new file mode 100644 index 000000000..047a213e9 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/RingVerifier.kt @@ -0,0 +1,28 @@ +package scientifik.kmath.operations.internal + +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.invoke +import kotlin.test.assertEquals + +internal open class RingVerifier(override val algebra: Ring, a: T, b: T, c: T, x: Number) : + SpaceVerifier(algebra, a, b, c, x) { + override fun verify() { + super.verify() + + algebra { + assertEquals(a * b, a * b, "Multiplication in $algebra is not commutative.") + assertEquals(a * b * c, a * (b * c), "Multiplication in $algebra is not associative.") + assertEquals(c * (a + b), (c * a) + (c * b), "Multiplication in $algebra is not distributive.") + assertEquals(a * one, one * a, "$one in $algebra is not a neutral multiplication element.") + assertEquals(a, one * a, "$one in $algebra is not a neutral multiplication element.") + assertEquals(a, a * one, "$one in $algebra is not a neutral multiplication element.") + assertEquals(a, one * a, "$one in $algebra is not a neutral multiplication element.") + assertEquals(a, a * one * one, "Multiplication by $one in $algebra is not idempotent.") + assertEquals(a, a * one * one * one, "Multiplication by $one in $algebra is not idempotent.") + assertEquals(a, a * one * one * one * one, "Multiplication by $one in $algebra is not idempotent.") + assertEquals(zero, a * zero, "Multiplication by $zero in $algebra doesn't give $zero.") + assertEquals(zero, zero * a, "Multiplication by $zero in $algebra doesn't give $zero.") + assertEquals(a * zero, a * zero, "Multiplication by $zero in $algebra doesn't give $zero.") + } + } +} diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/SpaceVerifier.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/SpaceVerifier.kt new file mode 100644 index 000000000..bc241c97d --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/internal/SpaceVerifier.kt @@ -0,0 +1,33 @@ +package scientifik.kmath.operations.internal + +import scientifik.kmath.operations.Space +import scientifik.kmath.operations.invoke +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +internal open class SpaceVerifier( + override val algebra: Space, + val a: T, + val b: T, + val c: T, + val x: Number +) : + AlgebraicVerifier> { + override fun verify() { + algebra { + assertEquals(a + b, b + a, "Addition in $algebra is not commutative.") + assertEquals(a + b + c, a + (b + c), "Addition in $algebra is not associative.") + assertEquals(x * (a + b), x * a + x * b, "Addition in $algebra is not distributive.") + assertEquals((a + b) * x, a * x + b * x, "Addition in $algebra is not distributive.") + assertEquals(a + zero, zero + a, "$zero in $algebra is not a neutral addition element.") + assertEquals(a, a + zero, "$zero in $algebra is not a neutral addition element.") + assertEquals(a, zero + a, "$zero in $algebra is not a neutral addition element.") + assertEquals(a - b, -(b - a), "Subtraction in $algebra is not anti-commutative.") + assertNotEquals(a - b - c, a - (b - c), "Subtraction in $algebra is associative.") + assertEquals(x * (a - b), x * a - x * b, "Subtraction in $algebra is not distributive.") + assertEquals(a, a - zero, "$zero in $algebra is not a neutral addition element.") + assertEquals(a * x, x * a, "Multiplication by scalar in $algebra is not commutative.") + assertEquals(x * (a + b), (x * a) + (x * b), "Multiplication by scalar in $algebra is not distributive.") + } + } +} From b1f52f3022171c28802bc9f7a08fff05e0fd40ec Mon Sep 17 00:00:00 2001 From: Iaroslav Date: Sat, 15 Aug 2020 17:00:17 +0700 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c99c7bc1..26f9e33ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - Local coding conventions - Geometric Domains API in `kmath-core` - Blocking chains in `kmath-coroutines` +- Full hyperbolic functions support and default implementations within `ExtendedField` +- Norm support for `Complex` ### Changed - BigInteger and BigDecimal algebra: JBigDecimalField has companion object with default math context; minor optimizations @@ -23,10 +25,11 @@ - Memory objects have more preconditions (overflow checking) - `tg` function is renamed to `tan` (https://github.com/mipt-npm/kmath/pull/114) - Gradle version: 6.3 -> 6.5.1 -- Moved probability distributions to commons-rng and to `kmath-prob`. +- Moved probability distributions to commons-rng and to `kmath-prob` ### Fixed - Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106) - D3.dim value in `kmath-dimensions` - Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101) - Commons RNG compatibility (https://github.com/mipt-npm/kmath/issues/93) +- Multiplication of BigInt by scalar