DoubleBuffer -> RealBuffer. Number algebra refactoring.

This commit is contained in:
Alexander Nozik 2020-06-27 12:19:43 +03:00
parent ea8c0db854
commit 4b067f7a97
21 changed files with 205 additions and 145 deletions

View File

@ -2,7 +2,7 @@
Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`). Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`).
There are different types of buffers: There are different types of buffers:
* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays. * Primitive buffers wrapping like `RealBuffer` which are wrapping primitive arrays.
* Boxing `ListBuffer` wrapping a list * Boxing `ListBuffer` wrapping a list
* Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value * Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value
* `MemoryBuffer` allows direct allocation of objects in continuous memory block. * `MemoryBuffer` allows direct allocation of objects in continuous memory block.

View File

@ -10,8 +10,8 @@ import scientifik.kmath.operations.complex
class BufferBenchmark { class BufferBenchmark {
@Benchmark @Benchmark
fun genericDoubleBufferReadWrite() { fun genericRealBufferReadWrite() {
val buffer = DoubleBuffer(size){it.toDouble()} val buffer = RealBuffer(size){it.toDouble()}
(0 until size).forEach { (0 until size).forEach {
buffer[it] buffer[it]

View File

@ -6,7 +6,7 @@ fun main(args: Array<String>) {
val n = 6000 val n = 6000
val array = DoubleArray(n * n) { 1.0 } val array = DoubleArray(n * n) { 1.0 }
val buffer = DoubleBuffer(array) val buffer = RealBuffer(array)
val strides = DefaultStrides(intArrayOf(n, n)) val strides = DefaultStrides(intArrayOf(n, n))
val structure = BufferNDStructure(strides, buffer) val structure = BufferNDStructure(strides, buffer)

View File

@ -26,10 +26,10 @@ fun main(args: Array<String>) {
} }
println("Array mapping finished in $time2 millis") println("Array mapping finished in $time2 millis")
val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 }) val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
val time3 = measureTimeMillis { val time3 = measureTimeMillis {
val target = DoubleBuffer(DoubleArray(n * n)) val target = RealBuffer(DoubleArray(n * n))
val res = array.forEachIndexed { index, value -> val res = array.forEachIndexed { index, value ->
target[index] = value + 1 target[index] = value + 1
} }

View File

@ -18,7 +18,7 @@ object Transformations {
private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> = private fun Buffer<Complex>.toArray(): Array<org.apache.commons.math3.complex.Complex> =
Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) } Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) }
private fun Buffer<Double>.asArray() = if (this is DoubleBuffer) { private fun Buffer<Double>.asArray() = if (this is RealBuffer) {
array array
} else { } else {
DoubleArray(size) { i -> get(i) } DoubleArray(size) { i -> get(i) }

View File

@ -16,7 +16,7 @@
package scientifik.kmath.domains package scientifik.kmath.domains
import scientifik.kmath.linear.Point import scientifik.kmath.linear.Point
import scientifik.kmath.structures.DoubleBuffer import scientifik.kmath.structures.RealBuffer
import scientifik.kmath.structures.indices import scientifik.kmath.structures.indices
/** /**
@ -25,7 +25,7 @@ import scientifik.kmath.structures.indices
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
class HyperSquareDomain(private val lower: DoubleBuffer, private val upper: DoubleBuffer) : RealDomain { class HyperSquareDomain(private val lower: RealBuffer, private val upper: RealBuffer) : RealDomain {
override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i -> override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
point[i] in lower[i]..upper[i] point[i] in lower[i]..upper[i]
@ -49,7 +49,7 @@ class HyperSquareDomain(private val lower: DoubleBuffer, private val upper: Doub
else -> point[i] else -> point[i]
} }
} }
return DoubleBuffer(*res) return RealBuffer(*res)
} }
override fun volume(): Double { override fun volume(): Double {

View File

@ -30,11 +30,11 @@ object RealMatrixContext : GenericMatrixContext<Double, RealField> {
override val elementContext get() = RealField override val elementContext get() = RealField
override inline fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> Double): Matrix<Double> { override inline fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> Double): Matrix<Double> {
val buffer = DoubleBuffer(rows * columns) { offset -> initializer(offset / columns, offset % columns) } val buffer = RealBuffer(rows * columns) { offset -> initializer(offset / columns, offset % columns) }
return BufferMatrix(rows, columns, buffer) return BufferMatrix(rows, columns, buffer)
} }
override inline fun point(size: Int, initializer: (Int) -> Double): Point<Double> = DoubleBuffer(size,initializer) override inline fun point(size: Int, initializer: (Int) -> Double): Point<Double> = RealBuffer(size,initializer)
} }
class BufferMatrix<T : Any>( class BufferMatrix<T : Any>(
@ -102,7 +102,7 @@ infix fun BufferMatrix<Double>.dot(other: BufferMatrix<Double>): BufferMatrix<Do
val array = DoubleArray(this.rowNum * other.colNum) val array = DoubleArray(this.rowNum * other.colNum)
//convert to array to insure there is not memory indirection //convert to array to insure there is not memory indirection
fun Buffer<out Double>.unsafeArray(): DoubleArray = if (this is DoubleBuffer) { fun Buffer<out Double>.unsafeArray(): DoubleArray = if (this is RealBuffer) {
array array
} else { } else {
DoubleArray(size) { get(it) } DoubleArray(size) { get(it) }
@ -119,6 +119,6 @@ infix fun BufferMatrix<Double>.dot(other: BufferMatrix<Double>): BufferMatrix<Do
} }
} }
val buffer = DoubleBuffer(array) val buffer = RealBuffer(array)
return BufferMatrix(rowNum, other.colNum, buffer) return BufferMatrix(rowNum, other.colNum, buffer)
} }

View File

@ -37,9 +37,9 @@ interface Buffer<T> {
companion object { companion object {
inline fun real(size: Int, initializer: (Int) -> Double): DoubleBuffer { inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer {
val array = DoubleArray(size) { initializer(it) } val array = DoubleArray(size) { initializer(it) }
return DoubleBuffer(array) return RealBuffer(array)
} }
/** /**
@ -51,7 +51,7 @@ interface Buffer<T> {
inline fun <T : Any> auto(type: KClass<T>, size: Int, crossinline initializer: (Int) -> T): Buffer<T> { inline fun <T : Any> auto(type: KClass<T>, size: Int, crossinline initializer: (Int) -> T): Buffer<T> {
//TODO add resolution based on Annotation or companion resolution //TODO add resolution based on Annotation or companion resolution
return when (type) { return when (type) {
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T> Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as Buffer<T> Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as Buffer<T>
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T> Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T>
Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as Buffer<T> Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as Buffer<T>
@ -93,7 +93,7 @@ interface MutableBuffer<T> : Buffer<T> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> { inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> {
return when (type) { return when (type) {
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer<T> Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer<T>
Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as MutableBuffer<T> Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as MutableBuffer<T>
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer<T> Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer<T>
Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as MutableBuffer<T> Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as MutableBuffer<T>
@ -109,12 +109,11 @@ interface MutableBuffer<T> : Buffer<T> {
auto(T::class, size, initializer) auto(T::class, size, initializer)
val real: MutableBufferFactory<Double> = { size: Int, initializer: (Int) -> Double -> val real: MutableBufferFactory<Double> = { size: Int, initializer: (Int) -> Double ->
DoubleBuffer(DoubleArray(size) { initializer(it) }) RealBuffer(DoubleArray(size) { initializer(it) })
} }
} }
} }
inline class ListBuffer<T>(val list: List<T>) : Buffer<T> { inline class ListBuffer<T>(val list: List<T>) : Buffer<T> {
override val size: Int override val size: Int
@ -163,57 +162,6 @@ class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> {
fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this) fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> {
override val size: Int get() = array.size
override fun get(index: Int): Short = array[index]
override fun set(index: Int, value: Short) {
array[index] = value
}
override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Short> = ShortBuffer(array.copyOf())
}
fun ShortArray.asBuffer() = ShortBuffer(this)
inline class IntBuffer(val array: IntArray) : MutableBuffer<Int> {
override val size: Int get() = array.size
override fun get(index: Int): Int = array[index]
override fun set(index: Int, value: Int) {
array[index] = value
}
override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Int> = IntBuffer(array.copyOf())
}
fun IntArray.asBuffer() = IntBuffer(this)
inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> {
override val size: Int get() = array.size
override fun get(index: Int): Long = array[index]
override fun set(index: Int, value: Long) {
array[index] = value
}
override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Long> = LongBuffer(array.copyOf())
}
fun LongArray.asBuffer() = LongBuffer(this)
inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> { inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> {
override val size: Int get() = buffer.size override val size: Int get() = buffer.size

View File

@ -0,0 +1,53 @@
package scientifik.kmath.structures
import kotlin.experimental.and
enum class ValueFlag(val mask: Byte) {
NAN(0b0000_0001),
MISSING(0b0000_0010),
NEGATIVE_INFINITY(0b0000_0100),
POSITIVE_INFINITY(0b0000_1000)
}
/**
* A buffer with flagged values
*/
interface FlaggedBuffer<T> : Buffer<T> {
fun getFlag(index: Int): Byte
}
/**
* The value is valid if all flags are down
*/
fun FlaggedBuffer<*>.isValid(index: Int) = getFlag(index) != 0.toByte()
fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag) = (getFlag(index) and flag.mask) != 0.toByte()
fun FlaggedBuffer<*>.isMissing(index: Int) = hasFlag(index, ValueFlag.MISSING)
/**
* A real buffer which supports flags for each value like NaN or Missing
*/
class FlaggedRealBuffer(val values: DoubleArray, val flags: ByteArray) : FlaggedBuffer<Double?>, Buffer<Double?> {
init {
require(values.size == flags.size) { "Values and flags must have the same dimensions" }
}
override fun getFlag(index: Int): Byte = flags[index]
override val size: Int get() = values.size
override fun get(index: Int): Double? = if (isValid(index)) values[index] else null
override fun iterator(): Iterator<Double?> = values.indices.asSequence().map {
if (isValid(it)) values[it] else null
}.iterator()
}
inline fun FlaggedRealBuffer.forEachValid(block: (Double) -> Unit) {
for(i in indices){
if(isValid(i)){
block(values[i])
}
}
}

View File

@ -0,0 +1,20 @@
package scientifik.kmath.structures
inline class IntBuffer(val array: IntArray) : MutableBuffer<Int> {
override val size: Int get() = array.size
override fun get(index: Int): Int = array[index]
override fun set(index: Int, value: Int) {
array[index] = value
}
override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Int> =
IntBuffer(array.copyOf())
}
fun IntArray.asBuffer() = IntBuffer(this)

View File

@ -0,0 +1,19 @@
package scientifik.kmath.structures
inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> {
override val size: Int get() = array.size
override fun get(index: Int): Long = array[index]
override fun set(index: Int, value: Long) {
array[index] = value
}
override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Long> =
LongBuffer(array.copyOf())
}
fun LongArray.asBuffer() = LongBuffer(this)

View File

@ -1,6 +1,6 @@
package scientifik.kmath.structures package scientifik.kmath.structures
inline class DoubleBuffer(val array: DoubleArray) : MutableBuffer<Double> { inline class RealBuffer(val array: DoubleArray) : MutableBuffer<Double> {
override val size: Int get() = array.size override val size: Int get() = array.size
override fun get(index: Int): Double = array[index] override fun get(index: Int): Double = array[index]
@ -12,23 +12,23 @@ inline class DoubleBuffer(val array: DoubleArray) : MutableBuffer<Double> {
override fun iterator() = array.iterator() override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Double> = override fun copy(): MutableBuffer<Double> =
DoubleBuffer(array.copyOf()) RealBuffer(array.copyOf())
} }
@Suppress("FunctionName") @Suppress("FunctionName")
inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) inline fun RealBuffer(size: Int, init: (Int) -> Double): RealBuffer = RealBuffer(DoubleArray(size) { init(it) })
@Suppress("FunctionName") @Suppress("FunctionName")
fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles) fun RealBuffer(vararg doubles: Double): RealBuffer = RealBuffer(doubles)
/** /**
* Transform buffer of doubles into array for high performance operations * Transform buffer of doubles into array for high performance operations
*/ */
val MutableBuffer<out Double>.array: DoubleArray val MutableBuffer<out Double>.array: DoubleArray
get() = if (this is DoubleBuffer) { get() = if (this is RealBuffer) {
array array
} else { } else {
DoubleArray(size) { get(it) } DoubleArray(size) { get(it) }
} }
fun DoubleArray.asBuffer() = DoubleBuffer(this) fun DoubleArray.asBuffer() = RealBuffer(this)

View File

@ -9,143 +9,143 @@ import kotlin.math.*
* A simple field over linear buffers of [Double] * A simple field over linear buffers of [Double]
*/ */
object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> { object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
override fun add(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer { override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " }
return if (a is DoubleBuffer && b is DoubleBuffer) { return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array val aArray = a.array
val bArray = b.array val bArray = b.array
DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) RealBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] })
} else { } else {
DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) RealBuffer(DoubleArray(a.size) { a[it] + b[it] })
} }
} }
override fun multiply(a: Buffer<Double>, k: Number): DoubleBuffer { override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
val kValue = k.toDouble() val kValue = k.toDouble()
return if (a is DoubleBuffer) { return if (a is RealBuffer) {
val aArray = a.array val aArray = a.array
DoubleBuffer(DoubleArray(a.size) { aArray[it] * kValue }) RealBuffer(DoubleArray(a.size) { aArray[it] * kValue })
} else { } else {
DoubleBuffer(DoubleArray(a.size) { a[it] * kValue }) RealBuffer(DoubleArray(a.size) { a[it] * kValue })
} }
} }
override fun multiply(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer { override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " }
return if (a is DoubleBuffer && b is DoubleBuffer) { return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array val aArray = a.array
val bArray = b.array val bArray = b.array
DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) RealBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] })
} else { } else {
DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] }) RealBuffer(DoubleArray(a.size) { a[it] * b[it] })
} }
} }
override fun divide(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer { override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " }
return if (a is DoubleBuffer && b is DoubleBuffer) { return if (a is RealBuffer && b is RealBuffer) {
val aArray = a.array val aArray = a.array
val bArray = b.array val bArray = b.array
DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) RealBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] })
} else { } else {
DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] }) RealBuffer(DoubleArray(a.size) { a[it] / b[it] })
} }
} }
override fun sin(arg: Buffer<Double>): DoubleBuffer { override fun sin(arg: Buffer<Double>): RealBuffer {
return if (arg is DoubleBuffer) { return if (arg is RealBuffer) {
val array = arg.array val array = arg.array
DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) RealBuffer(DoubleArray(arg.size) { sin(array[it]) })
} else { } else {
DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) RealBuffer(DoubleArray(arg.size) { sin(arg[it]) })
} }
} }
override fun cos(arg: Buffer<Double>): DoubleBuffer { override fun cos(arg: Buffer<Double>): RealBuffer {
return if (arg is DoubleBuffer) { return if (arg is RealBuffer) {
val array = arg.array val array = arg.array
DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) RealBuffer(DoubleArray(arg.size) { cos(array[it]) })
} else { } else {
DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) RealBuffer(DoubleArray(arg.size) { cos(arg[it]) })
} }
} }
override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer { override fun power(arg: Buffer<Double>, pow: Number): RealBuffer {
return if (arg is DoubleBuffer) { return if (arg is RealBuffer) {
val array = arg.array val array = arg.array
DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) RealBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) })
} else { } else {
DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) RealBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) })
} }
} }
override fun exp(arg: Buffer<Double>): DoubleBuffer { override fun exp(arg: Buffer<Double>): RealBuffer {
return if (arg is DoubleBuffer) { return if (arg is RealBuffer) {
val array = arg.array val array = arg.array
DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) RealBuffer(DoubleArray(arg.size) { exp(array[it]) })
} else { } else {
DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) RealBuffer(DoubleArray(arg.size) { exp(arg[it]) })
} }
} }
override fun ln(arg: Buffer<Double>): DoubleBuffer { override fun ln(arg: Buffer<Double>): RealBuffer {
return if (arg is DoubleBuffer) { return if (arg is RealBuffer) {
val array = arg.array val array = arg.array
DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) RealBuffer(DoubleArray(arg.size) { ln(array[it]) })
} else { } else {
DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) RealBuffer(DoubleArray(arg.size) { ln(arg[it]) })
} }
} }
} }
class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> { class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
override val zero: Buffer<Double> by lazy { DoubleBuffer(size) { 0.0 } } override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } }
override val one: Buffer<Double> by lazy { DoubleBuffer(size) { 1.0 } } override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } }
override fun add(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer { override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.add(a, b) return RealBufferFieldOperations.add(a, b)
} }
override fun multiply(a: Buffer<Double>, k: Number): DoubleBuffer { override fun multiply(a: Buffer<Double>, k: Number): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.multiply(a, k) return RealBufferFieldOperations.multiply(a, k)
} }
override fun multiply(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer { override fun multiply(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.multiply(a, b) return RealBufferFieldOperations.multiply(a, b)
} }
override fun divide(a: Buffer<Double>, b: Buffer<Double>): DoubleBuffer { override fun divide(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } require(a.size == size) { "The buffer size ${a.size} does not match context size $size" }
return RealBufferFieldOperations.divide(a, b) return RealBufferFieldOperations.divide(a, b)
} }
override fun sin(arg: Buffer<Double>): DoubleBuffer { override fun sin(arg: Buffer<Double>): RealBuffer {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.sin(arg) return RealBufferFieldOperations.sin(arg)
} }
override fun cos(arg: Buffer<Double>): DoubleBuffer { override fun cos(arg: Buffer<Double>): RealBuffer {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.cos(arg) return RealBufferFieldOperations.cos(arg)
} }
override fun power(arg: Buffer<Double>, pow: Number): DoubleBuffer { override fun power(arg: Buffer<Double>, pow: Number): RealBuffer {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.power(arg, pow) return RealBufferFieldOperations.power(arg, pow)
} }
override fun exp(arg: Buffer<Double>): DoubleBuffer { override fun exp(arg: Buffer<Double>): RealBuffer {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.exp(arg) return RealBufferFieldOperations.exp(arg)
} }
override fun ln(arg: Buffer<Double>): DoubleBuffer { override fun ln(arg: Buffer<Double>): RealBuffer {
require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" }
return RealBufferFieldOperations.ln(arg) return RealBufferFieldOperations.ln(arg)
} }

