From 651f8323f3f5c809d5b12d84bb6065fa32ce0cc7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 9 Jun 2019 22:03:35 +0300 Subject: [PATCH] Basic support for BigInteger (#69) --- .../kmath/structures/NDFieldBenchmark.kt | 2 +- .../scientifik/kmath/structures/NDField.kt | 2 +- .../kmath/structures/BoxingNDRing.kt | 72 +++++++++++++++++++ .../scientifik/kmath/structures/NDAlgebra.kt | 6 +- .../scientifik/kmath/structures/NDElement.kt | 2 +- .../scientifik/kmath/operations/BigNumers.kt | 45 ++++++++++++ 6 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt create mode 100644 kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumers.kt diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt index 46991b2de..ae27620f7 100644 --- a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt +++ b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt @@ -53,6 +53,6 @@ class NDFieldBenchmark { val bufferedField = NDField.auto(RealField, dim, dim) val specializedField = NDField.real(dim, dim) - val genericField = NDField.buffered(RealField, dim, dim) + val genericField = NDField.boxing(RealField, dim, dim) } } \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt index 10fad3ecb..7e8c433c0 100644 --- a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt @@ -13,7 +13,7 @@ fun main(args: Array) { // specialized nd-field for Double. It works as generic Double field as well val specializedField = NDField.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. - val genericField = NDField.buffered(RealField, dim, dim) + val genericField = NDField.boxing(RealField, dim, dim) val autoTime = measureTimeMillis { diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt new file mode 100644 index 000000000..39fc555e8 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt @@ -0,0 +1,72 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.RingElement + +class BoxingNDRing>( + override val shape: IntArray, + override val elementContext: R, + val bufferFactory: BufferFactory +) : BufferedNDRing { + + override val strides: Strides = DefaultStrides(shape) + + fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer = + bufferFactory(size, initializer) + + override fun check(vararg elements: NDBuffer) { + if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides") + } + + override val zero by lazy { produce { zero } } + override val one by lazy { produce { one } } + + override fun produce(initializer: R.(IntArray) -> T) = + BufferedNDRingElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }) + + override fun map(arg: NDBuffer, transform: R.(T) -> T): BufferedNDRingElement { + check(arg) + return BufferedNDRingElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) }) + +// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) } +// return BufferedNDFieldElement(this, buffer) + + } + + override fun mapIndexed( + arg: NDBuffer, + transform: R.(index: IntArray, T) -> T + ): BufferedNDRingElement { + check(arg) + return BufferedNDRingElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> + elementContext.transform( + arg.strides.index(offset), + arg.buffer[offset] + ) + }) + +// val buffer = +// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) } +// return BufferedNDFieldElement(this, buffer) + } + + override fun combine( + a: NDBuffer, + b: NDBuffer, + transform: R.(T, T) -> T + ): BufferedNDRingElement { + check(a, b) + return BufferedNDRingElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + } + + override fun NDBuffer.toElement(): RingElement, *, out BufferedNDRing> = + BufferedNDRingElement(this@BoxingNDRing, buffer) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt index 352c05467..c826565cf 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt @@ -82,6 +82,8 @@ interface NDSpace, N : NDStructure> : Space, NDAlgebra add(this@plus, value) } operator fun T.minus(arg: N) = map(arg) { value -> add(-this@minus, value) } + + companion object } /** @@ -98,6 +100,8 @@ interface NDRing, N : NDStructure> : Ring, NDSpace operator fun N.times(arg: T) = map(this) { value -> multiply(arg, value) } operator fun T.times(arg: N) = map(arg) { value -> multiply(this@times, value) } + + companion object } /** @@ -132,7 +136,7 @@ interface NDField, N : NDStructure> : Field, NDRing> buffered( + fun > boxing( field: F, vararg shape: Int, bufferFactory: BufferFactory = Buffer.Companion::boxing diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt index 59cf98df3..a18a03364 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt @@ -41,7 +41,7 @@ interface NDElement> : NDStructure { /** * Simple boxing NDArray */ - fun > buffered( + fun > boxing( shape: IntArray, field: F, initializer: F.(IntArray) -> T diff --git a/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumers.kt b/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumers.kt new file mode 100644 index 000000000..f44d15042 --- /dev/null +++ b/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumers.kt @@ -0,0 +1,45 @@ +package scientifik.kmath.operations + +import scientifik.kmath.structures.* +import java.math.BigDecimal +import java.math.BigInteger +import java.math.MathContext + +object BigIntegerRing : Ring { + override val zero: BigInteger = BigInteger.ZERO + override val one: BigInteger = BigInteger.ONE + + override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) + + override fun multiply(a: BigInteger, k: Number): BigInteger = a.multiply(k.toInt().toBigInteger()) + + override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) +} + +class BigDecimalField(val mathContext: MathContext = MathContext.DECIMAL64) : Field { + override val zero: BigDecimal = BigDecimal.ZERO + override val one: BigDecimal = BigDecimal.ONE + + override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) + + override fun multiply(a: BigDecimal, k: Number): BigDecimal = + a.multiply(k.toDouble().toBigDecimal(mathContext), mathContext) + + override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) + override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) +} + +inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInteger): Buffer = + boxing(size, initializer) + +inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInteger): MutableBuffer = + boxing(size, initializer) + +fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing = + BoxingNDRing(shape, BigIntegerRing, Buffer.Companion::bigInt) + +fun NDElement.Companion.bigInt( + vararg shape: Int, + initializer: BigIntegerRing.(IntArray) -> BigInteger +): BufferedNDRingElement = + NDAlgebra.bigInt(*shape).produce(initializer) \ No newline at end of file