Basic support for BigInteger (#69)

This commit is contained in:
Alexander Nozik 2019-06-09 22:03:35 +03:00
parent 7183d6ea8a
commit 651f8323f3
6 changed files with 125 additions and 4 deletions

View File

@ -53,6 +53,6 @@ class NDFieldBenchmark {
val bufferedField = NDField.auto(RealField, dim, dim) val bufferedField = NDField.auto(RealField, dim, dim)
val specializedField = NDField.real(dim, dim) val specializedField = NDField.real(dim, dim)
val genericField = NDField.buffered(RealField, dim, dim) val genericField = NDField.boxing(RealField, dim, dim)
} }
} }

View File

@ -13,7 +13,7 @@ fun main(args: Array<String>) {
// specialized nd-field for Double. It works as generic Double field as well // specialized nd-field for Double. It works as generic Double field as well
val specializedField = NDField.real(dim, dim) val specializedField = NDField.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives. //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 { val autoTime = measureTimeMillis {

View File

@ -0,0 +1,72 @@
package scientifik.kmath.structures
import scientifik.kmath.operations.Ring
import scientifik.kmath.operations.RingElement
class BoxingNDRing<T, R : Ring<T>>(
override val shape: IntArray,
override val elementContext: R,
val bufferFactory: BufferFactory<T>
) : BufferedNDRing<T, R> {
override val strides: Strides = DefaultStrides(shape)
fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
bufferFactory(size, initializer)
override fun check(vararg elements: NDBuffer<T>) {
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<T>, transform: R.(T) -> T): BufferedNDRingElement<T, R> {
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<T>,
transform: R.(index: IntArray, T) -> T
): BufferedNDRingElement<T, R> {
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<T>,
b: NDBuffer<T>,
transform: R.(T, T) -> T
): BufferedNDRingElement<T, R> {
check(a, b)
return BufferedNDRingElement(
this,
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) })
}
override fun NDBuffer<T>.toElement(): RingElement<NDBuffer<T>, *, out BufferedNDRing<T, R>> =
BufferedNDRingElement(this@BoxingNDRing, buffer)
}

View File

@ -82,6 +82,8 @@ interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T,
operator fun T.plus(arg: N) = map(arg) { value -> add(this@plus, value) } operator fun T.plus(arg: N) = map(arg) { value -> add(this@plus, value) }
operator fun T.minus(arg: N) = map(arg) { value -> add(-this@minus, value) } operator fun T.minus(arg: N) = map(arg) { value -> add(-this@minus, value) }
companion object
} }
/** /**
@ -98,6 +100,8 @@ interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N>
operator fun N.times(arg: T) = map(this) { value -> multiply(arg, value) } 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) } operator fun T.times(arg: N) = map(arg) { value -> multiply(this@times, value) }
companion object
} }
/** /**
@ -132,7 +136,7 @@ interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F,
/** /**
* Create a nd-field with boxing generic buffer * Create a nd-field with boxing generic buffer
*/ */
fun <T : Any, F : Field<T>> buffered( fun <T : Any, F : Field<T>> boxing(
field: F, field: F,
vararg shape: Int, vararg shape: Int,
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing bufferFactory: BufferFactory<T> = Buffer.Companion::boxing

View File

@ -41,7 +41,7 @@ interface NDElement<T, C, N : NDStructure<T>> : NDStructure<T> {
/** /**
* Simple boxing NDArray * Simple boxing NDArray
*/ */
fun <T : Any, F : Field<T>> buffered( fun <T : Any, F : Field<T>> boxing(
shape: IntArray, shape: IntArray,
field: F, field: F,
initializer: F.(IntArray) -> T initializer: F.(IntArray) -> T

View File

@ -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<BigInteger> {
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<BigDecimal> {
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<BigInteger> =
boxing(size, initializer)
inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInteger): MutableBuffer<BigInteger> =
boxing(size, initializer)
fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing<BigInteger, BigIntegerRing> =
BoxingNDRing(shape, BigIntegerRing, Buffer.Companion::bigInt)
fun NDElement.Companion.bigInt(
vararg shape: Int,
initializer: BigIntegerRing.(IntArray) -> BigInteger
): BufferedNDRingElement<BigInteger, BigIntegerRing> =
NDAlgebra.bigInt(*shape).produce(initializer)