View File

@ -16,7 +16,7 @@ class RealNDField(override val shape: IntArray) :
override val one by lazy { produce { one } } override val one by lazy { produce { one } }
inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer<Double> = inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer<Double> =
DoubleBuffer(DoubleArray(size) { initializer(it) }) RealBuffer(DoubleArray(size) { initializer(it) })
/** /**
* Inline transform an NDStructure to * Inline transform an NDStructure to
@ -82,7 +82,7 @@ class RealNDField(override val shape: IntArray) :
*/ */
inline fun BufferedNDField<Double, RealField>.produceInline(crossinline initializer: RealField.(Int) -> Double): RealNDElement { inline fun BufferedNDField<Double, RealField>.produceInline(crossinline initializer: RealField.(Int) -> Double): RealNDElement {
val array = DoubleArray(strides.linearSize) { offset -> RealField.initializer(offset) } val array = DoubleArray(strides.linearSize) { offset -> RealField.initializer(offset) }
return BufferedNDFieldElement(this, DoubleBuffer(array)) return BufferedNDFieldElement(this, RealBuffer(array))
} }
/** /**
@ -96,7 +96,7 @@ inline fun RealNDElement.mapIndexed(crossinline transform: RealField.(index: Int
*/ */
inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> Double): RealNDElement { inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> Double): RealNDElement {
val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) } val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) }
return BufferedNDFieldElement(context, DoubleBuffer(array)) return BufferedNDFieldElement(context, RealBuffer(array))
} }
/** /**

View File

@ -0,0 +1,20 @@
package scientifik.kmath.structures
inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> {
override val size: Int get() = array.size
override fun get(index: Int): Short = array[index]
override fun set(index: Int, value: Short) {
array[index] = value
}
override fun iterator() = array.iterator()
override fun copy(): MutableBuffer<Short> =
ShortBuffer(array.copyOf())
}
fun ShortArray.asBuffer() = ShortBuffer(this)

View File

@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.*
import scientifik.kmath.chains.BlockingRealChain import scientifik.kmath.chains.BlockingRealChain
import scientifik.kmath.structures.Buffer import scientifik.kmath.structures.Buffer
import scientifik.kmath.structures.BufferFactory import scientifik.kmath.structures.BufferFactory
import scientifik.kmath.structures.DoubleBuffer import scientifik.kmath.structures.RealBuffer
import scientifik.kmath.structures.asBuffer import scientifik.kmath.structures.asBuffer
/** /**
@ -45,7 +45,7 @@ fun <T> Flow<T>.chunked(bufferSize: Int, bufferFactory: BufferFactory<T>): Flow<
/** /**
* Specialized flow chunker for real buffer * Specialized flow chunker for real buffer
*/ */
fun Flow<Double>.chunked(bufferSize: Int): Flow<DoubleBuffer> = flow { fun Flow<Double>.chunked(bufferSize: Int): Flow<RealBuffer> = flow {
require(bufferSize > 0) { "Resulting chunk size must be more than zero" } require(bufferSize > 0) { "Resulting chunk size must be more than zero" }
if (this@chunked is BlockingRealChain) { if (this@chunked is BlockingRealChain) {
@ -61,13 +61,13 @@ fun Flow<Double>.chunked(bufferSize: Int): Flow<DoubleBuffer> = flow {
array[counter] = element array[counter] = element
counter++ counter++
if (counter == bufferSize) { if (counter == bufferSize) {
val buffer = DoubleBuffer(array) val buffer = RealBuffer(array)
emit(buffer) emit(buffer)
counter = 0 counter = 0
} }
} }
if (counter > 0) { if (counter > 0) {
emit(DoubleBuffer(counter) { array[it] }) emit(RealBuffer(counter) { array[it] })
} }
} }
} }

