Minor optimization for RealNDAlgebra
This commit is contained in:
parent
53c32abf4f
commit
360e0e17e9
@ -28,7 +28,7 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
@Benchmark
|
||||
fun mstExpression() {
|
||||
val expr = algebra.mstInField {
|
||||
symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
|
||||
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
|
||||
}
|
||||
|
||||
invokeAndSum(expr)
|
||||
@ -37,7 +37,7 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
@Benchmark
|
||||
fun asmExpression() {
|
||||
val expr = algebra.mstInField {
|
||||
symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
|
||||
symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0
|
||||
}.compile()
|
||||
|
||||
invokeAndSum(expr)
|
||||
|
@ -2,9 +2,8 @@ package kscience.kmath.benchmarks
|
||||
|
||||
import kotlinx.benchmark.Benchmark
|
||||
import kscience.kmath.commons.linear.CMMatrixContext
|
||||
import kscience.kmath.commons.linear.toCM
|
||||
import kscience.kmath.ejml.EjmlMatrixContext
|
||||
import kscience.kmath.ejml.toEjml
|
||||
|
||||
import kscience.kmath.linear.BufferMatrixContext
|
||||
import kscience.kmath.linear.RealMatrixContext
|
||||
import kscience.kmath.linear.real
|
||||
@ -26,11 +25,11 @@ class DotBenchmark {
|
||||
val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val matrix2 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
|
||||
val cmMatrix1 = matrix1.toCM()
|
||||
val cmMatrix2 = matrix2.toCM()
|
||||
val cmMatrix1 = CMMatrixContext { matrix1.toCM() }
|
||||
val cmMatrix2 = CMMatrixContext { matrix2.toCM() }
|
||||
|
||||
val ejmlMatrix1 = matrix1.toEjml()
|
||||
val ejmlMatrix2 = matrix2.toEjml()
|
||||
val ejmlMatrix1 = EjmlMatrixContext { matrix1.toEjml() }
|
||||
val ejmlMatrix2 = EjmlMatrixContext { matrix2.toEjml() }
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@ -49,9 +48,10 @@ class DotBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun ejmlMultiplicationwithConversion() {
|
||||
EjmlMatrixContext {
|
||||
val ejmlMatrix1 = matrix1.toEjml()
|
||||
val ejmlMatrix2 = matrix2.toEjml()
|
||||
EjmlMatrixContext {
|
||||
|
||||
ejmlMatrix1 dot ejmlMatrix2
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package kscience.kmath.benchmarks
|
||||
|
||||
import kscience.kmath.structures.NDField
|
||||
import org.openjdk.jmh.annotations.Benchmark
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import org.openjdk.jmh.infra.Blackhole
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
class LargeNDBenchmark {
|
||||
val arraySize = 10000
|
||||
val RANDOM = Random(222)
|
||||
val src1 = DoubleArray(arraySize) { RANDOM.nextDouble() }
|
||||
val src2 = DoubleArray(arraySize) { RANDOM.nextDouble() }
|
||||
val field = NDField.real(arraySize)
|
||||
val kmathArray1 = field.produce { (a) -> src1[a] }
|
||||
val kmathArray2 = field.produce { (a) -> src2[a] }
|
||||
|
||||
@Benchmark
|
||||
fun test10000(bh: Blackhole) {
|
||||
bh.consume(field.add(kmathArray1, kmathArray2))
|
||||
}
|
||||
|
||||
}
|
@ -5,10 +5,8 @@ import kotlinx.benchmark.Benchmark
|
||||
import kscience.kmath.commons.linear.CMMatrixContext
|
||||
import kscience.kmath.commons.linear.CMMatrixContext.dot
|
||||
import kscience.kmath.commons.linear.inverse
|
||||
import kscience.kmath.commons.linear.toCM
|
||||
import kscience.kmath.ejml.EjmlMatrixContext
|
||||
import kscience.kmath.ejml.inverse
|
||||
import kscience.kmath.ejml.toEjml
|
||||
import kscience.kmath.operations.invoke
|
||||
import kscience.kmath.structures.Matrix
|
||||
import org.openjdk.jmh.annotations.Scope
|
||||
@ -35,16 +33,14 @@ class LinearAlgebraBenchmark {
|
||||
@Benchmark
|
||||
fun cmLUPInversion() {
|
||||
CMMatrixContext {
|
||||
val cm = matrix.toCM() //avoid overhead on conversion
|
||||
inverse(cm)
|
||||
inverse(matrix)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun ejmlInverse() {
|
||||
EjmlMatrixContext {
|
||||
val km = matrix.toEjml() //avoid overhead on conversion
|
||||
inverse(km)
|
||||
inverse(matrix)
|
||||
}
|
||||
}
|
||||
}
|
@ -95,8 +95,9 @@ public open class FunctionalExpressionRing<T, A : Ring<T>>(
|
||||
super<FunctionalExpressionSpace>.binaryOperationFunction(operation)
|
||||
}
|
||||
|
||||
public open class FunctionalExpressionField<T, A : Field<T>>(algebra: A) :
|
||||
FunctionalExpressionRing<T, A>(algebra), Field<Expression<T>> {
|
||||
public open class FunctionalExpressionField<T, A : Field<T>>(
|
||||
algebra: A,
|
||||
) : FunctionalExpressionRing<T, A>(algebra), Field<Expression<T>> {
|
||||
/**
|
||||
* Builds an Expression of division an expression by another one.
|
||||
*/
|
||||
|
@ -224,6 +224,7 @@ public inline fun <reified T : Comparable<T>, F : Field<T>> GenericMatrixContext
|
||||
): Matrix<T> = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular)
|
||||
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun RealMatrixContext.solveWithLUP(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> {
|
||||
// Use existing decomposition if it is provided by matrix
|
||||
val bufferFactory: MutableBufferFactory<Double> = MutableBuffer.Companion::real
|
||||
|
@ -3,6 +3,7 @@ package kscience.kmath.operations
|
||||
import kscience.kmath.memory.MemoryReader
|
||||
import kscience.kmath.memory.MemorySpec
|
||||
import kscience.kmath.memory.MemoryWriter
|
||||
import kscience.kmath.misc.UnstableKMathAPI
|
||||
import kscience.kmath.structures.Buffer
|
||||
import kscience.kmath.structures.MemoryBuffer
|
||||
import kscience.kmath.structures.MutableBuffer
|
||||
@ -41,6 +42,7 @@ private val PI_DIV_2 = Complex(PI / 2, 0)
|
||||
/**
|
||||
* A field of [Complex].
|
||||
*/
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public object ComplexField : ExtendedField<Complex>, Norm<Complex, Complex>, RingWithNumbers<Complex> {
|
||||
override val zero: Complex = 0.0.toComplex()
|
||||
override val one: Complex = 1.0.toComplex()
|
||||
|
@ -24,35 +24,31 @@ public class RealNDField(override val shape: IntArray) :
|
||||
return produce { d }
|
||||
}
|
||||
|
||||
private inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer<Double> =
|
||||
RealBuffer(DoubleArray(size) { initializer(it) })
|
||||
|
||||
/**
|
||||
* Inline transform an NDStructure to
|
||||
*/
|
||||
override fun map(
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun map(
|
||||
arg: NDBuffer<Double>,
|
||||
transform: RealField.(Double) -> Double
|
||||
transform: RealField.(Double) -> Double,
|
||||
): RealNDElement {
|
||||
check(arg)
|
||||
val array = buildBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
|
||||
val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) }
|
||||
return BufferedNDFieldElement(this, array)
|
||||
}
|
||||
|
||||
override fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement {
|
||||
val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }
|
||||
@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)
|
||||
}
|
||||
|
||||
override fun mapIndexed(
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun mapIndexed(
|
||||
arg: NDBuffer<Double>,
|
||||
transform: RealField.(index: IntArray, Double) -> Double
|
||||
transform: RealField.(index: IntArray, Double) -> Double,
|
||||
): RealNDElement {
|
||||
check(arg)
|
||||
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(arg.strides.linearSize) { offset ->
|
||||
RealBuffer(arg.strides.linearSize) { offset ->
|
||||
elementContext.transform(
|
||||
arg.strides.index(offset),
|
||||
arg.buffer[offset]
|
||||
@ -60,16 +56,17 @@ public class RealNDField(override val shape: IntArray) :
|
||||
})
|
||||
}
|
||||
|
||||
override fun combine(
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
override inline fun combine(
|
||||
a: NDBuffer<Double>,
|
||||
b: NDBuffer<Double>,
|
||||
transform: RealField.(Double, Double) -> Double
|
||||
transform: RealField.(Double, Double) -> Double,
|
||||
): RealNDElement {
|
||||
check(a, b)
|
||||
return BufferedNDFieldElement(
|
||||
this,
|
||||
buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }
|
||||
)
|
||||
val buffer = RealBuffer(strides.linearSize) { offset ->
|
||||
elementContext.transform(a.buffer[offset], b.buffer[offset])
|
||||
}
|
||||
return BufferedNDFieldElement(this, buffer)
|
||||
}
|
||||
|
||||
override fun NDBuffer<Double>.toElement(): FieldElement<NDBuffer<Double>, *, out BufferedNDField<Double, RealField>> =
|
||||
|
@ -7,6 +7,7 @@ import kscience.kmath.structures.as2D
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class MatrixTest {
|
||||
@Test
|
||||
fun testTranspose() {
|
||||
|
@ -8,6 +8,7 @@ import kotlin.math.pow
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class NumberNDFieldTest {
|
||||
val array1: RealNDElement = real2D(3, 3) { i, j -> (i + j).toDouble() }
|
||||
val array2: RealNDElement = real2D(3, 3) { i, j -> (i - j).toDouble() }
|
||||
|
@ -6,6 +6,7 @@ import kscience.kmath.dimensions.DMatrixContext
|
||||
import kscience.kmath.dimensions.one
|
||||
import kotlin.test.Test
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
internal class DMatrixContextTest {
|
||||
@Test
|
||||
fun testDimensionSafeMatrix() {
|
||||
|
Loading…
Reference in New Issue
Block a user