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 - 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. - 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` - 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 ### Deprecated

View File

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

View File

@ -22,16 +22,16 @@ import space.kscience.kmath.structures.Float64
* @param M the EJML matrix type. * @param M the EJML matrix type.
* @author Iaroslav Postovalov * @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. * 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. * 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( public abstract override fun buildMatrix(
rows: Int, 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 T the type of elements contained in the buffer.
* @param M the type of EJML matrix. * @param M the type of EJML matrix.
* @property origin The underlying EJML matrix. * @property ejmlMatrix The underlying EJML matrix.
* @author Iaroslav Postovalov * @author Iaroslav Postovalov
*/ */
public abstract class EjmlMatrix<out T, out M : Matrix>(public open val origin: M) : Structure2D<T> { public abstract class EjmlMatrix<out T, out M : Matrix>(public open val ejmlMatrix: M) : Structure2D<T> {
override val rowNum: Int get() = origin.numRows override val rowNum: Int get() = ejmlMatrix.numRows
override val colNum: Int get() = origin.numCols 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 T the type of elements contained in the buffer.
* @param M the type of EJML matrix. * @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 * @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 override val size: Int
get() = origin.numRows get() = ejmlVector.numRows
override operator fun iterator(): Iterator<T> = object : Iterator<T> { override operator fun iterator(): Iterator<T> = object : Iterator<T> {
private var cursor: Int = 0 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] 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 @Test
fun origin() { fun origin() {
val m = randomMatrix val m = randomMatrix
assertSame(m, EjmlDoubleMatrix(m).origin) assertSame(m, EjmlDoubleMatrix(m).ejmlMatrix)
} }
@Test @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 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 l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
val matrix = space { l dot u } val matrix = space { l dot u }
val inverted = matrix.toEjml().inverted() val inverted = matrix.inverted()
val res = matrix dot inverted val res = matrix dot inverted

View File

@ -55,7 +55,7 @@ internal class EjmlVectorTest {
fun origin() { fun origin() {
val m = randomMatrix val m = randomMatrix
val w = EjmlDoubleVector(m) val w = EjmlDoubleVector(m)
assertSame(m, w.origin) assertSame(m, w.ejmlVector)
} }
@Test @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. * 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.GeometrySpace
import space.kscience.kmath.geometry.Line import space.kscience.kmath.geometry.Line
import space.kscience.kmath.geometry.LineSegment import space.kscience.kmath.geometry.LineSegment