diff --git a/build.gradle.kts b/build.gradle.kts index e5c4fc39b..6f0478fc2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,10 @@ buildscript { - extra["kotlinVersion"] = "1.3.20-eap-100" - extra["ioVersion"] = "0.1.2" - extra["coroutinesVersion"] = "1.1.0" - - val kotlinVersion: String by extra - val ioVersion: String by extra - val coroutinesVersion: String by extra + val kotlinVersion: String by rootProject.extra("1.3.20") + val ioVersion: String by rootProject.extra("0.1.2") + val coroutinesVersion: String by rootProject.extra("1.1.1") repositories { - maven("https://dl.bintray.com/kotlin/kotlin-eap") + //maven("https://dl.bintray.com/kotlin/kotlin-eap") jcenter() } @@ -28,7 +24,7 @@ allprojects { apply(plugin = "com.jfrog.artifactory") group = "scientifik" - version = "0.0.3-dev-3" + version = "0.0.3-dev-4" repositories { maven("https://dl.bintray.com/kotlin/kotlin-eap") diff --git a/kmath-commons/src/main/kotlin/scientifik/kmath/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/scientifik/kmath/linear/CMMatrix.kt index aed4f4bb1..808b2768b 100644 --- a/kmath-commons/src/main/kotlin/scientifik/kmath/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/scientifik/kmath/linear/CMMatrix.kt @@ -4,11 +4,16 @@ import org.apache.commons.math3.linear.* import org.apache.commons.math3.linear.RealMatrix import org.apache.commons.math3.linear.RealVector -inline class CMMatrix(val origin: RealMatrix) : Matrix { +class CMMatrix(val origin: RealMatrix, features: Set? = null) : Matrix { override val rowNum: Int get() = origin.rowDimension override val colNum: Int get() = origin.columnDimension - override val features: Set get() = emptySet() + override val features: Set = features ?: sequence { + if(origin is DiagonalMatrix) yield(DiagonalFeature) + }.toSet() + + override fun suggestFeature(vararg features: MatrixFeature) = + CMMatrix(origin, this.features + features) override fun get(i: Int, j: Int): Double = origin.getEntry(i, j) } @@ -23,7 +28,7 @@ fun Matrix.toCM(): CMMatrix = if (this is CMMatrix) { fun RealMatrix.toMatrix() = CMMatrix(this) -inline class CMVector(val origin: RealVector) : Point { +class CMVector(val origin: RealVector) : Point { override val size: Int get() = origin.dimension override fun get(index: Int): Double = origin.getEntry(index) diff --git a/kmath-core/build.gradle b/kmath-core/build.gradle deleted file mode 100644 index b1a6cccb5..000000000 --- a/kmath-core/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -plugins { - id "org.jetbrains.kotlin.multiplatform" -} - -kotlin { - jvm { - compilations["main"].kotlinOptions.jvmTarget = "1.8" - compilations["test"].kotlinOptions.jvmTarget = "1.8" - } - js() - - sourceSets { - commonMain { - dependencies { - api 'org.jetbrains.kotlin:kotlin-stdlib-common' - } - } - commonTest { - dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-common' - implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' - } - } - jvmMain { - dependencies { - api 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - } - } - jvmTest { - dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test' - implementation 'org.jetbrains.kotlin:kotlin-test-junit' - } - } - jsMain { - dependencies { - api 'org.jetbrains.kotlin:kotlin-stdlib-js' - } - } - jsTest { - dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-js' - } - } -// mingwMain { -// } -// mingwTest { -// } - } -} diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts new file mode 100644 index 000000000..2e753f624 --- /dev/null +++ b/kmath-core/build.gradle.kts @@ -0,0 +1,55 @@ +plugins { + kotlin("multiplatform") +} + + +kotlin { + jvm { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs += "-progressive" + } + } + } + js() + + sourceSets { + val commonMain by getting { + dependencies { + api(kotlin("stdlib")) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + val jvmMain by getting { + dependencies { + api(kotlin("stdlib-jdk8")) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(kotlin("test-junit")) + } + } + val jsMain by getting { + dependencies { + api(kotlin("stdlib-js")) + } + } + val jsTest by getting { + dependencies { + implementation(kotlin("test-js")) + } + } +// mingwMain { +// } +// mingwTest { +// } + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt index 5b65821db..3752f6db5 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt @@ -35,6 +35,9 @@ class BufferMatrix( override val shape: IntArray get() = intArrayOf(rowNum, colNum) + override fun suggestFeature(vararg features: MatrixFeature) = + BufferMatrix(rowNum, colNum, buffer, this.features + features) + override fun get(index: IntArray): T = get(index[0], index[1]) override fun get(i: Int, j: Int): T = buffer[i * colNum + j] diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt index b2161baf2..85ddb8786 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt @@ -8,20 +8,19 @@ import scientifik.kmath.structures.MutableBufferFactory import scientifik.kmath.structures.NDStructure import scientifik.kmath.structures.get - class LUPDecomposition>( private val elementContext: Ring, internal val lu: NDStructure, val pivot: IntArray, private val even: Boolean -) : DeterminantFeature { +) : LUPDecompositionFeature, DeterminantFeature { /** * Returns the matrix L of the decomposition. * * L is a lower-triangular matrix with [Ring.one] in diagonal */ - val l: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> + override val l: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1], setOf(LFeature)) { i, j -> when { j < i -> lu[i, j] j == i -> elementContext.one @@ -35,7 +34,7 @@ class LUPDecomposition>( * * U is an upper-triangular matrix including the diagonal */ - val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> + override val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1], setOf(UFeature)) { i, j -> if (j >= i) lu[i, j] else elementContext.zero } @@ -46,7 +45,7 @@ class LUPDecomposition>( * P is a sparse matrix with exactly one element set to [Ring.one] in * each row and each column, all other elements being set to [Ring.zero]. */ - val p: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> + override val p: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> if (j == pivot[i]) elementContext.one else elementContext.zero } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt index 5b4f3f12d..533e77d61 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Matrix.kt @@ -107,26 +107,6 @@ interface GenericMatrixContext> : MatrixContext { produce(rowNum, colNum) { i, j -> elementContext.run { get(i, j) * value } } } -/** - * A marker interface representing some matrix feature like diagonal, sparce, zero, etc. Features used to optimize matrix - * operations performance in some cases. - */ -interface MatrixFeature - -object DiagonalFeature : MatrixFeature - -object ZeroFeature : MatrixFeature - -object UnitFeature : MatrixFeature - -interface InverseMatrixFeature : MatrixFeature { - val inverse: Matrix -} - -interface DeterminantFeature : MatrixFeature { - val determinant: T -} - /** * Specialized 2-d structure */ @@ -136,6 +116,14 @@ interface Matrix : NDStructure { val features: Set + /** + * Suggest new feature for this matrix. The result is the new matrix that may or may not reuse existing data structure. + * + * The implementation does not guarantee to check that matrix actually have the feature, so one should be careful to + * add only those features that are valid. + */ + fun suggestFeature(vararg features: MatrixFeature): Matrix + operator fun get(i: Int, j: Int): T override fun get(index: IntArray): T = get(index[0], index[1]) @@ -167,12 +155,22 @@ interface Matrix : NDStructure { /** * Build a square matrix from given elements. */ - fun build(vararg elements: T): Matrix { + fun square(vararg elements: T): Matrix { val size: Int = sqrt(elements.size.toDouble()).toInt() if (size * size != elements.size) error("The number of elements ${elements.size} is not a full square") val buffer = elements.asBuffer() return BufferMatrix(size, size, buffer) } + + fun build(rows: Int, columns: Int): MatrixBuilder = MatrixBuilder(rows, columns) + } +} + +class MatrixBuilder(val rows: Int, val columns: Int) { + operator fun invoke(vararg elements: T): Matrix { + if (rows * columns != elements.size) error("The number of elements ${elements.size} is not equal $rows * $columns") + val buffer = elements.asBuffer() + return BufferMatrix(rows, columns, buffer) } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixFeatures.kt new file mode 100644 index 000000000..6b45a14b1 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixFeatures.kt @@ -0,0 +1,62 @@ +package scientifik.kmath.linear + +/** + * A marker interface representing some matrix feature like diagonal, sparce, zero, etc. Features used to optimize matrix + * operations performance in some cases. + */ +interface MatrixFeature + +/** + * The matrix with this feature is considered to have only diagonal non-null elements + */ +object DiagonalFeature : MatrixFeature + +/** + * Matrix with this feature has all zero elements + */ +object ZeroFeature : MatrixFeature + +/** + * Matrix with this feature have unit elements on diagonal and zero elements in all other places + */ +object UnitFeature : MatrixFeature + +/** + * Inverted matrix feature + */ +interface InverseMatrixFeature : MatrixFeature { + val inverse: Matrix +} + +/** + * A determinant container + */ +interface DeterminantFeature : MatrixFeature { + val determinant: T +} + +@Suppress("FunctionName") +fun DeterminantFeature(determinant: T) = object: DeterminantFeature{ + override val determinant: T = determinant +} + +/** + * Lower triangular matrix + */ +object LFeature: MatrixFeature + +/** + * Upper triangular feature + */ +object UFeature: MatrixFeature + +/** + * TODO add documentation + */ +interface LUPDecompositionFeature : MatrixFeature { + val l: Matrix + val u: Matrix + val p: Matrix +} + +//TODO add sparse matrix feature \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt index 98655ad48..1bab52902 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt @@ -8,6 +8,9 @@ class VirtualMatrix( ) : Matrix { override fun get(i: Int, j: Int): T = generator(i, j) + override fun suggestFeature(vararg features: MatrixFeature) = + VirtualMatrix(rowNum, colNum, this.features + features, generator) + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Matrix<*>) return false diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt index 5c887f343..09e93483d 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt @@ -15,6 +15,7 @@ class ShortNDRing(override val shape: IntArray) : override val zero by lazy { produce { ShortRing.zero } } override val one by lazy { produce { ShortRing.one } } + @Suppress("OVERRIDE_BY_INLINE") override inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Short): Buffer = ShortBuffer(ShortArray(size) { initializer(it) }) diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt index 2a00b84cd..61aa506c4 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt @@ -41,4 +41,14 @@ class MatrixTest { assertEquals(5.0, product[1, 0]) assertEquals(6.0, product[2, 2]) } + + @Test + fun testBuilder() { + val matrix = Matrix.build(2, 3)( + 1.0, 0.0, 0.0, + 0.0, 1.0, 2.0 + ) + + assertEquals(2.0, matrix[1, 2]) + } } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt index ea104355c..bfa720369 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt @@ -13,7 +13,7 @@ class RealLUSolverTest { @Test fun testInvert() { - val matrix = Matrix.build( + val matrix = Matrix.square( 3.0, 1.0, 1.0, 3.0 ) @@ -31,7 +31,7 @@ class RealLUSolverTest { val inverted = LUSolver.real.inverse(decomposed) - val expected = Matrix.build( + val expected = Matrix.square( 0.375, -0.125, -0.125, 0.375 ) diff --git a/kmath-koma/build.gradle.kts b/kmath-koma/build.gradle.kts index 20ad02fbe..b95aaf3c8 100644 --- a/kmath-koma/build.gradle.kts +++ b/kmath-koma/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("kotlin-multiplatform") + kotlin("multiplatform") } repositories { @@ -8,8 +8,12 @@ repositories { kotlin { jvm { - compilations["main"].kotlinOptions.jvmTarget = "1.8" - compilations["test"].kotlinOptions.jvmTarget = "1.8" + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs += "-progressive" + } + } } js() diff --git a/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt b/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt index 3b7894d18..343d5b8b9 100644 --- a/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt +++ b/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt @@ -48,10 +48,25 @@ class KomaMatrixContext(val factory: MatrixFactory(val origin: koma.matrix.Matrix) : Matrix { +class KomaMatrix(val origin: koma.matrix.Matrix, features: Set? = null) : + Matrix { override val rowNum: Int get() = origin.numRows() override val colNum: Int get() = origin.numCols() - override val features: Set get() = emptySet() + + override val features: Set = features ?: setOf( + object : DeterminantFeature { + override val determinant: T get() = origin.det() + }, + object : LUPDecompositionFeature { + private val lup by lazy { origin.LU() } + override val l: Matrix get() = KomaMatrix(lup.second) + override val u: Matrix get() = KomaMatrix(lup.third) + override val p: Matrix get() = KomaMatrix(lup.first) + } + ) + + override fun suggestFeature(vararg features: MatrixFeature): Matrix = + KomaMatrix(this.origin, this.features + features) override fun get(i: Int, j: Int): T = origin.getGeneric(i, j) } diff --git a/settings.gradle.kts b/settings.gradle.kts index ca738647e..cee985432 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ pluginManagement { repositories { mavenCentral() maven("https://plugins.gradle.org/m2/") - maven ("https://dl.bintray.com/kotlin/kotlin-eap") + //maven ("https://dl.bintray.com/kotlin/kotlin-eap") } }