Optimize Real NDField
This commit is contained in:
parent
0baec14059
commit
1cb41f4dc2
@ -4,8 +4,8 @@ import kotlinx.benchmark.Benchmark
|
|||||||
import kscience.kmath.commons.linear.CMMatrixContext
|
import kscience.kmath.commons.linear.CMMatrixContext
|
||||||
import kscience.kmath.ejml.EjmlMatrixContext
|
import kscience.kmath.ejml.EjmlMatrixContext
|
||||||
import kscience.kmath.linear.BufferMatrixContext
|
import kscience.kmath.linear.BufferMatrixContext
|
||||||
|
import kscience.kmath.linear.Matrix
|
||||||
import kscience.kmath.linear.RealMatrixContext
|
import kscience.kmath.linear.RealMatrixContext
|
||||||
import kscience.kmath.nd.Matrix
|
|
||||||
import kscience.kmath.operations.RealField
|
import kscience.kmath.operations.RealField
|
||||||
import kscience.kmath.operations.invoke
|
import kscience.kmath.operations.invoke
|
||||||
import kscience.kmath.structures.Buffer
|
import kscience.kmath.structures.Buffer
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
package kscience.kmath.benchmarks
|
package kscience.kmath.benchmarks
|
||||||
|
|
||||||
import kscience.kmath.nd.AbstractNDBuffer
|
import kscience.kmath.nd.*
|
||||||
import kscience.kmath.nd.NDField
|
|
||||||
import kscience.kmath.nd.RealNDField
|
|
||||||
import kscience.kmath.operations.RealField
|
import kscience.kmath.operations.RealField
|
||||||
import kscience.kmath.operations.invoke
|
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.Benchmark
|
||||||
import org.openjdk.jmh.annotations.Scope
|
import org.openjdk.jmh.annotations.Scope
|
||||||
import org.openjdk.jmh.annotations.State
|
import org.openjdk.jmh.annotations.State
|
||||||
@ -14,22 +12,16 @@ import org.openjdk.jmh.annotations.State
|
|||||||
internal class NDFieldBenchmark {
|
internal class NDFieldBenchmark {
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun autoFieldAdd() {
|
fun autoFieldAdd() {
|
||||||
bufferedField {
|
autoField {
|
||||||
var res: AbstractNDBuffer<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += one }
|
repeat(n) { res += one }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
|
||||||
fun autoElementAdd() {
|
|
||||||
var res = genericField.one
|
|
||||||
repeat(n) { res += 1.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun specializedFieldAdd() {
|
fun specializedFieldAdd() {
|
||||||
specializedField {
|
specializedField {
|
||||||
var res: AbstractNDBuffer<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,16 +30,16 @@ internal class NDFieldBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun boxingFieldAdd() {
|
fun boxingFieldAdd() {
|
||||||
genericField {
|
genericField {
|
||||||
var res: AbstractNDBuffer<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += one }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val dim: Int = 1000
|
const val dim: Int = 1000
|
||||||
const val n: Int = 100
|
const val n: Int = 100
|
||||||
val bufferedField: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
|
val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||||
val specializedField: RealNDField = NDField.real(dim, dim)
|
val specializedField: RealNDField = NDAlgebra.real(dim, dim)
|
||||||
val genericField: BoxingNDField<Double, RealField> = NDField.boxing(RealField, dim, dim)
|
val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,8 @@
|
|||||||
package kscience.kmath.benchmarks
|
package kscience.kmath.benchmarks
|
||||||
|
|
||||||
import kscience.kmath.nd.NDField
|
import kscience.kmath.nd.*
|
||||||
import kscience.kmath.nd.RealNDField
|
|
||||||
import kscience.kmath.operations.RealField
|
import kscience.kmath.operations.RealField
|
||||||
import kscience.kmath.operations.invoke
|
import kscience.kmath.operations.invoke
|
||||||
import kscience.kmath.structures.BufferedNDField
|
|
||||||
import kscience.kmath.viktor.ViktorNDField
|
import kscience.kmath.viktor.ViktorNDField
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
import org.jetbrains.bio.viktor.F64Array
|
||||||
import org.openjdk.jmh.annotations.Benchmark
|
import org.openjdk.jmh.annotations.Benchmark
|
||||||
@ -17,14 +15,14 @@ internal class ViktorBenchmark {
|
|||||||
final val n: Int = 100
|
final val n: Int = 100
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// automatically build context most suited for given type.
|
||||||
final val autoField: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
|
final val autoField: BufferedNDField<Double, RealField> = NDAlgebra.auto(RealField, dim, dim)
|
||||||
final val realField: RealNDField = NDField.real(dim, dim)
|
final val realField: RealNDField = NDAlgebra.real(dim, dim)
|
||||||
final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
|
final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun automaticFieldAddition() {
|
fun automaticFieldAddition() {
|
||||||
autoField {
|
autoField {
|
||||||
var res = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += one }
|
repeat(n) { res += one }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package kscience.kmath.structures
|
package kscience.kmath.structures
|
||||||
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kscience.kmath.nd.NDAlgebra
|
import kscience.kmath.nd.*
|
||||||
import kscience.kmath.nd.NDStructure
|
|
||||||
import kscience.kmath.nd.field
|
|
||||||
import kscience.kmath.nd.real
|
|
||||||
import kscience.kmath.nd4j.Nd4jArrayField
|
import kscience.kmath.nd4j.Nd4jArrayField
|
||||||
import kscience.kmath.operations.RealField
|
import kscience.kmath.operations.RealField
|
||||||
import kscience.kmath.operations.invoke
|
import kscience.kmath.operations.invoke
|
||||||
@ -26,11 +23,11 @@ fun main() {
|
|||||||
val n = 1000
|
val n = 1000
|
||||||
|
|
||||||
// automatically build context most suited for given type.
|
// 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
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val specializedField = NDAlgebra.real(dim, dim)
|
val specializedField = NDAlgebra.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 boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
|
||||||
// Nd4j specialized field.
|
// Nd4j specialized field.
|
||||||
val nd4jField = Nd4jArrayField.real(dim, dim)
|
val nd4jField = Nd4jArrayField.real(dim, dim)
|
||||||
|
|
||||||
@ -41,9 +38,9 @@ fun main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Element addition") {
|
measureAndPrint("Boxing addition") {
|
||||||
boxingField {
|
boxingField {
|
||||||
var res: NDStructure<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +54,7 @@ fun main() {
|
|||||||
|
|
||||||
measureAndPrint("Nd4j specialized addition") {
|
measureAndPrint("Nd4j specialized addition") {
|
||||||
nd4jField {
|
nd4jField {
|
||||||
var res:NDStructure<Double> = one
|
var res: NDStructure<Double> = one
|
||||||
repeat(n) { res += 1.0 }
|
repeat(n) { res += 1.0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,14 +70,4 @@ fun main() {
|
|||||||
|
|
||||||
res.elements().forEach { it.second }
|
res.elements().forEach { it.second }
|
||||||
}
|
}
|
||||||
|
|
||||||
measureAndPrint("Generic addition") {
|
|
||||||
//genericField.run(action)
|
|
||||||
boxingField {
|
|
||||||
var res: NDStructure<Double> = one
|
|
||||||
repeat(n) {
|
|
||||||
res += 1.0 // couldn't avoid using `one` due to resolution ambiguity }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package kscience.kmath.nd
|
|||||||
|
|
||||||
import kscience.kmath.nd.*
|
import kscience.kmath.nd.*
|
||||||
import kscience.kmath.operations.*
|
import kscience.kmath.operations.*
|
||||||
|
import kscience.kmath.structures.Buffer
|
||||||
import kscience.kmath.structures.BufferFactory
|
import kscience.kmath.structures.BufferFactory
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
@ -118,6 +119,11 @@ public fun <T, A : Field<T>> NDAlgebra.Companion.field(
|
|||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
): BufferedNDField<T, A> = BufferedNDField(shape, field, bufferFactory)
|
): BufferedNDField<T, A> = BufferedNDField(shape, field, bufferFactory)
|
||||||
|
|
||||||
|
public inline fun <reified T : Any, A : Field<T>> NDAlgebra.Companion.auto(
|
||||||
|
field: A,
|
||||||
|
vararg shape: Int,
|
||||||
|
): BufferedNDField<T, A> = BufferedNDField(shape, field, Buffer.Companion::auto)
|
||||||
|
|
||||||
public inline fun <T, A : Field<T>, R> A.ndField(
|
public inline fun <T, A : Field<T>, R> A.ndField(
|
||||||
noinline bufferFactory: BufferFactory<T>,
|
noinline bufferFactory: BufferFactory<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.contracts.InvocationKind
|
|||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
@OptIn(UnstableKMathAPI::class)
|
@OptIn(UnstableKMathAPI::class)
|
||||||
public open class RealNDField(
|
public class RealNDField(
|
||||||
shape: IntArray,
|
shape: IntArray,
|
||||||
) : BufferedNDField<Double, RealField>(shape, RealField, Buffer.Companion::real),
|
) : BufferedNDField<Double, RealField>(shape, RealField, Buffer.Companion::real),
|
||||||
RingWithNumbers<NDStructure<Double>>,
|
RingWithNumbers<NDStructure<Double>>,
|
||||||
@ -23,51 +23,52 @@ public open class RealNDField(
|
|||||||
val d = value.toDouble() // minimize conversions
|
val d = value.toDouble() // minimize conversions
|
||||||
return produce { d }
|
return produce { d }
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun map(
|
override inline fun map(
|
||||||
// arg: AbstractNDBuffer<Double>,
|
arg: NDStructure<Double>,
|
||||||
// transform: RealField.(Double) -> Double,
|
transform: RealField.(Double) -> Double,
|
||||||
// ): RealNDElement {
|
): NDBuffer<Double> {
|
||||||
// check(arg)
|
val argAsBuffer = arg.ndBuffer
|
||||||
// val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
|
val buffer = RealBuffer(strides.linearSize) { offset -> RealField.transform(argAsBuffer.buffer[offset]) }
|
||||||
// return BufferedNDFieldElement(this, array)
|
return NDBuffer(strides, buffer)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement {
|
override inline fun produce(initializer: RealField.(IntArray) -> Double): NDBuffer<Double> {
|
||||||
// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
val buffer = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||||
// return BufferedNDFieldElement(this, array)
|
return NDBuffer(strides, buffer)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun mapIndexed(
|
override inline fun mapIndexed(
|
||||||
// arg: AbstractNDBuffer<Double>,
|
arg: NDStructure<Double>,
|
||||||
// transform: RealField.(index: IntArray, Double) -> Double,
|
transform: RealField.(index: IntArray, Double) -> Double,
|
||||||
// ): RealNDElement {
|
): NDBuffer<Double> {
|
||||||
// check(arg)
|
val argAsBuffer = arg.ndBuffer
|
||||||
// return BufferedNDFieldElement(
|
return NDBuffer(
|
||||||
// this,
|
strides,
|
||||||
// RealBuffer(arg.strides.linearSize) { offset ->
|
RealBuffer(strides.linearSize) { offset ->
|
||||||
// elementContext.transform(
|
elementContext.transform(
|
||||||
// arg.strides.index(offset),
|
strides.index(offset),
|
||||||
// arg.buffer[offset]
|
argAsBuffer.buffer[offset]
|
||||||
// )
|
)
|
||||||
// })
|
})
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @Suppress("OVERRIDE_BY_INLINE")
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
// override inline fun combine(
|
override inline fun combine(
|
||||||
// a: AbstractNDBuffer<Double>,
|
a: NDStructure<Double>,
|
||||||
// b: AbstractNDBuffer<Double>,
|
b: NDStructure<Double>,
|
||||||
// transform: RealField.(Double, Double) -> Double,
|
transform: RealField.(Double, Double) -> Double,
|
||||||
// ): RealNDElement {
|
): NDBuffer<Double> {
|
||||||
// check(a, b)
|
val aBuffer = a.ndBuffer
|
||||||
// val buffer = RealBuffer(strides.linearSize) { offset ->
|
val bBuffer = b.ndBuffer
|
||||||
// elementContext.transform(a.buffer[offset], b.buffer[offset])
|
val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||||
// }
|
elementContext.transform(aBuffer.buffer[offset], bBuffer.buffer[offset])
|
||||||
// return BufferedNDFieldElement(this, buffer)
|
}
|
||||||
// }
|
return NDBuffer(strides, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = map(arg) { power(it, pow) }
|
override fun power(arg: NDStructure<Double>, pow: Number): NDBuffer<Double> = map(arg) { power(it, pow) }
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package kscience.kmath.nd
|
package kscience.kmath.nd
|
||||||
|
|
||||||
|
import kscience.kmath.linear.Matrix
|
||||||
import kscience.kmath.structures.Buffer
|
import kscience.kmath.structures.Buffer
|
||||||
import kscience.kmath.structures.VirtualBuffer
|
import kscience.kmath.structures.VirtualBuffer
|
||||||
|
|
||||||
@ -57,9 +58,9 @@ public interface Structure2D<T> : NDStructure<T> {
|
|||||||
rows: Int,
|
rows: Int,
|
||||||
columns: Int,
|
columns: Int,
|
||||||
crossinline init: (i: Int, j: Int) -> Double,
|
crossinline init: (i: Int, j: Int) -> Double,
|
||||||
): NDBuffer<Double> = NDAlgebra.real(rows, columns).produceInline { (i, j) ->
|
): Matrix<Double> = NDAlgebra.real(rows, columns).produceInline { (i, j) ->
|
||||||
init(i, j)
|
init(i, j)
|
||||||
}
|
}.as2D()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user