From 334dadc6bfdd2d1a66d60985a281f74937b49528 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 30 Dec 2018 19:48:32 +0300 Subject: [PATCH] Specialized BufferNDField --- {kmath-jmh => benchmarks}/build.gradle | 0 .../kmath/structures/ArrayBenchmark.kt | 0 .../kmath/structures/BufferBenchmark.kt | 0 .../structures/StructureReadBenchmark.kt | 36 +++ .../structures/StructureWriteBenchmark.kt | 39 ++++ .../kotlin/scientifik/kmath/misc/Grids.kt | 2 +- .../kmath/structures/BufferNDField.kt | 22 ++ .../kmath/structures/ExtendedNDField.kt | 9 +- .../scientifik/kmath/structures/NDField.kt | 206 +++++++++--------- .../kmath/structures/NDStructure.kt | 17 +- .../kmath/structures/GenericNDFieldTest.kt | 16 -- .../kmath/structures/NDFieldTest.kt | 13 ++ .../kmath/structures/NumberNDFieldTest.kt | 13 +- .../scientifik/kmath/structures/LazyField.kt | 7 + .../kmath/structures/LazyNDField.kt | 14 +- .../kmath/structures/LazyNDFieldTest.kt | 2 +- settings.gradle.kts | 2 +- 17 files changed, 259 insertions(+), 139 deletions(-) rename {kmath-jmh => benchmarks}/build.gradle (100%) rename {kmath-jmh => benchmarks}/src/jmh/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt (100%) rename {kmath-jmh => benchmarks}/src/jmh/kotlin/scientifik/kmath/structures/BufferBenchmark.kt (100%) create mode 100644 benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt create mode 100644 benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt create mode 100644 kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt delete mode 100644 kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/GenericNDFieldTest.kt create mode 100644 kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt create mode 100644 kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyField.kt diff --git a/kmath-jmh/build.gradle b/benchmarks/build.gradle similarity index 100% rename from kmath-jmh/build.gradle rename to benchmarks/build.gradle diff --git a/kmath-jmh/src/jmh/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt b/benchmarks/src/jmh/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt similarity index 100% rename from kmath-jmh/src/jmh/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt rename to benchmarks/src/jmh/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt diff --git a/kmath-jmh/src/jmh/kotlin/scientifik/kmath/structures/BufferBenchmark.kt b/benchmarks/src/jmh/kotlin/scientifik/kmath/structures/BufferBenchmark.kt similarity index 100% rename from kmath-jmh/src/jmh/kotlin/scientifik/kmath/structures/BufferBenchmark.kt rename to benchmarks/src/jmh/kotlin/scientifik/kmath/structures/BufferBenchmark.kt diff --git a/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt b/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt new file mode 100644 index 000000000..ecfb4ab20 --- /dev/null +++ b/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt @@ -0,0 +1,36 @@ +package scientifik.kmath.structures + +import kotlin.system.measureTimeMillis + +fun main(args: Array) { + val n = 6000 + + val array = DoubleArray(n * n) { 1.0 } + val buffer = DoubleBuffer(array) + val strides = DefaultStrides(intArrayOf(n, n)) + + val structure = BufferNDStructure(strides, buffer) + + measureTimeMillis { + var res: Double = 0.0 + strides.indices().forEach { res = structure[it] } + } // warmup + + val time1 = measureTimeMillis { + var res: Double = 0.0 + strides.indices().forEach { res = structure[it] } + } + println("Structure reading finished in $time1 millis") + + val time2 = measureTimeMillis { + var res: Double = 0.0 + strides.indices().forEach { res = buffer[strides.offset(it)] } + } + println("Buffer reading finished in $time2 millis") + + val time3 = measureTimeMillis { + var res: Double = 0.0 + strides.indices().forEach { res = array[strides.offset(it)] } + } + println("Array reading finished in $time3 millis") +} \ No newline at end of file diff --git a/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt b/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt new file mode 100644 index 000000000..538993d8d --- /dev/null +++ b/benchmarks/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt @@ -0,0 +1,39 @@ +package scientifik.kmath.structures + +import kotlin.system.measureTimeMillis + + + +fun main(args: Array) { + + val n = 6000 + + val structure = NdStructure(intArrayOf(n, n), DoubleBufferFactory) { 1.0 } + + structure.map { it + 1 } // warm-up + + val time1 = measureTimeMillis { + val res = structure.map { it + 1 } + } + println("Structure mapping finished in $time1 millis") + + val array = DoubleArray(n*n){1.0} + + val time2 = measureTimeMillis { + val target = DoubleArray(n*n) + val res = array.forEachIndexed{index, value -> + target[index] = value + 1 + } + } + println("Array mapping finished in $time2 millis") + + val buffer = DoubleBuffer(DoubleArray(n*n){1.0}) + + val time3 = measureTimeMillis { + val target = DoubleBuffer(DoubleArray(n*n)) + val res = array.forEachIndexed{index, value -> + target[index] = value + 1 + } + } + println("Buffer mapping finished in $time3 millis") +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt index b48afbdcc..c16b03608 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt @@ -32,6 +32,6 @@ fun ClosedFloatingPointRange.toSequence(step: Double): Sequence * Convert double range to array of evenly spaced doubles, where the size of array equals [numPoints] */ fun ClosedFloatingPointRange.toGrid(numPoints: Int): DoubleArray { - if (numPoints < 2) error("Can't create grid with less than two points") + if (numPoints < 2) error("Can't generic grid with less than two points") return DoubleArray(numPoints) { i -> start + (endInclusive - start) / (numPoints - 1) * i } } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt new file mode 100644 index 000000000..edf34c7b4 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferNDField.kt @@ -0,0 +1,22 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Field + +class BufferNDField>(override val shape: IntArray, override val field: F, val bufferFactory: BufferFactory) : NDField { + val strides = DefaultStrides(shape) + + override inline fun produce(crossinline initializer: F.(IntArray) -> T): NDElement { + return BufferNDElement(this, bufferFactory(strides.linearSize) { offset -> field.initializer(strides.index(offset)) }) + } +} + +class BufferNDElement>(override val context: BufferNDField, private val buffer: Buffer) : NDElement { + + override val self: NDStructure get() = this + override val shape: IntArray get() = context.shape + + override fun get(index: IntArray): T = buffer[context.strides.offset(index)] + + override fun elements(): Sequence> = context.strides.indices().map { it to get(it) } + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt index 915b09419..5fb9cc8c6 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt @@ -9,14 +9,15 @@ import scientifik.kmath.operations.TrigonometricOperations /** * NDField that supports [ExtendedField] operations on its elements */ -class ExtendedNDField>(shape: IntArray, field: F) : NDField(shape, field), +inline class ExtendedNDField>(private val ndField: NDField) : NDField, TrigonometricOperations>, PowerOperations>, ExponentialOperations> { - override fun produceStructure(initializer: F.(IntArray) -> T): NDStructure { - return NdStructure(shape, ::boxingBuffer) { field.initializer(it) } - } + override val shape: IntArray get() = ndField.shape + override val field: F get() = ndField.field + + override fun produce(initializer: F.(IntArray) -> T): NDElement = ndField.produce(initializer) override fun power(arg: NDStructure, pow: Double): NDElement { return produce { with(field) { power(arg[it], pow) } } 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 c06df4938..dedb0e6d3 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDField.kt @@ -15,28 +15,25 @@ class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : Run * @param field - operations field defined on individual array element * @param T the type of the element contained in NDArray */ -abstract class NDField>(val shape: IntArray, val field: F) : Field> { +interface NDField> : Field> { - abstract fun produceStructure(initializer: F.(IntArray) -> T): NDStructure + val shape: IntArray + val field: F /** * Create new instance of NDArray using field shape and given initializer * The producer takes list of indices as argument and returns contained value */ - fun produce(initializer: F.(IntArray) -> T): NDElement = NDStructureElement(this, produceStructure(initializer)) + fun produce(initializer: F.(IntArray) -> T): NDElement - override val zero: NDElement by lazy { - produce { zero } - } + override val zero: NDElement get() = produce { zero } - override val one: NDElement by lazy { - produce { one } - } + override val one: NDElement get() = produce { one } /** * Check the shape of given NDArray and throw exception if it does not coincide with shape of the field */ - private fun checkShape(vararg elements: NDStructure) { + fun checkShape(vararg elements: NDStructure) { elements.forEach { if (!shape.contentEquals(it.shape)) { throw ShapeMismatchException(shape, it.shape) @@ -49,7 +46,7 @@ abstract class NDField>(val shape: IntArray, val field: F) : Fie */ override fun add(a: NDStructure, b: NDStructure): NDElement { checkShape(a, b) - return produce { with(field) { a[it] + b[it] } } + return produce { field.run { a[it] + b[it] } } } /** @@ -57,7 +54,7 @@ abstract class NDField>(val shape: IntArray, val field: F) : Fie */ override fun multiply(a: NDStructure, k: Double): NDElement { checkShape(a) - return produce { with(field) { a[it] * k } } + return produce { field.run { a[it] * k } } } /** @@ -65,7 +62,7 @@ abstract class NDField>(val shape: IntArray, val field: F) : Fie */ override fun multiply(a: NDStructure, b: NDStructure): NDElement { checkShape(a) - return produce { with(field) { a[it] * b[it] } } + return produce { field.run { a[it] * b[it] } } } /** @@ -73,55 +70,72 @@ abstract class NDField>(val shape: IntArray, val field: F) : Fie */ override fun divide(a: NDStructure, b: NDStructure): NDElement { checkShape(a) - return produce { with(field) { a[it] / b[it] } } + return produce { field.run { a[it] / b[it] } } } -// /** -// * Reverse sum operation -// */ -// operator fun T.plus(arg: NDElement): NDElement = arg + this -// -// /** -// * Reverse minus operation -// */ -// operator fun T.minus(arg: NDElement): NDElement = arg.transformIndexed { _, value -> -// with(arg.context.field) { -// this@minus - value -// } -// } -// -// /** -// * Reverse product operation -// */ -// operator fun T.times(arg: NDElement): NDElement = arg * this -// -// /** -// * Reverse division operation -// */ -// operator fun T.div(arg: NDElement): NDElement = arg.transformIndexed { _, value -> -// with(arg.context.field) { -// this@div / value -// } -// } + + companion object { + /** + * Create a nd-field for [Double] values + */ + fun real(shape: IntArray) = ExtendedNDField(BufferNDField(shape, DoubleField, DoubleBufferFactory)) + + /** + * Create a nd-field with boxing generic buffer + */ + fun > generic(shape: IntArray, field: F) = BufferNDField(shape, field, ::boxingBuffer) + + /** + * Create a most suitable implementation for nd-field using reified class + */ + inline fun > inline(shape: IntArray, field: F) = BufferNDField(shape, field, ::inlineBuffer) + } } -interface NDElement> : FieldElement, NDField>, NDStructure +interface NDElement> : FieldElement, NDField>, NDStructure { + companion object { + /** + * Create a platform-optimized NDArray of doubles + */ + fun real(shape: IntArray, initializer: DoubleField.(IntArray) -> Double = { 0.0 }): NDElement { + return NDField.real(shape).produce(initializer) + } + + fun real1D(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDElement { + return real(intArrayOf(dim)) { initializer(it[0]) } + } + + fun real2D(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }): NDElement { + return real(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) } + } + + fun real3D(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }): NDElement { + return real(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) } + } + +// inline fun real(shape: IntArray, block: ExtendedNDField.() -> NDStructure): NDElement { +// val field = NDField.real(shape) +// return GenericNDElement(field, field.run(block)) +// } + + /** + * Simple boxing NDArray + */ + fun > generic(shape: IntArray, field: F, initializer: F.(IntArray) -> T): NDElement { + return NDField.generic(shape,field).produce(initializer) + } + + inline fun > inline(shape: IntArray, field: F, crossinline initializer: F.(IntArray) -> T): NDElement { + return NDField.inline(shape,field).produce(initializer) + } + } +} inline fun > NDElement.transformIndexed(crossinline action: F.(IntArray, T) -> T): NDElement = context.produce { action(it, get(*it)) } inline fun > NDElement.transform(crossinline action: F.(T) -> T): NDElement = context.produce { action(get(*it)) } -/** - * Read-only [NDStructure] coupled to the context. - */ -class NDStructureElement>(override val context: NDField, private val structure: NDStructure) : NDElement, NDStructure by structure { - - //TODO ensure structure is immutable - - override val self: NDElement get() = this -} - /** * Element by element application of any operation on elements to the whole array. Just like in numpy */ @@ -133,18 +147,14 @@ operator fun > Function1.invoke(ndElement: NDElement * Summation operation for [NDElement] and single element */ operator fun > NDElement.plus(arg: T): NDElement = transform { value -> - with(context.field) { - arg + value - } + context.field.run { arg + value } } /** * Subtraction operation between [NDElement] and single element */ operator fun > NDElement.minus(arg: T): NDElement = transform { value -> - with(context.field) { - arg - value - } + context.field.run { arg - value } } /* prod and div */ @@ -153,55 +163,53 @@ operator fun > NDElement.minus(arg: T): NDElement = * Product operation for [NDElement] and single element */ operator fun > NDElement.times(arg: T): NDElement = transform { value -> - with(context.field) { - arg * value - } + context.field.run { arg * value } } /** * Division operation between [NDElement] and single element */ operator fun > NDElement.div(arg: T): NDElement = transform { value -> - with(context.field) { - arg / value - } + context.field.run { arg / value } } -class GenericNDField>(shape: IntArray, field: F) : NDField(shape, field) { - override fun produceStructure(initializer: F.(IntArray) -> T): NDStructure = NdStructure(shape, ::boxingBuffer) { field.initializer(it) } + +// /** +// * Reverse sum operation +// */ +// operator fun T.plus(arg: NDStructure): NDElement = produce { index -> +// field.run { this@plus + arg[index] } +// } +// +// /** +// * Reverse minus operation +// */ +// operator fun T.minus(arg: NDStructure): NDElement = produce { index -> +// field.run { this@minus - arg[index] } +// } +// +// /** +// * Reverse product operation +// */ +// operator fun T.times(arg: NDStructure): NDElement = produce { index -> +// field.run { this@times * arg[index] } +// } +// +// /** +// * Reverse division operation +// */ +// operator fun T.div(arg: NDStructure): NDElement = produce { index -> +// field.run { this@div / arg[index] } +// } + +class GenericNDField>(override val shape: IntArray, override val field: F) : NDField { + override fun produce(initializer: F.(IntArray) -> T): NDElement = GenericNDElement(this, produceStructure(initializer)) + private inline fun produceStructure(crossinline initializer: F.(IntArray) -> T): NDStructure = NdStructure(shape, ::boxingBuffer) { field.initializer(it) } } -//typealias NDFieldFactory = (IntArray)->NDField - -object NDElements { - /** - * Create a platform-optimized NDArray of doubles - */ - fun realNDElement(shape: IntArray, initializer: DoubleField.(IntArray) -> Double = { 0.0 }): NDElement { - return ExtendedNDField(shape, DoubleField).produce(initializer) - } - - fun real1DElement(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDElement { - return realNDElement(intArrayOf(dim)) { initializer(it[0]) } - } - - fun real2DElement(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }): NDElement { - return realNDElement(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) } - } - - fun real3DElement(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }): NDElement { - return realNDElement(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) } - } - - inline fun real(shape: IntArray, block: ExtendedNDField.() -> NDStructure): NDElement { - val field = ExtendedNDField(shape, DoubleField) - return NDStructureElement(field, field.run(block)) - } - - /** - * Simple boxing NDArray - */ - fun > create(field: F, shape: IntArray, initializer: (IntArray) -> T): NDElement { - return GenericNDField(shape, field).produce { initializer(it) } - } +/** + * Read-only [NDStructure] coupled to the context. + */ +class GenericNDElement>(override val context: NDField, private val structure: NDStructure) : NDElement, NDStructure by structure { + override val self: NDElement get() = this } 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 8900d0d9b..765d7148b 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt @@ -19,7 +19,7 @@ interface MutableNDStructure : NDStructure { operator fun set(index: IntArray, value: T) } -fun MutableNDStructure.transformInPlace(action: (IntArray, T) -> T) { +fun MutableNDStructure.mapInPlace(action: (IntArray, T) -> T) { elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } @@ -113,8 +113,8 @@ class DefaultStrides private constructor(override val shape: IntArray) : Strides } abstract class GenericNDStructure> : NDStructure { - protected abstract val buffer: B - protected abstract val strides: Strides + abstract val buffer: B + abstract val strides: Strides override fun get(index: IntArray): T = buffer[strides.offset(index)] @@ -153,7 +153,18 @@ class BufferNDStructure( result = 31 * result + buffer.hashCode() return result } +} +/** + * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferNDStructure] + */ +inline fun NDStructure.map(factory: BufferFactory = ::inlineBuffer, crossinline transform: (T) -> R): BufferNDStructure { + return if (this is BufferNDStructure) { + BufferNDStructure(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) + } else { + val strides = DefaultStrides(shape) + BufferNDStructure(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) + } } /** diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/GenericNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/GenericNDFieldTest.kt deleted file mode 100644 index 0bc118e3b..000000000 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/GenericNDFieldTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package scientifik.kmath.structures - -import scientifik.kmath.operations.DoubleField -import scientifik.kmath.structures.NDElements.create -import kotlin.test.Test -import kotlin.test.assertEquals - - -class GenericNDFieldTest{ - @Test - fun testStrides(){ - val ndArray = create(DoubleField, intArrayOf(10,10)){(it[0]+it[1]).toDouble()} - assertEquals(ndArray[5,5], 10.0) - } - -} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt new file mode 100644 index 000000000..39cce5c67 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt @@ -0,0 +1,13 @@ +package scientifik.kmath.structures + +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NDFieldTest { + @Test + fun testStrides() { + val ndArray = NDElement.real(intArrayOf(10, 10)) { (it[0] + it[1]).toDouble() } + assertEquals(ndArray[5, 5], 10.0) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt index 5d5ee97cf..3c4160329 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt @@ -1,16 +1,15 @@ package scientifik.kmath.structures import scientifik.kmath.operations.Norm -import scientifik.kmath.structures.NDElements.real -import scientifik.kmath.structures.NDElements.real2DElement +import scientifik.kmath.structures.NDElement.Companion.real2D import kotlin.math.abs import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals class NumberNDFieldTest { - val array1 = real2DElement(3, 3) { i, j -> (i + j).toDouble() } - val array2 = real2DElement(3, 3) { i, j -> (i - j).toDouble() } + val array1 = real2D(3, 3) { i, j -> (i + j).toDouble() } + val array2 = real2D(3, 3) { i, j -> (i - j).toDouble() } @Test fun testSum() { @@ -27,7 +26,7 @@ class NumberNDFieldTest { @Test fun testGeneration() { - val array = real2DElement(3, 3) { i, j -> (i * 10 + j).toDouble() } + val array = real2D(3, 3) { i, j -> (i * 10 + j).toDouble() } for (i in 0..2) { for (j in 0..2) { @@ -52,7 +51,7 @@ class NumberNDFieldTest { } @Test - fun combineTest(){ + fun combineTest() { val division = array1.combine(array2, Double::div) } @@ -64,7 +63,7 @@ class NumberNDFieldTest { @Test fun testInternalContext() { - real(array1.shape) { + NDField.real(array1.shape).run { with(L2Norm) { 1 + norm(array1) + exp(array2) } diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyField.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyField.kt new file mode 100644 index 000000000..d534d3eb3 --- /dev/null +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyField.kt @@ -0,0 +1,7 @@ +package scientifik.kmath.structures + +// +//class LazyField: Field { +//} +// +//class LazyValue(): \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyNDField.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyNDField.kt index 823245685..adc2b4ed5 100644 --- a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyNDField.kt +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/structures/LazyNDField.kt @@ -8,7 +8,7 @@ class LazyNDField>(shape: IntArray, field: F, val scope: Corouti override fun produceStructure(initializer: F.(IntArray) -> T): NDStructure = LazyNDStructure(this) { initializer(field, it) } - override fun add(a: NDElement, b: NDElement): NDElement { + override fun add(a: NDStructure, b: NDStructure): NDElement { return LazyNDStructure(this) { index -> val aDeferred = a.deferred(index) val bDeferred = b.deferred(index) @@ -16,11 +16,11 @@ class LazyNDField>(shape: IntArray, field: F, val scope: Corouti } } - override fun multiply(a: NDElement, k: Double): NDElement { + override fun multiply(a: NDStructure, k: Double): NDElement { return LazyNDStructure(this) { index -> a.await(index) * k } } - override fun multiply(a: NDElement, b: NDElement): NDElement { + override fun multiply(a: NDStructure, b: NDStructure): NDElement { return LazyNDStructure(this) { index -> val aDeferred = a.deferred(index) val bDeferred = b.deferred(index) @@ -28,7 +28,7 @@ class LazyNDField>(shape: IntArray, field: F, val scope: Corouti } } - override fun divide(a: NDElement, b: NDElement): NDElement { + override fun divide(a: NDStructure, b: NDStructure): NDElement { return LazyNDStructure(this) { index -> val aDeferred = a.deferred(index) val bDeferred = b.deferred(index) @@ -57,15 +57,15 @@ class LazyNDStructure>(override val context: LazyNDField, } } -fun NDElement.deferred(index: IntArray) = if (this is LazyNDStructure) this.deferred(index) else CompletableDeferred(get(index)) +fun NDStructure.deferred(index: IntArray) = if (this is LazyNDStructure) this.deferred(index) else CompletableDeferred(get(index)) -suspend fun NDElement.await(index: IntArray) = if (this is LazyNDStructure) this.await(index) else get(index) +suspend fun NDStructure.await(index: IntArray) = if (this is LazyNDStructure) this.await(index) else get(index) fun > NDElement.lazy(scope: CoroutineScope = GlobalScope): LazyNDStructure { return if (this is LazyNDStructure) { this } else { - val context = LazyNDField(context.shape, context.field) + val context = LazyNDField(context.shape, context.field, scope) LazyNDStructure(context) { get(it) } } } diff --git a/kmath-coroutines/src/commonTest/kotlin/scientifik/kmath/structures/LazyNDFieldTest.kt b/kmath-coroutines/src/commonTest/kotlin/scientifik/kmath/structures/LazyNDFieldTest.kt index 6dce9b533..b5594cbdb 100644 --- a/kmath-coroutines/src/commonTest/kotlin/scientifik/kmath/structures/LazyNDFieldTest.kt +++ b/kmath-coroutines/src/commonTest/kotlin/scientifik/kmath/structures/LazyNDFieldTest.kt @@ -9,7 +9,7 @@ class LazyNDFieldTest { @Test fun testLazyStructure() { var counter = 0 - val regularStructure = NDElements.create(IntField, intArrayOf(2, 2, 2)) { it[0] + it[1] - it[2] } + val regularStructure = NDElements.generic(intArrayOf(2, 2, 2), IntField) { it[0] + it[1] - it[2] } val result = (regularStructure.lazy() + 2).transform { counter++ it * it diff --git a/settings.gradle.kts b/settings.gradle.kts index 0c91b8446..3b94f15c5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,5 +12,5 @@ include( ":kmath-core", ":kmath-io", ":kmath-coroutines", - ":kmath-jmh" + ":benchmarks" )