forked from kscience/kmath
Vector space refactor (optimization)
This commit is contained in:
parent
be9398b322
commit
0aa73cd48f
@ -92,6 +92,14 @@ benchmark {
|
||||
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
||||
include("ExpressionsInterpretersBenchmark")
|
||||
}
|
||||
|
||||
configurations.register("matrixInverse") {
|
||||
warmups = 1 // number of warmup iterations
|
||||
iterations = 3 // number of iterations
|
||||
iterationTime = 500 // time in seconds per iteration
|
||||
iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds
|
||||
include("MatrixInverseBenchmark")
|
||||
}
|
||||
}
|
||||
|
||||
kotlin.sourceSets.all {
|
||||
|
@ -6,12 +6,9 @@ import kotlinx.benchmark.Scope
|
||||
import kotlinx.benchmark.State
|
||||
import space.kscience.kmath.commons.linear.CMLinearSpace
|
||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||
import space.kscience.kmath.linear.BufferLinearSpace
|
||||
import space.kscience.kmath.linear.Matrix
|
||||
import space.kscience.kmath.linear.RealLinearSpace
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.invoke
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@ -21,8 +18,8 @@ internal class DotBenchmark {
|
||||
const val dim = 1000
|
||||
|
||||
//creating invertible matrix
|
||||
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 matrix1 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val matrix2 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
|
||||
val cmMatrix1 = CMLinearSpace { matrix1.toCM() }
|
||||
val cmMatrix2 = CMLinearSpace { matrix2.toCM() }
|
||||
@ -33,7 +30,7 @@ internal class DotBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun cmDot(blackhole: Blackhole) {
|
||||
CMLinearSpace {
|
||||
CMLinearSpace.run {
|
||||
blackhole.consume(cmMatrix1 dot cmMatrix2)
|
||||
}
|
||||
}
|
||||
@ -54,14 +51,14 @@ internal class DotBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun bufferedDot(blackhole: Blackhole) {
|
||||
BufferLinearSpace(RealField, Buffer.Companion::real).invoke {
|
||||
LinearSpace.auto(RealField).invoke {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun realDot(blackhole: Blackhole) {
|
||||
RealLinearSpace {
|
||||
LinearSpace.real {
|
||||
blackhole.consume(matrix1 dot matrix2)
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
fun mstExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.mstInField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + 2.0 / x - 16.0
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
@ -40,7 +40,7 @@ internal class ExpressionsInterpretersBenchmark {
|
||||
fun asmExpression(blackhole: Blackhole) {
|
||||
val expr = algebra.mstInField {
|
||||
val x = bindSymbol(x)
|
||||
x * 2.0 + 2.0 / x - 16.0
|
||||
x * 2.0 + number(2.0) / x - 16.0
|
||||
}.compile()
|
||||
|
||||
invokeAndSum(expr, blackhole)
|
||||
|
@ -9,21 +9,22 @@ import space.kscience.kmath.commons.linear.inverse
|
||||
import space.kscience.kmath.ejml.EjmlLinearSpace
|
||||
import space.kscience.kmath.ejml.inverse
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.linear.Matrix
|
||||
import space.kscience.kmath.linear.inverseWithLup
|
||||
import space.kscience.kmath.linear.real
|
||||
import space.kscience.kmath.linear.invoke
|
||||
import kotlin.random.Random
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
internal class LinearAlgebraBenchmark {
|
||||
internal class MatrixInverseBenchmark {
|
||||
companion object {
|
||||
val random = Random(1224)
|
||||
const val dim = 100
|
||||
|
||||
private val space = LinearSpace.real
|
||||
|
||||
//creating invertible matrix
|
||||
val u = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val l = Matrix.real(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
||||
val matrix = l dot u
|
||||
val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
||||
val matrix = space { l dot u }
|
||||
}
|
||||
|
||||
@Benchmark
|
@ -15,7 +15,7 @@ import space.kscience.kmath.viktor.ViktorNDField
|
||||
internal class ViktorLogBenchmark {
|
||||
@Benchmark
|
||||
fun realFieldLog(blackhole: Blackhole) {
|
||||
with(realField) {
|
||||
with(realNdField) {
|
||||
val fortyTwo = produce { 42.0 }
|
||||
var res = one
|
||||
repeat(n) { res = ln(fortyTwo) }
|
||||
@ -47,7 +47,7 @@ internal class ViktorLogBenchmark {
|
||||
|
||||
// automatically build context most suited for given type.
|
||||
private val autoField = NDAlgebra.auto(RealField, dim, dim)
|
||||
private val realField = NDAlgebra.real(dim, dim)
|
||||
private val realNdField = NDAlgebra.real(dim, dim)
|
||||
private val viktorField = ViktorNDField(intArrayOf(dim, dim))
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public object MstRing : Ring<MST>, NumbersAddOperations<MST>, ScaleOperations<MS
|
||||
public override val one: MST.Numeric = number(1.0)
|
||||
|
||||
public override fun number(value: Number): MST.Numeric = MstGroup.number(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstGroup.bindSymbol(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||
public override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b)
|
||||
|
||||
public override fun scale(a: MST, value: Double): MST.Binary =
|
||||
@ -83,7 +83,7 @@ public object MstField : Field<MST>, NumbersAddOperations<MST>, ScaleOperations<
|
||||
|
||||
public override val one: MST.Numeric get() = MstRing.one
|
||||
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstRing.bindSymbol(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
||||
public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b)
|
||||
|
||||
@ -112,7 +112,7 @@ public object MstExtendedField : ExtendedField<MST>, NumericAlgebra<MST> {
|
||||
public override val zero: MST.Numeric get() = MstField.zero
|
||||
public override val one: MST.Numeric get() = MstField.one
|
||||
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstField.bindSymbol(value)
|
||||
public override fun bindSymbol(value: String): MST.Symbolic = MstAlgebra.bindSymbol(value)
|
||||
public override fun number(value: Number): MST.Numeric = MstRing.number(value)
|
||||
public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg)
|
||||
public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg)
|
||||
|
@ -496,7 +496,6 @@ public final class space/kscience/kmath/linear/LinearSpace$Companion {
|
||||
}
|
||||
|
||||
public final class space/kscience/kmath/linear/LinearSpace$DefaultImpls {
|
||||
public static fun buildVector (Lspace/kscience/kmath/linear/LinearSpace;ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public static fun dot (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public static fun dot (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public static fun minus (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
@ -511,6 +510,29 @@ public final class space/kscience/kmath/linear/LinearSpace$DefaultImpls {
|
||||
public static fun unaryMinus (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
}
|
||||
|
||||
public final class space/kscience/kmath/linear/LinearSpaceKt {
|
||||
public static final fun invoke (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
}
|
||||
|
||||
public final class space/kscience/kmath/linear/LinearSpaceOverNd : space/kscience/kmath/linear/LinearSpace {
|
||||
public fun <init> (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V
|
||||
public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring;
|
||||
public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun minus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun plus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun times (Ljava/lang/Object;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun times (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun times (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun unaryMinus (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
|
||||
}
|
||||
|
||||
public final class space/kscience/kmath/linear/LupDecomposition : space/kscience/kmath/linear/DeterminantFeature, space/kscience/kmath/linear/LupDecompositionFeature {
|
||||
public fun <init> (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;[IZ)V
|
||||
public final fun getContext ()Lspace/kscience/kmath/linear/LinearSpace;
|
||||
@ -566,12 +588,12 @@ public final class space/kscience/kmath/linear/MatrixWrapper : space/kscience/km
|
||||
public fun get (II)Ljava/lang/Object;
|
||||
public fun get ([I)Ljava/lang/Object;
|
||||
public fun getColNum ()I
|
||||
public fun getColumns ()Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun getColumns ()Ljava/util/List;
|
||||
public fun getDimension ()I
|
||||
public final fun getFeatures ()Ljava/util/Set;
|
||||
public final fun getOrigin ()Lspace/kscience/kmath/nd/Structure2D;
|
||||
public fun getRowNum ()I
|
||||
public fun getRows ()Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun getRows ()Ljava/util/List;
|
||||
public fun getShape ()[I
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
@ -622,11 +644,11 @@ public final class space/kscience/kmath/linear/VirtualMatrix : space/kscience/km
|
||||
public fun get (II)Ljava/lang/Object;
|
||||
public fun get ([I)Ljava/lang/Object;
|
||||
public fun getColNum ()I
|
||||
public fun getColumns ()Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun getColumns ()Ljava/util/List;
|
||||
public fun getDimension ()I
|
||||
public final fun getGenerator ()Lkotlin/jvm/functions/Function2;
|
||||
public fun getRowNum ()I
|
||||
public fun getRows ()Lspace/kscience/kmath/structures/Buffer;
|
||||
public fun getRows ()Ljava/util/List;
|
||||
public fun getShape ()[I
|
||||
public fun hashCode ()I
|
||||
}
|
||||
@ -678,11 +700,11 @@ public final class space/kscience/kmath/nd/BufferNDAlgebra$DefaultImpls {
|
||||
|
||||
public final class space/kscience/kmath/nd/BufferNDAlgebraKt {
|
||||
public static final fun field (Lspace/kscience/kmath/nd/NDAlgebra$Companion;Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedNDField;
|
||||
public static final fun group (Lspace/kscience/kmath/nd/NDAlgebra$Companion;Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedNDGroup;
|
||||
public static final fun ndField (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
public static final fun ndGroup (Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
public static final fun ndRing (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
public static final fun ndSpace (Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object;
|
||||
public static final fun ring (Lspace/kscience/kmath/nd/NDAlgebra$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedNDRing;
|
||||
public static final fun space (Lspace/kscience/kmath/nd/NDAlgebra$Companion;Lspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedNDGroup;
|
||||
}
|
||||
|
||||
public class space/kscience/kmath/nd/BufferedNDField : space/kscience/kmath/nd/BufferedNDRing, space/kscience/kmath/nd/NDField {
|
||||
@ -1103,9 +1125,9 @@ public abstract interface class space/kscience/kmath/nd/Structure2D : space/ksci
|
||||
public abstract fun get (II)Ljava/lang/Object;
|
||||
public abstract fun get ([I)Ljava/lang/Object;
|
||||
public abstract fun getColNum ()I
|
||||
public abstract fun getColumns ()Lspace/kscience/kmath/structures/Buffer;
|
||||
public abstract fun getColumns ()Ljava/util/List;
|
||||
public abstract fun getRowNum ()I
|
||||
public abstract fun getRows ()Lspace/kscience/kmath/structures/Buffer;
|
||||
public abstract fun getRows ()Ljava/util/List;
|
||||
public abstract fun getShape ()[I
|
||||
}
|
||||
|
||||
@ -1115,9 +1137,9 @@ public final class space/kscience/kmath/nd/Structure2D$Companion {
|
||||
public final class space/kscience/kmath/nd/Structure2D$DefaultImpls {
|
||||
public static fun elements (Lspace/kscience/kmath/nd/Structure2D;)Lkotlin/sequences/Sequence;
|
||||
public static fun get (Lspace/kscience/kmath/nd/Structure2D;[I)Ljava/lang/Object;
|
||||
public static fun getColumns (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public static fun getColumns (Lspace/kscience/kmath/nd/Structure2D;)Ljava/util/List;
|
||||
public static fun getDimension (Lspace/kscience/kmath/nd/Structure2D;)I
|
||||
public static fun getRows (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/structures/Buffer;
|
||||
public static fun getRows (Lspace/kscience/kmath/nd/Structure2D;)Ljava/util/List;
|
||||
public static fun getShape (Lspace/kscience/kmath/nd/Structure2D;)[I
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,7 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
||||
/**
|
||||
* Produces a point compatible with matrix space (and possibly optimized for it).
|
||||
*/
|
||||
public fun buildVector(size: Int, initializer: A.(Int) -> T): Vector<T> =
|
||||
buildMatrix(1, size) { _, j -> initializer(j) }.as1D()
|
||||
public fun buildVector(size: Int, initializer: A.(Int) -> T): Vector<T>
|
||||
|
||||
public operator fun Matrix<T>.unaryMinus(): Matrix<T> = buildMatrix(rowNum, colNum) { i, j ->
|
||||
-get(i, j)
|
||||
@ -154,7 +153,7 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
||||
|
||||
/**
|
||||
* Gets a feature from the matrix. This function may return some additional features to
|
||||
* [space.kscience.kmath.nd.NDStructure.getFeature].
|
||||
* [group.kscience.kmath.nd.NDStructure.getFeature].
|
||||
*
|
||||
* @param F the type of feature.
|
||||
* @param m the matrix.
|
||||
@ -172,16 +171,7 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
||||
public fun <T : Any, A : Ring<T>> buffered(
|
||||
algebra: A,
|
||||
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
|
||||
): LinearSpace<T, A> = object : LinearSpace<T, A> {
|
||||
override val elementAlgebra: A = algebra
|
||||
|
||||
override fun buildMatrix(
|
||||
rows: Int, columns: Int,
|
||||
initializer: A.(i: Int, j: Int) -> T,
|
||||
): Matrix<T> = NDStructure.buffered(intArrayOf(rows, columns), bufferFactory) { (i, j) ->
|
||||
algebra.initializer(i, j)
|
||||
}.as2D()
|
||||
}
|
||||
): LinearSpace<T, A> = LinearSpaceOverNd(algebra,bufferFactory)
|
||||
|
||||
public val real: LinearSpace<Double, RealField> = buffered(RealField, Buffer.Companion::real)
|
||||
|
||||
@ -193,9 +183,11 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
public operator fun <LS : LinearSpace<*, *>, R> LS.invoke(block: LS.() -> R): R = run(block)
|
||||
|
||||
/**
|
||||
* Gets a feature from the matrix. This function may return some additional features to
|
||||
* [space.kscience.kmath.nd.NDStructure.getFeature].
|
||||
* [group.kscience.kmath.nd.NDStructure.getFeature].
|
||||
*
|
||||
* @param T the type of items in the matrices.
|
||||
* @param M the type of operated matrices.
|
||||
|
@ -0,0 +1,85 @@
|
||||
package space.kscience.kmath.linear
|
||||
|
||||
import space.kscience.kmath.nd.*
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import space.kscience.kmath.structures.VirtualBuffer
|
||||
import space.kscience.kmath.structures.indices
|
||||
|
||||
|
||||
public class LinearSpaceOverNd<T : Any, A : Ring<T>>(
|
||||
override val elementAlgebra: A,
|
||||
private val bufferFactory: BufferFactory<T>,
|
||||
) : LinearSpace<T, A> {
|
||||
|
||||
private fun ndRing(
|
||||
rows: Int,
|
||||
cols: Int,
|
||||
): BufferedNDRing<T, A> = NDAlgebra.ring(elementAlgebra, bufferFactory, rows, cols)
|
||||
|
||||
override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix<T> =
|
||||
ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D()
|
||||
|
||||
override fun buildVector(size: Int, initializer: A.(Int) -> T): Vector<T> =
|
||||
bufferFactory(size) { elementAlgebra.initializer(it) }
|
||||
|
||||
override fun Matrix<T>.unaryMinus(): Matrix<T> = ndRing(rowNum, colNum).run {
|
||||
unwrap().map { -it }.as2D()
|
||||
}
|
||||
|
||||
override fun Matrix<T>.plus(other: Matrix<T>): Matrix<T> = ndRing(rowNum, colNum).run {
|
||||
require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" }
|
||||
unwrap().plus(other.unwrap()).as2D()
|
||||
}
|
||||
|
||||
override fun Matrix<T>.minus(other: Matrix<T>): Matrix<T> = ndRing(rowNum, colNum).run {
|
||||
require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" }
|
||||
unwrap().minus(other.unwrap()).as2D()
|
||||
}
|
||||
|
||||
private fun Buffer<T>.linearize() = if (this is VirtualBuffer) {
|
||||
buildVector(size) { get(it) }
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
override fun Matrix<T>.dot(other: Matrix<T>): Matrix<T> {
|
||||
require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" }
|
||||
return elementAlgebra {
|
||||
val rows = this@dot.rows.map{it.linearize()}
|
||||
val columns = other.columns.map { it.linearize() }
|
||||
//TODO optimize buffers
|
||||
buildMatrix(rowNum, other.colNum) { i, j ->
|
||||
val r = rows[i]
|
||||
val c = columns[j]
|
||||
var res = zero
|
||||
for (l in r.indices) {
|
||||
res += r[l] * c[l]
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun Matrix<T>.dot(vector: Vector<T>): Vector<T> {
|
||||
require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" }
|
||||
return elementAlgebra {
|
||||
val rows = this@dot.rows
|
||||
//TODO optimize buffers
|
||||
buildVector(rowNum) { i ->
|
||||
val r = rows[i]
|
||||
var res = zero
|
||||
for (j in r.indices) {
|
||||
res += r[j] * vector[j]
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun Matrix<T>.times(value: T): Matrix<T> = ndRing(rowNum, colNum).run {
|
||||
unwrap().map { it * value }.as2D()
|
||||
}
|
||||
}
|
@ -79,20 +79,20 @@ public open class BufferedNDField<T, R : Field<T>>(
|
||||
override fun scale(a: NDStructure<T>, value: Double): NDStructure<T> = a.map { it * value }
|
||||
}
|
||||
|
||||
// space factories
|
||||
public fun <T, A : Group<T>> NDAlgebra.Companion.space(
|
||||
// group factories
|
||||
public fun <T, A : Group<T>> NDAlgebra.Companion.group(
|
||||
space: A,
|
||||
bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
): BufferedNDGroup<T, A> = BufferedNDGroup(shape, space, bufferFactory)
|
||||
|
||||
public inline fun <T, A : Group<T>, R> A.ndSpace(
|
||||
public inline fun <T, A : Group<T>, R> A.ndGroup(
|
||||
noinline bufferFactory: BufferFactory<T>,
|
||||
vararg shape: Int,
|
||||
action: BufferedNDGroup<T, A>.() -> R,
|
||||
): R {
|
||||
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
|
||||
return NDAlgebra.space(this, bufferFactory, *shape).run(action)
|
||||
return NDAlgebra.group(this, bufferFactory, *shape).run(action)
|
||||
}
|
||||
|
||||
//ring factories
|
||||
|
@ -45,14 +45,12 @@ private inline class Buffer1DWrapper<T>(val buffer: Buffer<T>) : Structure1D<T>
|
||||
/**
|
||||
* Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch
|
||||
*/
|
||||
public fun <T> NDStructure<T>.as1D(): Structure1D<T> = if (shape.size == 1) {
|
||||
public fun <T> NDStructure<T>.as1D(): Structure1D<T> = this as? Structure1D<T> ?: if (shape.size == 1) {
|
||||
when (this) {
|
||||
is Structure1DWrapper -> this
|
||||
is NDBuffer -> Buffer1DWrapper(this.buffer)
|
||||
else -> Structure1DWrapper(this)
|
||||
}
|
||||
} else
|
||||
error("Can't create 1d-structure from ${shape.size}d-structure")
|
||||
} else error("Can't create 1d-structure from ${shape.size}d-structure")
|
||||
|
||||
/**
|
||||
* Represent this buffer as 1D structure
|
||||
|
@ -26,14 +26,14 @@ public interface Structure2D<T> : NDStructure<T> {
|
||||
/**
|
||||
* The buffer of rows of this structure. It gets elements from the structure dynamically.
|
||||
*/
|
||||
public val rows: Buffer<Buffer<T>>
|
||||
get() = VirtualBuffer(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } }
|
||||
public val rows: List<Buffer<T>>
|
||||
get() = List(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } }
|
||||
|
||||
/**
|
||||
* The buffer of columns of this structure. It gets elements from the structure dynamically.
|
||||
*/
|
||||
public val columns: Buffer<Buffer<T>>
|
||||
get() = VirtualBuffer(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } }
|
||||
public val columns: List<Buffer<T>>
|
||||
get() = List(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } }
|
||||
|
||||
/**
|
||||
* Retrieves an element from the structure by two indices.
|
||||
@ -75,20 +75,15 @@ private class Structure2DWrapper<T>(val structure: NDStructure<T>) : Structure2D
|
||||
|
||||
override fun equals(other: Any?): Boolean = structure == other
|
||||
|
||||
override fun hashCode(): Int = structure.hashCode()
|
||||
override fun hashCode(): Int = structure.hashCode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch
|
||||
*/
|
||||
public fun <T> NDStructure<T>.as2D(): Structure2D<T> = if (shape.size == 2)
|
||||
Structure2DWrapper(this)
|
||||
else
|
||||
error("Can't create 2d-structure from ${shape.size}d-structure")
|
||||
public fun <T> NDStructure<T>.as2D(): Structure2D<T> = this as? Structure2D<T> ?: when (shape.size) {
|
||||
2 -> Structure2DWrapper(this)
|
||||
else -> error("Can't create 2d-structure from ${shape.size}d-structure")
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for [Structure2D] with more familiar name.
|
||||
*
|
||||
* @param T the type of items in the matrix.
|
||||
*/
|
||||
public typealias Matrix<T> = Structure2D<T>
|
||||
internal fun <T> Structure2D<T>.unwrap(): NDStructure<T> = if (this is Structure2DWrapper) structure else this
|
@ -13,10 +13,10 @@ internal class BufferAccessor2D<T : Any>(
|
||||
public val colNum: Int,
|
||||
val factory: MutableBufferFactory<T>,
|
||||
) {
|
||||
public operator fun Buffer<T>.get(i: Int, j: Int): T = get(i + colNum * j)
|
||||
public operator fun Buffer<T>.get(i: Int, j: Int): T = get(i*colNum + j)
|
||||
|
||||
public operator fun MutableBuffer<T>.set(i: Int, j: Int, value: T) {
|
||||
set(i + colNum * j, value)
|
||||
set(i*colNum + j, value)
|
||||
}
|
||||
|
||||
public inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer<T> =
|
||||
|
@ -0,0 +1,7 @@
|
||||
package space.kscience.kmath.structures
|
||||
|
||||
|
||||
public inline fun <T : Any, reified R : Any> Buffer<T>.map(
|
||||
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
||||
crossinline block: (T) -> R,
|
||||
): Buffer<R> = bufferFactory(size) { block(get(it)) }
|
@ -19,13 +19,13 @@ class RealLUSolverTest {
|
||||
LinearSpace.real.run {
|
||||
val matrix = matrix(2,2)(
|
||||
3.0, 1.0,
|
||||
1.0, 3.0
|
||||
2.0, 3.0
|
||||
)
|
||||
|
||||
val lup = lup(matrix)
|
||||
|
||||
//Check determinant
|
||||
assertEquals(8.0, lup.determinant)
|
||||
assertEquals(7.0, lup.determinant)
|
||||
|
||||
assertEquals(lup.p dot matrix, lup.l dot lup.u)
|
||||
}
|
||||
|
@ -5,14 +5,13 @@ import space.kscience.kmath.linear.*
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.getFeature
|
||||
import space.kscience.kmath.operations.RealField
|
||||
import space.kscience.kmath.operations.ScaleOperations
|
||||
|
||||
/**
|
||||
* Represents context of basic operations operating with [EjmlMatrix].
|
||||
*
|
||||
* @author Iaroslav Postovalov
|
||||
*/
|
||||
public object EjmlLinearSpace : LinearSpace<Double, RealField>, ScaleOperations<Matrix<Double>> {
|
||||
public object EjmlLinearSpace : LinearSpace<Double, RealField> {
|
||||
|
||||
override val elementAlgebra: RealField get() = RealField
|
||||
|
||||
@ -50,7 +49,7 @@ public object EjmlLinearSpace : LinearSpace<Double, RealField>, ScaleOperations<
|
||||
private fun SimpleMatrix.wrapMatrix() = EjmlMatrix(this)
|
||||
private fun SimpleMatrix.wrapVector() = EjmlVector(this)
|
||||
|
||||
override fun Matrix<Double>.unaryMinus(): Matrix<Double> = this * (-1)
|
||||
override fun Matrix<Double>.unaryMinus(): Matrix<Double> = this * (-1.0)
|
||||
|
||||
public override fun Matrix<Double>.dot(other: Matrix<Double>): EjmlMatrix =
|
||||
EjmlMatrix(toEjml().origin.mult(other.toEjml().origin))
|
||||
@ -61,9 +60,6 @@ public object EjmlLinearSpace : LinearSpace<Double, RealField>, ScaleOperations<
|
||||
public override operator fun Matrix<Double>.minus(other: Matrix<Double>): EjmlMatrix =
|
||||
(toEjml().origin - other.toEjml().origin).wrapMatrix()
|
||||
|
||||
public override fun scale(a: Matrix<Double>, value: Double): EjmlMatrix =
|
||||
a.toEjml().origin.scale(value).wrapMatrix()
|
||||
|
||||
public override operator fun Matrix<Double>.times(value: Double): EjmlMatrix =
|
||||
toEjml().origin.scale(value).wrapMatrix()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package space.kscience.kmath.real
|
||||
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.nd.Matrix
|
||||
import space.kscience.kmath.linear.Matrix
|
||||
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user