Change EJML implementation to match CM and Ojalgo

This commit is contained in:
Alexander Nozik 2025-01-12 13:04:46 +03:00
parent 1ec3d1adb9
commit b2b64f35d0
9 changed files with 232 additions and 219 deletions

View File

@ -10,6 +10,7 @@
- attributes-kt moved to a separate project, and the version used is 0.3.0
- Kotlin 2.1. Now use cross-compilation to deploy macOS targets.
- Changed `origin` to `cmMatrix` in kmath-commons to avoid property name clash. Expose bidirectional conversion in `CMLinearSpace`
- (BREAKING CHANGE) Changed implementations in `kmath-ejml` to match CM and ojalgo style. Specifically, provide bidirectional conversion for library types.
### Deprecated

View File

@ -10,7 +10,6 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.commons.linear.CMLinearSpace.dot
import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM
import space.kscience.kmath.linear.Float64ParallelLinearSpace
import space.kscience.kmath.linear.invoke
@ -59,13 +58,13 @@ internal class DotBenchmark {
}
@Benchmark
fun cmDot(blackhole: Blackhole) = CMLinearSpace {
blackhole.consume(cmMatrix1 dot cmMatrix2)
fun cmDot(blackhole: Blackhole): Unit = CMLinearSpace {
blackhole.consume(cmMatrix1.asMatrix() dot cmMatrix2.asMatrix())
}
@Benchmark
fun ejmlDot(blackhole: Blackhole) = EjmlLinearSpaceDDRM {
blackhole.consume(ejmlMatrix1 dot ejmlMatrix2)
fun ejmlDot(blackhole: Blackhole): Unit = EjmlLinearSpaceDDRM {
blackhole.consume(ejmlMatrix1.asMatrix() dot ejmlMatrix2.asMatrix())
}
@Benchmark

View File

@ -22,16 +22,16 @@ import space.kscience.kmath.structures.Float64
* @param M the EJML matrix type.
* @author Iaroslav Postovalov
*/
public abstract class EjmlLinearSpace<T : Any, out A : Ring<T>, out M : org.ejml.data.Matrix> : LinearSpace<T, A> {
public interface EjmlLinearSpace<T : Any, out A : Ring<T>, M : org.ejml.data.Matrix> : LinearSpace<T, A> {
/**
* Converts this matrix to EJML one.
*/
public abstract fun Matrix<T>.toEjml(): EjmlMatrix<T, M>
public fun Matrix<T>.toEjml(): M
/**
* Converts this vector to EJML one.
*/
public abstract fun Point<T>.toEjml(): EjmlVector<T, M>
public fun Point<T>.toEjml(): M
public abstract override fun buildMatrix(
rows: Int,

View File

@ -13,10 +13,10 @@ import space.kscience.kmath.nd.Structure2D
*
* @param T the type of elements contained in the buffer.
* @param M the type of EJML matrix.
* @property origin The underlying EJML matrix.
* @property ejmlMatrix The underlying EJML matrix.
* @author Iaroslav Postovalov
*/
public abstract class EjmlMatrix<out T, out M : Matrix>(public open val origin: M) : Structure2D<T> {
override val rowNum: Int get() = origin.numRows
override val colNum: Int get() = origin.numCols
public abstract class EjmlMatrix<out T, out M : Matrix>(public open val ejmlMatrix: M) : Structure2D<T> {
override val rowNum: Int get() = ejmlMatrix.numRows
override val colNum: Int get() = ejmlMatrix.numCols
}

View File

@ -13,12 +13,12 @@ import space.kscience.kmath.linear.Point
*
* @param T the type of elements contained in the buffer.
* @param M the type of EJML matrix.
* @property origin The underlying matrix, must have only one row.
* @property ejmlVector The underlying matrix, must have only one row.
* @author Iaroslav Postovalov
*/
public abstract class EjmlVector<out T, out M : Matrix>(public open val origin: M) : Point<T> {
public abstract class EjmlVector<out T, out M : Matrix>(public open val ejmlVector: M) : Point<T> {
override val size: Int
get() = origin.numRows
get() = ejmlVector.numRows
override operator fun iterator(): Iterator<T> = object : Iterator<T> {
private var cursor: Int = 0
@ -28,8 +28,8 @@ public abstract class EjmlVector<out T, out M : Matrix>(public open val origin:
return this@EjmlVector[cursor - 1]
}
override fun hasNext(): Boolean = cursor < origin.numCols * origin.numRows
override fun hasNext(): Boolean = cursor < ejmlVector.numCols * ejmlVector.numRows
}
override fun toString(): String = "EjmlVector(origin=$origin)"
override fun toString(): String = "EjmlVector(origin=$ejmlVector)"
}

View File

@ -86,7 +86,7 @@ internal class EjmlMatrixTest {
@Test
fun origin() {
val m = randomMatrix
assertSame(m, EjmlDoubleMatrix(m).origin)
assertSame(m, EjmlDoubleMatrix(m).ejmlMatrix)
}
@Test
@ -100,7 +100,7 @@ internal class EjmlMatrixTest {
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 }
val inverted = matrix.toEjml().inverted()
val inverted = matrix.inverted()
val res = matrix dot inverted

View File

@ -55,7 +55,7 @@ internal class EjmlVectorTest {
fun origin() {
val m = randomMatrix
val w = EjmlDoubleVector(m)
assertSame(m, w.origin)
assertSame(m, w.ejmlVector)
}
@Test

View File

@ -3,6 +3,8 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("CONTEXT_RECEIVERS_DEPRECATED")
import space.kscience.kmath.geometry.GeometrySpace
import space.kscience.kmath.geometry.Line
import space.kscience.kmath.geometry.LineSegment