From 41a325d4284bf31494ca1b04950059c93efa7168 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 18 Feb 2024 14:22:20 +0300 Subject: [PATCH] fix dot bug introduced in the last refactor. Add test for parallel linear algebra. --- CHANGELOG.md | 1 + .../kmath/linear/Float64LinearSpace.kt | 4 +- .../kmath/linear/DoubleLUSolverTest.kt | 4 +- .../space/kscience/kmath/linear/MatrixTest.kt | 4 +- .../linear/Float64ParallelLinearSpace.kt | 4 +- .../kmath/linear/ParallelMatrixTest.kt | 74 +++++++++++++++++++ 6 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index cf8dd62cc..07ab04fc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - New Attributes-kt module that could be used as stand-alone. It declares. type-safe attributes containers. - Explicit `mutableStructureND` builders for mutable structures. - `Buffer.asList()` zero-copy transformation. +- Wasm support. - Parallel implementation of `LinearSpace` for Float64 - Parallel buffer factories diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt index f1290d727..bafdbbc3b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/Float64LinearSpace.kt @@ -54,7 +54,7 @@ public object Float64LinearSpace : LinearSpace { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } val rows = this@dot.rows.map { it.linearize() } val columns = other.columns.map { it.linearize() } - val indices = 0 until this.rowNum + val indices = 0 until this.colNum return buildMatrix(rowNum, other.colNum) { i, j -> val r = rows[i] val c = columns[j] @@ -70,7 +70,7 @@ public object Float64LinearSpace : LinearSpace { override fun Matrix.dot(vector: Point): Float64Buffer { require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } val rows = this@dot.rows.map { it.linearize() } - val indices = 0 until this.rowNum + val indices = 0 until this.colNum return Float64Buffer(rowNum) { i -> val r = rows[i] var res = 0.0 diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt index 999c9ffbe..901b1157c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt @@ -28,13 +28,13 @@ class DoubleLUSolverTest { } @Test - fun testDecomposition() = Double.algebra.linearSpace.run { + fun testDecomposition() = with(Double.algebra.linearSpace){ val matrix = matrix(2, 2)( 3.0, 1.0, 2.0, 3.0 ) - val lup = lup(matrix) + val lup = elementAlgebra.lup(matrix) //Check determinant // assertEquals(7.0, lup.determinant) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt index 4e9cc2011..f7863a68c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.linear import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals @@ -58,7 +59,7 @@ class MatrixTest { } @Test - fun test2DDot() = Double.algebra.linearSpace.run { + fun test2DDot() = Float64Field.linearSpace { val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() } val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() } @@ -70,6 +71,5 @@ class MatrixTest { assertEquals(8.0, result[0, 1]) assertEquals(8.0, result[1, 0]) assertEquals(14.0, result[1, 1]) - } } diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt index 9e05fded1..fd200d9f8 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/linear/Float64ParallelLinearSpace.kt @@ -69,7 +69,7 @@ public object Float64ParallelLinearSpace : LinearSpace { require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } val rows = this@dot.rows.map { it.linearize() } val columns = other.columns.map { it.linearize() } - val indices = 0 until this.rowNum + val indices = 0 until this.colNum return buildMatrix(rowNum, other.colNum) { i, j -> val r = rows[i] val c = columns[j] @@ -85,7 +85,7 @@ public object Float64ParallelLinearSpace : LinearSpace { override fun Matrix.dot(vector: Point): Float64Buffer { require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } val rows = this@dot.rows.map { it.linearize() } - val indices = 0 until this.rowNum + val indices = 0 until this.colNum return Float64Buffer(rowNum) { i -> val r = rows[i] var res = 0.0 diff --git a/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt new file mode 100644 index 000000000..493948361 --- /dev/null +++ b/kmath-core/src/jvmTest/kotlin/space/kscience/kmath/linear/ParallelMatrixTest.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2018-2024 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.linear + +import space.kscience.kmath.PerformancePitfall +import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.Float64Field +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +@UnstableKMathAPI +@OptIn(PerformancePitfall::class) +@Suppress("UNUSED_VARIABLE") +class ParallelMatrixTest { + + @Test + fun testTranspose() = Float64Field.linearSpace.parallel{ + val matrix = one(3, 3) + val transposed = matrix.transposed() + assertTrue { StructureND.contentEquals(matrix, transposed) } + } + + @Test + fun testBuilder() = Float64Field.linearSpace.parallel{ + val matrix = matrix(2, 3)( + 1.0, 0.0, 0.0, + 0.0, 1.0, 2.0 + ) + + assertEquals(2.0, matrix[1, 2]) + } + + @Test + fun testMatrixExtension() = Float64Field.linearSpace.parallel{ + val transitionMatrix: Matrix = VirtualMatrix(type,6, 6) { row, col -> + when { + col == 0 -> .50 + row + 1 == col -> .50 + row == 5 && col == 5 -> 1.0 + else -> 0.0 + } + } + + infix fun Matrix.pow(power: Int): Matrix { + var res = this + repeat(power - 1) { + res = res dot this@pow + } + return res + } + + val toTenthPower = transitionMatrix pow 10 + } + + @Test + fun test2DDot() = Float64Field.linearSpace.parallel { + val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() } + val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() } + +// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() } +// val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() } + val result = firstMatrix dot secondMatrix + assertEquals(2, result.rowNum) + assertEquals(2, result.colNum) + assertEquals(8.0, result[0, 1]) + assertEquals(8.0, result[1, 0]) + assertEquals(14.0, result[1, 1]) + } +}