diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt index 4a0c96f78..cc8043664 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt @@ -4,8 +4,8 @@ import kotlinx.benchmark.Benchmark import kscience.kmath.commons.linear.CMMatrixContext import kscience.kmath.ejml.EjmlMatrixContext import kscience.kmath.linear.BufferMatrixContext +import kscience.kmath.linear.Matrix import kscience.kmath.linear.RealMatrixContext -import kscience.kmath.nd.Matrix import kscience.kmath.operations.RealField import kscience.kmath.operations.invoke import kscience.kmath.structures.Buffer diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/NDFieldBenchmark.kt index 3f103dd37..e465403ad 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -1,11 +1,9 @@ package kscience.kmath.benchmarks -import kscience.kmath.nd.AbstractNDBuffer -import kscience.kmath.nd.NDField -import kscience.kmath.nd.RealNDField +import kscience.kmath.nd.* import kscience.kmath.operations.RealField import kscience.kmath.operations.invoke -import kscience.kmath.structures.* +import kscience.kmath.structures.Buffer import org.openjdk.jmh.annotations.Benchmark import org.openjdk.jmh.annotations.Scope import org.openjdk.jmh.annotations.State @@ -14,22 +12,16 @@ import org.openjdk.jmh.annotations.State internal class NDFieldBenchmark { @Benchmark fun autoFieldAdd() { - bufferedField { - var res: AbstractNDBuffer = one + autoField { + var res: NDStructure = one repeat(n) { res += one } } } - @Benchmark - fun autoElementAdd() { - var res = genericField.one - repeat(n) { res += 1.0 } - } - @Benchmark fun specializedFieldAdd() { specializedField { - var res: AbstractNDBuffer = one + var res: NDStructure = one repeat(n) { res += 1.0 } } } @@ -38,16 +30,16 @@ internal class NDFieldBenchmark { @Benchmark fun boxingFieldAdd() { genericField { - var res: AbstractNDBuffer = one - repeat(n) { res += one } + var res: NDStructure = one + repeat(n) { res += 1.0 } } } companion object { const val dim: Int = 1000 const val n: Int = 100 - val bufferedField: BufferedNDField = NDField.auto(RealField, dim, dim) - val specializedField: RealNDField = NDField.real(dim, dim) - val genericField: BoxingNDField = NDField.boxing(RealField, dim, dim) + val autoField = NDAlgebra.auto(RealField, dim, dim) + val specializedField: RealNDField = NDAlgebra.real(dim, dim) + val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) } } \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ViktorBenchmark.kt index 49b30cf7e..892fb3457 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -1,10 +1,8 @@ package kscience.kmath.benchmarks -import kscience.kmath.nd.NDField -import kscience.kmath.nd.RealNDField +import kscience.kmath.nd.* import kscience.kmath.operations.RealField import kscience.kmath.operations.invoke -import kscience.kmath.structures.BufferedNDField import kscience.kmath.viktor.ViktorNDField import org.jetbrains.bio.viktor.F64Array import org.openjdk.jmh.annotations.Benchmark @@ -17,14 +15,14 @@ internal class ViktorBenchmark { final val n: Int = 100 // automatically build context most suited for given type. - final val autoField: BufferedNDField = NDField.auto(RealField, dim, dim) - final val realField: RealNDField = NDField.real(dim, dim) + final val autoField: BufferedNDField = NDAlgebra.auto(RealField, dim, dim) + final val realField: RealNDField = NDAlgebra.real(dim, dim) final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim)) @Benchmark fun automaticFieldAddition() { autoField { - var res = one + var res: NDStructure = one repeat(n) { res += one } } } diff --git a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt index 3e84c0be0..697affeca 100644 --- a/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/kscience/kmath/structures/NDField.kt @@ -1,10 +1,7 @@ package kscience.kmath.structures import kotlinx.coroutines.GlobalScope -import kscience.kmath.nd.NDAlgebra -import kscience.kmath.nd.NDStructure -import kscience.kmath.nd.field -import kscience.kmath.nd.real +import kscience.kmath.nd.* import kscience.kmath.nd4j.Nd4jArrayField import kscience.kmath.operations.RealField import kscience.kmath.operations.invoke @@ -26,11 +23,11 @@ fun main() { val n = 1000 // automatically build context most suited for given type. - val autoField = NDAlgebra.field(RealField, Buffer.Companion::auto, dim, dim) + val autoField = NDAlgebra.auto(RealField, dim, dim) // specialized nd-field for Double. It works as generic Double field as well val specializedField = NDAlgebra.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. - val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) + val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim) // Nd4j specialized field. val nd4jField = Nd4jArrayField.real(dim, dim) @@ -41,9 +38,9 @@ fun main() { } } - measureAndPrint("Element addition") { + measureAndPrint("Boxing addition") { boxingField { - var res: NDStructure = one + var res: NDStructure = one repeat(n) { res += 1.0 } } } @@ -57,7 +54,7 @@ fun main() { measureAndPrint("Nd4j specialized addition") { nd4jField { - var res:NDStructure = one + var res: NDStructure = one repeat(n) { res += 1.0 } } } @@ -73,14 +70,4 @@ fun main() { res.elements().forEach { it.second } } - - measureAndPrint("Generic addition") { - //genericField.run(action) - boxingField { - var res: NDStructure = one - repeat(n) { - res += 1.0 // couldn't avoid using `one` due to resolution ambiguity } - } - } - } } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/BufferNDAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/BufferNDAlgebra.kt index c07726ad6..901bb5a44 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/BufferNDAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/BufferNDAlgebra.kt @@ -2,6 +2,7 @@ package kscience.kmath.nd import kscience.kmath.nd.* import kscience.kmath.operations.* +import kscience.kmath.structures.Buffer import kscience.kmath.structures.BufferFactory import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -118,6 +119,11 @@ public fun > NDAlgebra.Companion.field( vararg shape: Int, ): BufferedNDField = BufferedNDField(shape, field, bufferFactory) +public inline fun > NDAlgebra.Companion.auto( + field: A, + vararg shape: Int, +): BufferedNDField = BufferedNDField(shape, field, Buffer.Companion::auto) + public inline fun , R> A.ndField( noinline bufferFactory: BufferFactory, vararg shape: Int, diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/RealNDField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/RealNDField.kt index 7a0d8f8f9..b96ee0e9b 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/RealNDField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/RealNDField.kt @@ -10,7 +10,7 @@ import kotlin.contracts.InvocationKind import kotlin.contracts.contract @OptIn(UnstableKMathAPI::class) -public open class RealNDField( +public class RealNDField( shape: IntArray, ) : BufferedNDField(shape, RealField, Buffer.Companion::real), RingWithNumbers>, @@ -23,51 +23,52 @@ public open class RealNDField( val d = value.toDouble() // minimize conversions return produce { d } } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun map( -// arg: AbstractNDBuffer, -// transform: RealField.(Double) -> Double, -// ): RealNDElement { -// check(arg) -// val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } -// return BufferedNDFieldElement(this, array) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { -// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } -// return BufferedNDFieldElement(this, array) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun mapIndexed( -// arg: AbstractNDBuffer, -// transform: RealField.(index: IntArray, Double) -> Double, -// ): RealNDElement { -// check(arg) -// return BufferedNDFieldElement( -// this, -// RealBuffer(arg.strides.linearSize) { offset -> -// elementContext.transform( -// arg.strides.index(offset), -// arg.buffer[offset] -// ) -// }) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun combine( -// a: AbstractNDBuffer, -// b: AbstractNDBuffer, -// transform: RealField.(Double, Double) -> Double, -// ): RealNDElement { -// check(a, b) -// val buffer = RealBuffer(strides.linearSize) { offset -> -// elementContext.transform(a.buffer[offset], b.buffer[offset]) -// } -// return BufferedNDFieldElement(this, buffer) -// } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun map( + arg: NDStructure, + transform: RealField.(Double) -> Double, + ): NDBuffer { + val argAsBuffer = arg.ndBuffer + val buffer = RealBuffer(strides.linearSize) { offset -> RealField.transform(argAsBuffer.buffer[offset]) } + return NDBuffer(strides, buffer) + } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun produce(initializer: RealField.(IntArray) -> Double): NDBuffer { + val buffer = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } + return NDBuffer(strides, buffer) + } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun mapIndexed( + arg: NDStructure, + transform: RealField.(index: IntArray, Double) -> Double, + ): NDBuffer { + val argAsBuffer = arg.ndBuffer + return NDBuffer( + strides, + RealBuffer(strides.linearSize) { offset -> + elementContext.transform( + strides.index(offset), + argAsBuffer.buffer[offset] + ) + }) + } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun combine( + a: NDStructure, + b: NDStructure, + transform: RealField.(Double, Double) -> Double, + ): NDBuffer { + val aBuffer = a.ndBuffer + val bBuffer = b.ndBuffer + val buffer = RealBuffer(strides.linearSize) { offset -> + elementContext.transform(aBuffer.buffer[offset], bBuffer.buffer[offset]) + } + return NDBuffer(strides, buffer) + } override fun power(arg: NDStructure, pow: Number): NDBuffer = map(arg) { power(it, pow) } diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/Structure2D.kt index b092d48e8..48fba45d9 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/nd/Structure2D.kt @@ -1,5 +1,6 @@ package kscience.kmath.nd +import kscience.kmath.linear.Matrix import kscience.kmath.structures.Buffer import kscience.kmath.structures.VirtualBuffer @@ -57,9 +58,9 @@ public interface Structure2D : NDStructure { rows: Int, columns: Int, crossinline init: (i: Int, j: Int) -> Double, - ): NDBuffer = NDAlgebra.real(rows, columns).produceInline { (i, j) -> + ): Matrix = NDAlgebra.real(rows, columns).produceInline { (i, j) -> init(i, j) - } + }.as2D() } }