View File

@ -7,7 +7,7 @@ import scientifik.kmath.operations.Norm
import scientifik.kmath.operations.RealField import scientifik.kmath.operations.RealField
import scientifik.kmath.operations.SpaceElement import scientifik.kmath.operations.SpaceElement
import scientifik.kmath.structures.Buffer import scientifik.kmath.structures.Buffer
import scientifik.kmath.structures.DoubleBuffer import scientifik.kmath.structures.RealBuffer
import scientifik.kmath.structures.asBuffer import scientifik.kmath.structures.asBuffer
import scientifik.kmath.structures.asIterable import scientifik.kmath.structures.asIterable
import kotlin.math.sqrt import kotlin.math.sqrt
@ -41,7 +41,7 @@ inline class RealVector(private val point: Point<Double>) :
private val spaceCache = HashMap<Int, BufferVectorSpace<Double, RealField>>() private val spaceCache = HashMap<Int, BufferVectorSpace<Double, RealField>>()
inline operator fun invoke(dim: Int, initializer: (Int) -> Double) = inline operator fun invoke(dim: Int, initializer: (Int) -> Double) =
RealVector(DoubleBuffer(dim, initializer)) RealVector(RealBuffer(dim, initializer))
operator fun invoke(vararg values: Double): RealVector = values.asVector() operator fun invoke(vararg values: Double): RealVector = values.asVector()

