diff --git a/benchmarks/src/main/kotlin/scientifik/kmath/structures/NDStructureBenchmark.kt b/benchmarks/src/main/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt similarity index 95% rename from benchmarks/src/main/kotlin/scientifik/kmath/structures/NDStructureBenchmark.kt rename to benchmarks/src/main/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt index 77f0a2737..fcacc44f5 100644 --- a/benchmarks/src/main/kotlin/scientifik/kmath/structures/NDStructureBenchmark.kt +++ b/benchmarks/src/main/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt @@ -5,9 +5,9 @@ import kotlin.system.measureTimeMillis fun main(args: Array) { val dim = 1000 - val n = 100 + val n = 1000 - val bufferedField = NDField.buffered(intArrayOf(dim, dim), RealField) + val bufferedField = NDField.auto(intArrayOf(dim, dim), RealField) val specializedField = NDField.real(intArrayOf(dim, dim)) val genericField = NDField.generic(intArrayOf(dim, dim), RealField) val lazyNDField = NDField.lazy(intArrayOf(dim, dim), RealField) @@ -20,7 +20,6 @@ fun main(args: Array) { // } - val doubleTime = measureTimeMillis { bufferedField.run { diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt index 63c78973a..1fc48264a 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt @@ -59,7 +59,7 @@ interface MatrixSpace> : Space> { * Automatic buffered matrix, unboxed if it is possible */ inline fun > smart(rows: Int, columns: Int, ring: R): MatrixSpace = - buffered(rows, columns, ring, ::inlineBuffer) + buffered(rows, columns, ring, ::autoBuffer) } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt index 9aaa28203..4cbed0b42 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt @@ -56,7 +56,7 @@ interface VectorSpace> : Space> { * Automatic buffered vector, unboxed if it is possible */ inline fun > smart(size: Int, space: S): VectorSpace = - buffered(size, space, ::inlineBuffer) + buffered(size, space, ::autoBuffer) } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt index ec9268b21..60b0e9869 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt @@ -8,6 +8,20 @@ abstract class StridedNDField>(shape: IntArray, elementField: F) val strides = DefaultStrides(shape) abstract fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer + + /** + * Convert any [NDStructure] to buffered structure using strides from this context. + * If the structure is already [NDBuffer], conversion is free. If not, it could be expensive because iteration over indexes + * + * If the argument is [NDBuffer] with different strides structure, the new element will be produced. + */ + fun NDStructure.toBuffer(): NDBuffer { + return if (this is NDBuffer && this.strides == this@StridedNDField.strides) { + this + } else { + produce { index -> get(index) } + } + } } @@ -26,29 +40,26 @@ class BufferNDField>( override val zero by lazy { produce { zero } } override val one by lazy { produce { one } } - @Suppress("OVERRIDE_BY_INLINE") - override inline fun produce(crossinline initializer: F.(IntArray) -> T): BufferNDElement = + override fun produce(initializer: F.(IntArray) -> T): BufferNDElement = BufferNDElement( this, - bufferFactory(strides.linearSize) { offset -> elementField.initializer(strides.index(offset)) }) + buildBuffer(strides.linearSize) { offset -> elementField.initializer(strides.index(offset)) }) - @Suppress("OVERRIDE_BY_INLINE") - override inline fun map(arg: NDBuffer, crossinline transform: F.(T) -> T): BufferNDElement { + override fun map(arg: NDBuffer, transform: F.(T) -> T): BufferNDElement { check(arg) return BufferNDElement( this, - bufferFactory(arg.strides.linearSize) { offset -> elementField.transform(arg.buffer[offset]) }) + buildBuffer(arg.strides.linearSize) { offset -> elementField.transform(arg.buffer[offset]) }) } - @Suppress("OVERRIDE_BY_INLINE") - override inline fun mapIndexed( + override fun mapIndexed( arg: NDBuffer, - crossinline transform: F.(index: IntArray, T) -> T + transform: F.(index: IntArray, T) -> T ): BufferNDElement { check(arg) return BufferNDElement( this, - bufferFactory(arg.strides.linearSize) { offset -> + buildBuffer(arg.strides.linearSize) { offset -> elementField.transform( arg.strides.index(offset), arg.buffer[offset] @@ -56,30 +67,15 @@ class BufferNDField>( }) } - @Suppress("OVERRIDE_BY_INLINE") - override inline fun combine( + override fun combine( a: NDBuffer, b: NDBuffer, - crossinline transform: F.(T, T) -> T + transform: F.(T, T) -> T ): BufferNDElement { check(a, b) return BufferNDElement( this, - bufferFactory(strides.linearSize) { offset -> elementField.transform(a.buffer[offset], b.buffer[offset]) }) - } - - /** - * Convert any [NDStructure] to buffered structure using strides from this context. - * If the structure is already [NDBuffer], conversion is free. If not, it could be expensive because iteration over indexes - * - * If the argument is [NDBuffer] with different strides structure, the new element will be produced. - */ - fun NDStructure.toBuffer(): NDBuffer { - return if (this is NDBuffer && this.strides == this@BufferNDField.strides) { - this - } else { - produce { index -> get(index) } - } + buildBuffer(strides.linearSize) { offset -> elementField.transform(a.buffer[offset], b.buffer[offset]) }) } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt index e3ca79558..2c08427b3 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -140,7 +140,7 @@ inline fun boxingBuffer(size: Int, initializer: (Int) -> T): Buffer = Lis * Create most appropriate immutable buffer for given type avoiding boxing wherever possible */ @Suppress("UNCHECKED_CAST") -inline fun inlineBuffer(size: Int, initializer: (Int) -> T): Buffer { +inline fun autoBuffer(size: Int, initializer: (Int) -> T): Buffer { return when (T::class) { Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer @@ -159,7 +159,7 @@ inline fun boxingMutableBuffer(size: Int, initializer: (Int) -> T): Mu * Create most appropriate mutable buffer for given type avoiding boxing wherever possible */ @Suppress("UNCHECKED_CAST") -inline fun inlineMutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer { +inline fun autoMutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer { return when (T::class) { Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer 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 4bed26510..6beea1a04 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt @@ -51,7 +51,7 @@ object NDElements { noinline initializer: F.(IntArray) -> T ): GenericNDElement { val ndField = GenericNDField(shape, field) - val structure = ndStructure(shape, ::inlineBuffer) { index -> field.initializer(index) } + val structure = ndStructure(shape, ::autoBuffer) { index -> field.initializer(index) } return GenericNDElement(ndField, structure) } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt index dde406c51..9ed82faa1 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt @@ -71,10 +71,11 @@ interface NDField, N : NDStructure> : Field { fun > generic(shape: IntArray, field: F) = GenericNDField(shape, field) /** - * Create a most suitable implementation for nd-field using reified class + * Create a most suitable implementation for nd-field using reified class. */ - inline fun > buffered(shape: IntArray, field: F) = - BufferNDField(shape, field, ::inlineBuffer) + inline fun > auto(shape: IntArray, field: F): BufferNDField { + return BufferNDField(shape, field, ::autoBuffer) + } } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt index 617c99a9d..0852271e4 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt @@ -163,7 +163,7 @@ data class BufferNDStructure( * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferNDStructure] */ inline fun NDStructure.mapToBuffer( - factory: BufferFactory = ::inlineBuffer, + factory: BufferFactory = ::autoBuffer, crossinline transform: (T) -> R ): BufferNDStructure { return if (this is BufferNDStructure) { @@ -186,7 +186,7 @@ fun ndStructure(strides: Strides, bufferFactory: BufferFactory = ::boxing * Inline create NDStructure with non-boxing buffer implementation if it is possible */ inline fun inlineNDStructure(strides: Strides, crossinline initializer: (IntArray) -> T) = - BufferNDStructure(strides, inlineBuffer(strides.linearSize) { i -> initializer(strides.index(i)) }) + BufferNDStructure(strides, autoBuffer(strides.linearSize) { i -> initializer(strides.index(i)) }) fun ndStructure(shape: IntArray, bufferFactory: BufferFactory = ::boxingBuffer, initializer: (IntArray) -> T) = ndStructure(DefaultStrides(shape), bufferFactory, initializer) @@ -195,7 +195,7 @@ inline fun inlineNdStructure(shape: IntArray, crossinline init inlineNDStructure(DefaultStrides(shape), initializer) /** - * Mutable ND buffer based on linear [inlineBuffer] + * Mutable ND buffer based on linear [autoBuffer] */ class MutableBufferNDStructure( override val strides: Strides, @@ -222,7 +222,7 @@ fun mutableNdStructure( MutableBufferNDStructure(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) inline fun inlineMutableNdStructure(strides: Strides, crossinline initializer: (IntArray) -> T) = - MutableBufferNDStructure(strides, inlineMutableBuffer(strides.linearSize) { i -> initializer(strides.index(i)) }) + MutableBufferNDStructure(strides, autoMutableBuffer(strides.linearSize) { i -> initializer(strides.index(i)) }) fun mutableNdStructure( shape: IntArray, diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt index 5bd58eb6e..82d399436 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt @@ -8,32 +8,30 @@ class RealNDField(shape: IntArray) : StridedNDField(shape, RealField), ExtendedNDField> { - override fun buildBuffer(size: Int, initializer: (Int) -> Double): Buffer = - DoubleBuffer(DoubleArray(size, initializer)) + @Suppress("OVERRIDE_BY_INLINE") + override inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer = + DoubleBuffer(DoubleArray(size){initializer(it)}) /** * Inline transform an NDStructure to */ - @Suppress("OVERRIDE_BY_INLINE") - override inline fun map( + override fun map( arg: NDBuffer, - crossinline transform: RealField.(Double) -> Double + transform: RealField.(Double) -> Double ): RealNDElement { check(arg) - val array = DoubleArray(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } - return BufferNDElement(this, DoubleBuffer(array)) + val array = buildBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } + return BufferNDElement(this, array) } - @Suppress("OVERRIDE_BY_INLINE") - override inline fun produce(crossinline initializer: RealField.(IntArray) -> Double): RealNDElement { - val array = DoubleArray(strides.linearSize) { offset -> elementField.initializer(strides.index(offset)) } - return BufferNDElement(this, DoubleBuffer(array)) + override fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { + val array = buildBuffer(strides.linearSize) { offset -> elementField.initializer(strides.index(offset)) } + return BufferNDElement(this, array) } - @Suppress("OVERRIDE_BY_INLINE") - override inline fun mapIndexed( + override fun mapIndexed( arg: NDBuffer, - crossinline transform: RealField.(index: IntArray, Double) -> Double + transform: RealField.(index: IntArray, Double) -> Double ): BufferNDElement { check(arg) return BufferNDElement( @@ -46,11 +44,10 @@ class RealNDField(shape: IntArray) : }) } - @Suppress("OVERRIDE_BY_INLINE") - override inline fun combine( + override fun combine( a: NDBuffer, b: NDBuffer, - crossinline transform: RealField.(Double, Double) -> Double + transform: RealField.(Double, Double) -> Double ): BufferNDElement { check(a, b) return BufferNDElement( @@ -105,4 +102,4 @@ operator fun RealNDElement.plus(arg: Double) = * Subtraction operation between [BufferNDElement] and single element */ operator fun RealNDElement.minus(arg: Double) = - context.produceInline { i -> buffer[i] - arg } + context.produceInline { i -> buffer[i] - arg } \ No newline at end of file