forked from kscience/kmath
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.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
|
||||
|
@ -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<Double> = one
|
||||
autoField {
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += one }
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun autoElementAdd() {
|
||||
var res = genericField.one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun specializedFieldAdd() {
|
||||
specializedField {
|
||||
var res: AbstractNDBuffer<Double> = one
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
@ -38,16 +30,16 @@ internal class NDFieldBenchmark {
|
||||
@Benchmark
|
||||
fun boxingFieldAdd() {
|
||||
genericField {
|
||||
var res: AbstractNDBuffer<Double> = one
|
||||
repeat(n) { res += one }
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val dim: Int = 1000
|
||||
const val n: Int = 100
|
||||
val bufferedField: BufferedNDField<Double, RealField> = NDField.auto(RealField, dim, dim)
|
||||
val specializedField: RealNDField = NDField.real(dim, dim)
|
||||
val genericField: BoxingNDField<Double, RealField> = 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)
|
||||
}
|
||||
}
|
@ -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<Double, RealField> = NDField.auto(RealField, dim, dim)
|
||||
final val realField: RealNDField = NDField.real(dim, dim)
|
||||
final val autoField: BufferedNDField<Double, RealField> = 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<Double> = one
|
||||
repeat(n) { res += one }
|
||||
}
|
||||
}
|
||||
|
@ -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<Double> = one
|
||||
var res: NDStructure<Double> = one
|
||||
repeat(n) { res += 1.0 }
|
||||
}
|
||||
}
|
||||
@ -57,7 +54,7 @@ fun main() {
|
||||
|
||||
measureAndPrint("Nd4j specialized addition") {
|
||||
nd4jField {
|
||||
var res:NDStructure<Double> = one
|
||||
var res: NDStructure<Double> = 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<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.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 <T, A : Field<T>> NDAlgebra.Companion.field(
|
||||
vararg shape: Int,
|
||||
): 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(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
|
@ -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<Double, RealField>(shape, RealField, Buffer.Companion::real),
|
||||
RingWithNumbers<NDStructure<Double>>,
|
||||
@ -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<Double>,
|
||||
// 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<Double>,
|
||||
// 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<Double>,
|
||||
// b: AbstractNDBuffer<Double>,
|
||||
// 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<Double>,
|
||||
transform: RealField.(Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
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<Double> {
|
||||
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<Double>,
|
||||
transform: RealField.(index: IntArray, Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
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<Double>,
|
||||
b: NDStructure<Double>,
|
||||
transform: RealField.(Double, Double) -> Double,
|
||||
): NDBuffer<Double> {
|
||||
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<Double>, pow: Number): NDBuffer<Double> = map(arg) { power(it, pow) }
|
||||
|
||||
|
@ -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<T> : NDStructure<T> {
|
||||
rows: Int,
|
||||
columns: Int,
|
||||
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)
|
||||
}
|
||||
}.as2D()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user