View File

@ -1,8 +1,8 @@
package scientifik.kmath.real package scientifik.kmath.real
import scientifik.kmath.structures.DoubleBuffer import scientifik.kmath.structures.RealBuffer
/** /**
* Simplified [DoubleBuffer] to array comparison * Simplified [RealBuffer] to array comparison
*/ */
fun DoubleBuffer.contentEquals(vararg doubles: Double) = array.contentEquals(doubles) fun RealBuffer.contentEquals(vararg doubles: Double) = array.contentEquals(doubles)

View File

@ -5,8 +5,8 @@ import scientifik.kmath.linear.RealMatrixContext.elementContext
import scientifik.kmath.linear.VirtualMatrix import scientifik.kmath.linear.VirtualMatrix
import scientifik.kmath.operations.sum import scientifik.kmath.operations.sum
import scientifik.kmath.structures.Buffer import scientifik.kmath.structures.Buffer
import scientifik.kmath.structures.DoubleBuffer
import scientifik.kmath.structures.Matrix import scientifik.kmath.structures.Matrix
import scientifik.kmath.structures.RealBuffer
import scientifik.kmath.structures.asIterable import scientifik.kmath.structures.asIterable
import kotlin.math.pow import kotlin.math.pow
@ -133,22 +133,22 @@ fun Matrix<Double>.extractColumns(columnRange: IntRange): RealMatrix =
fun Matrix<Double>.extractColumn(columnIndex: Int): RealMatrix = fun Matrix<Double>.extractColumn(columnIndex: Int): RealMatrix =
extractColumns(columnIndex..columnIndex) extractColumns(columnIndex..columnIndex)
fun Matrix<Double>.sumByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> fun Matrix<Double>.sumByColumn(): RealBuffer = RealBuffer(colNum) { j ->
val column = columns[j] val column = columns[j]
with(elementContext) { with(elementContext) {
sum(column.asIterable()) sum(column.asIterable())
} }
} }
fun Matrix<Double>.minByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> fun Matrix<Double>.minByColumn(): RealBuffer = RealBuffer(colNum) { j ->
columns[j].asIterable().min() ?: throw Exception("Cannot produce min on empty column") columns[j].asIterable().min() ?: throw Exception("Cannot produce min on empty column")
} }
fun Matrix<Double>.maxByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> fun Matrix<Double>.maxByColumn(): RealBuffer = RealBuffer(colNum) { j ->
columns[j].asIterable().max() ?: throw Exception("Cannot produce min on empty column") columns[j].asIterable().max() ?: throw Exception("Cannot produce min on empty column")
} }
fun Matrix<Double>.averageByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> fun Matrix<Double>.averageByColumn(): RealBuffer = RealBuffer(colNum) { j ->
columns[j].asIterable().average() columns[j].asIterable().average()
} }

View File

@ -3,7 +3,7 @@ package scientifik.kmath.histogram
import scientifik.kmath.domains.Domain import scientifik.kmath.domains.Domain
import scientifik.kmath.linear.Point import scientifik.kmath.linear.Point
import scientifik.kmath.structures.ArrayBuffer import scientifik.kmath.structures.ArrayBuffer
import scientifik.kmath.structures.DoubleBuffer import scientifik.kmath.structures.RealBuffer
/** /**
* The bin in the histogram. The histogram is by definition always done in the real space * The bin in the histogram. The histogram is by definition always done in the real space
@ -43,9 +43,9 @@ interface MutableHistogram<T : Any, out B : Bin<T>> : Histogram<T, B> {
fun <T : Any> MutableHistogram<T, *>.put(vararg point: T) = put(ArrayBuffer(point)) fun <T : Any> MutableHistogram<T, *>.put(vararg point: T) = put(ArrayBuffer(point))
fun MutableHistogram<Double, *>.put(vararg point: Number) = fun MutableHistogram<Double, *>.put(vararg point: Number) =
put(DoubleBuffer(point.map { it.toDouble() }.toDoubleArray())) put(RealBuffer(point.map { it.toDouble() }.toDoubleArray()))
fun MutableHistogram<Double, *>.put(vararg point: Double) = put(DoubleBuffer(point)) fun MutableHistogram<Double, *>.put(vararg point: Double) = put(RealBuffer(point))
fun <T : Any> MutableHistogram<T, *>.fill(sequence: Iterable<Point<T>>) = sequence.forEach { put(it) } fun <T : Any> MutableHistogram<T, *>.fill(sequence: Iterable<Point<T>>) = sequence.forEach { put(it) }

View File

@ -50,7 +50,7 @@ class RealHistogram(
override val dimension: Int get() = lower.size override val dimension: Int get() = lower.size
private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } private val binSize = RealBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] }
init { init {
// argument checks // argument checks