diff --git a/README.md b/README.md index 34761e838..5678fc530 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,9 @@ -[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) +Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/scientifik/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/kmath-core/_latestVersion) + +Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/kmath-core/_latestVersion) + [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) -![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) - -Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/scientifik/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/kmath-core/_latestVersion) - -Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/kmath-core/_latestVersion) - # KMath Could be pronounced as `key-math`. The Kotlin MATHematics library is intended as a Kotlin-based analog to Python's `numpy` library. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. @@ -43,8 +40,6 @@ can be used for a wide variety of purposes from high performance calculations to * **Streaming** Streaming operations on mathematical objects and objects buffers. -* **Type-safe dimensions** Type-safe dimensions for matrix operations. - * **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free to submit a feature request if you want something to be done first. diff --git a/build.gradle.kts b/build.gradle.kts index 6c4536b4c..a63966dfe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id("scientifik.publish") version "0.4.1" apply false + id("scientifik.publish") version "0.2.6" apply false } -val kmathVersion by extra("0.1.4-dev-2") +val kmathVersion by extra("0.1.4-dev-1") val bintrayRepo by extra("scientifik") val githubProject by extra("kmath") diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 8853b78a5..ad59afc5c 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -4,8 +4,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { java kotlin("jvm") - kotlin("plugin.allopen") version "1.3.71" - id("kotlinx.benchmark") version "0.2.0-dev-7" + kotlin("plugin.allopen") version "1.3.60" + id("kotlinx.benchmark") version "0.2.0-dev-5" } configure { @@ -13,9 +13,10 @@ configure { } repositories { + maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("http://dl.bintray.com/kyonifer/maven") - maven("https://dl.bintray.com/mipt-npm/scientifik") - maven("https://dl.bintray.com/mipt-npm/dev") + maven ("https://dl.bintray.com/orangy/maven") + mavenCentral() } @@ -28,11 +29,12 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-koma")) - implementation(project(":kmath-viktor")) - implementation(project(":kmath-dimensions")) implementation("com.kyonifer:koma-core-ejml:0.12") - implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6") - implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-7") + implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:${Scientifik.ioVersion}") + + implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-2") + + "benchmarksCompile"(sourceSets.main.get().compileClasspath) } diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ViktorBenchmark.kt deleted file mode 100644 index be4115d81..000000000 --- a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ViktorBenchmark.kt +++ /dev/null @@ -1,71 +0,0 @@ -package scientifik.kmath.structures - -import org.jetbrains.bio.viktor.F64Array -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import scientifik.kmath.operations.RealField -import scientifik.kmath.viktor.ViktorNDField - - -@State(Scope.Benchmark) -class ViktorBenchmark { - final val dim = 1000 - final val n = 100 - - // automatically build context most suited for given type. - final val autoField = NDField.auto(RealField, dim, dim) - final val realField = NDField.real(dim, dim) - - final val viktorField = ViktorNDField(intArrayOf(dim, dim)) - - @Benchmark - fun `Automatic field addition`() { - autoField.run { - var res = one - repeat(n) { - res += 1.0 - } - } - } - - @Benchmark - fun `Viktor field addition`() { - viktorField.run { - var res = one - repeat(n) { - res += one - } - } - } - - @Benchmark - fun `Raw Viktor`() { - val one = F64Array.full(init = 1.0, shape = *intArrayOf(dim, dim)) - var res = one - repeat(n) { - res = res + one - } - } - - @Benchmark - fun `Real field log`() { - realField.run { - val fortyTwo = produce { 42.0 } - var res = one - - repeat(n) { - res = ln(fortyTwo) - } - } - } - - @Benchmark - fun `Raw Viktor log`() { - val fortyTwo = F64Array.full(dim, dim, init = 42.0) - var res: F64Array - repeat(n) { - res = fortyTwo.log() - } - } -} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/utils/utils.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/utils/utils.kt deleted file mode 100644 index 6ec9e9c17..000000000 --- a/examples/src/benchmarks/kotlin/scientifik/kmath/utils/utils.kt +++ /dev/null @@ -1,8 +0,0 @@ -package scientifik.kmath.utils - -import kotlin.system.measureTimeMillis - -internal inline fun measureAndPrint(title: String, block: () -> Unit) { - val time = measureTimeMillis(block) - println("$title completed in $time millis") -} \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt index cfd1206ff..7e8c433c0 100644 --- a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt @@ -4,13 +4,7 @@ import kotlinx.coroutines.GlobalScope import scientifik.kmath.operations.RealField import kotlin.system.measureTimeMillis -internal inline fun measureAndPrint(title: String, block: () -> Unit) { - val time = measureTimeMillis(block) - println("$title completed in $time millis") -} - - -fun main() { +fun main(args: Array) { val dim = 1000 val n = 1000 @@ -21,7 +15,8 @@ fun main() { //A generic boxing field. It should be used for objects, not primitives. val genericField = NDField.boxing(RealField, dim, dim) - measureAndPrint("Automatic field addition") { + + val autoTime = measureTimeMillis { autoField.run { var res = one repeat(n) { @@ -30,14 +25,18 @@ fun main() { } } - measureAndPrint("Element addition"){ + println("Automatic field addition completed in $autoTime millis") + + val elementTime = measureTimeMillis { var res = genericField.one repeat(n) { res += 1.0 } } - measureAndPrint("Specialized addition") { + println("Element addition completed in $elementTime millis") + + val specializedTime = measureTimeMillis { specializedField.run { var res: NDBuffer = one repeat(n) { @@ -46,7 +45,10 @@ fun main() { } } - measureAndPrint("Lazy addition") { + println("Specialized addition completed in $specializedTime millis") + + + val lazyTime = measureTimeMillis { val res = specializedField.one.mapAsync(GlobalScope) { var c = 0.0 repeat(n) { @@ -58,7 +60,9 @@ fun main() { res.elements().forEach { it.second } } - measureAndPrint("Generic addition") { + println("Lazy addition completed in $lazyTime millis") + + val genericTime = measureTimeMillis { //genericField.run(action) genericField.run { var res: NDBuffer = one @@ -68,4 +72,6 @@ fun main() { } } + println("Generic addition completed in $genericTime millis") + } \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/scientifik/kmath/structures/typeSafeDimensions.kt deleted file mode 100644 index 9169c7d7b..000000000 --- a/examples/src/main/kotlin/scientifik/kmath/structures/typeSafeDimensions.kt +++ /dev/null @@ -1,34 +0,0 @@ -package scientifik.kmath.structures - -import scientifik.kmath.dimensions.D2 -import scientifik.kmath.dimensions.D3 -import scientifik.kmath.dimensions.DMatrixContext -import scientifik.kmath.dimensions.Dimension -import scientifik.kmath.operations.RealField - -fun DMatrixContext.simple() { - val m1 = produce { i, j -> (i + j).toDouble() } - val m2 = produce { i, j -> (i + j).toDouble() } - - //Dimension-safe addition - m1.transpose() + m2 -} - -object D5 : Dimension { - override val dim: UInt = 5u -} - -fun DMatrixContext.custom() { - val m1 = produce { i, j -> (i + j).toDouble() } - val m2 = produce { i, j -> (i - j).toDouble() } - val m3 = produce { i, j -> (i - j).toDouble() } - - (m1 dot m2) + m3 -} - -fun main() { - DMatrixContext.real.run { - simple() - custom() - } -} \ No newline at end of file diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 5ce1b935a..9b446f872 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { api(project(":kmath-core")) api(project(":kmath-coroutines")) api(project(":kmath-prob")) - api(project(":kmath-functions")) api("org.apache.commons:commons-math3:3.6.1") + testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt rename to kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt diff --git a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/linear/RealVector.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/RealVector.kt similarity index 100% rename from kmath-for-real/src/commonMain/kotlin/scientifik/kmath/linear/RealVector.kt rename to kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/RealVector.kt diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/functions.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/functions.kt new file mode 100644 index 000000000..cef8209ed --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/functions.kt @@ -0,0 +1,37 @@ +package scientifik.kmath.coroutines + +import scientifik.kmath.operations.RealField +import scientifik.kmath.operations.SpaceOperations +import kotlin.jvm.JvmName + +/** + * A suspendable univariate function defined in algebraic context + */ +interface UFunction> { + suspend operator fun C.invoke(arg: T): T +} + +suspend fun UFunction.invoke(arg: Double) = RealField.invoke(arg) + +/** + * A suspendable multivariate (N->1) function defined on algebraic context + */ +interface MFunction> { + /** + * The input dimension of the function + */ + val dimension: UInt + + suspend operator fun C.invoke(vararg args: T): T +} + +suspend fun MFunction.invoke(args: DoubleArray) = RealField.invoke(*args.toTypedArray()) +@JvmName("varargInvoke") +suspend fun MFunction.invoke(vararg args: Double) = RealField.invoke(*args.toTypedArray()) + +/** + * A suspendable univariate function with parameter + */ +interface ParametricUFunction> { + suspend operator fun C.invoke(arg: T, parameter: P): T +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt index 485185526..0ed769db8 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt @@ -6,14 +6,14 @@ annotation class KMathContext /** * Marker interface for any algebra */ -interface Algebra +interface Algebra -inline operator fun , R> T.invoke(block: T.() -> R): R = run(block) +inline operator fun T.invoke(block: T.() -> R): R = run(block) /** * Space-like operations without neutral element */ -interface SpaceOperations : Algebra { +interface SpaceOperations : Algebra { /** * Addition operation for two context elements */ diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt index 1e0453f08..4e8dbf36d 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt @@ -1,13 +1,4 @@ package scientifik.kmath.operations -fun Space.sum(data: Iterable): T = data.fold(zero) { left, right -> add(left, right) } -fun Space.sum(data: Sequence): T = data.fold(zero) { left, right -> add(left, right) } - -//TODO optimized power operation -fun RingOperations.power(arg: T, power: Int): T { - var res = arg - repeat(power - 1) { - res *= arg - } - return res -} \ No newline at end of file +fun Space.sum(data : Iterable): T = data.fold(zero) { left, right -> add(left,right) } +fun Space.sum(data : Sequence): T = data.fold(zero) { left, right -> add(left, right) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt index bd83932e7..2a77e36ef 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt @@ -29,7 +29,7 @@ fun >> ctg(arg: T): T = arg.conte /** * A context extension to include power operations like square roots, etc */ -interface PowerOperations : Algebra { +interface PowerOperations { fun power(arg: T, pow: Number): T fun sqrt(arg: T) = power(arg, 0.5) @@ -42,7 +42,7 @@ fun >> sqr(arg: T): T = arg pow 2.0 /* Exponential */ -interface ExponentialOperations: Algebra { +interface ExponentialOperations { fun exp(arg: T): T fun ln(arg: T): T } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt index f02fd8dd0..c63384fb9 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -73,8 +73,6 @@ fun Buffer.asSequence(): Sequence = Sequence(::iterator) fun Buffer.asIterable(): Iterable = asSequence().asIterable() -val Buffer<*>.indices: IntRange get() = IntRange(0, size - 1) - interface MutableBuffer : Buffer { operator fun set(index: Int, value: T) diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt index 3437644ff..370dc646e 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt @@ -2,6 +2,7 @@ package scientifik.kmath.structures import scientifik.kmath.operations.* + interface ExtendedNDField> : NDField, TrigonometricOperations, 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 7d1209963..de13c9888 100644 --- a/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt @@ -1,13 +1,26 @@ package scientifik.kmath.linear import scientifik.kmath.structures.Matrix -import scientifik.kmath.structures.NDStructure -import scientifik.kmath.structures.as2D import kotlin.test.Test import kotlin.test.assertEquals class MatrixTest { + @Test + fun testSum() { + val vector1 = RealVector(5) { it.toDouble() } + val vector2 = RealVector(5) { 5 - it.toDouble() } + val sum = vector1 + vector2 + assertEquals(5.0, sum[2]) + } + + @Test + fun testVectorToMatrix() { + val vector = RealVector(5) { it.toDouble() } + val matrix = vector.asMatrix() + assertEquals(4.0, matrix[4, 0]) + } + @Test fun testTranspose() { val matrix = MatrixContext.real.one(3, 3) @@ -15,6 +28,21 @@ class MatrixTest { assertEquals(matrix, transposed) } + + @Test + fun testDot() { + val vector1 = RealVector(5) { it.toDouble() } + val vector2 = RealVector(5) { 5 - it.toDouble() } + + val matrix1 = vector1.asMatrix() + val matrix2 = vector2.asMatrix().transpose() + val product = MatrixContext.real.run { matrix1 dot matrix2 } + + + assertEquals(5.0, product[1, 0]) + assertEquals(6.0, product[2, 2]) + } + @Test fun testBuilder() { val matrix = Matrix.build(2, 3)( @@ -46,20 +74,4 @@ class MatrixTest { val toTenthPower = transitionMatrix pow 10 } - - @Test - fun test2DDot() { - val firstMatrix = NDStructure.auto(2,3){ (i, j) -> (i + j).toDouble() }.as2D() - val secondMatrix = NDStructure.auto(3,2){ (i, j) -> (i + j).toDouble() }.as2D() - MatrixContext.real.run { -// 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]) - } - } } \ No newline at end of file diff --git a/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumers.kt b/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumbers.kt similarity index 100% rename from kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumers.kt rename to kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/BigNumbers.kt diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts deleted file mode 100644 index 50fb41391..000000000 --- a/kmath-dimensions/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("scientifik.mpp") -} - -description = "A proof of concept module for adding typ-safe dimensions to structures" - -kotlin.sourceSets { - commonMain { - dependencies { - implementation(kotlin("reflect")) - api(project(":kmath-core")) - } - } -} \ No newline at end of file diff --git a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Dimensions.kt b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Dimensions.kt deleted file mode 100644 index 2eef69a0c..000000000 --- a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Dimensions.kt +++ /dev/null @@ -1,37 +0,0 @@ -package scientifik.kmath.dimensions - -/** - * An interface which is not used in runtime. Designates a size of some structure. - * All descendants should be singleton objects. - */ -interface Dimension { - val dim: UInt - - companion object { - @Suppress("NOTHING_TO_INLINE") - inline fun of(dim: UInt): Dimension { - return when (dim) { - 1u -> D1 - 2u -> D2 - 3u -> D3 - else -> object : Dimension { - override val dim: UInt = dim - } - } - } - } -} - -expect inline fun Dimension.Companion.dim(): UInt - -object D1 : Dimension { - override val dim: UInt = 1u -} - -object D2 : Dimension { - override val dim: UInt = 2u -} - -object D3 : Dimension { - override val dim: UInt = 3u -} \ No newline at end of file diff --git a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt deleted file mode 100644 index c78018753..000000000 --- a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt +++ /dev/null @@ -1,154 +0,0 @@ -package scientifik.kmath.dimensions - -import scientifik.kmath.linear.GenericMatrixContext -import scientifik.kmath.linear.MatrixContext -import scientifik.kmath.linear.Point -import scientifik.kmath.linear.transpose -import scientifik.kmath.operations.Ring -import scientifik.kmath.structures.Matrix -import scientifik.kmath.structures.Structure2D - -/** - * A matrix with compile-time controlled dimension - */ -interface DMatrix : Structure2D { - companion object { - /** - * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed - */ - inline fun coerce(structure: Structure2D): DMatrix { - if (structure.rowNum != Dimension.dim().toInt()) { - error("Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}") - } - if (structure.colNum != Dimension.dim().toInt()) { - error("Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}") - } - return DMatrixWrapper(structure) - } - - /** - * The same as [coerce] but without dimension checks. Use with caution - */ - inline fun coerceUnsafe(structure: Structure2D): DMatrix { - return DMatrixWrapper(structure) - } - } -} - -/** - * An inline wrapper for a Matrix - */ -inline class DMatrixWrapper( - val structure: Structure2D -) : DMatrix { - override val shape: IntArray get() = structure.shape - override fun get(i: Int, j: Int): T = structure[i, j] -} - -/** - * Dimension-safe point - */ -interface DPoint : Point { - companion object { - inline fun coerce(point: Point): DPoint { - if (point.size != Dimension.dim().toInt()) { - error("Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}") - } - return DPointWrapper(point) - } - - inline fun coerceUnsafe(point: Point): DPoint { - return DPointWrapper(point) - } - } -} - -/** - * Dimension-safe point wrapper - */ -inline class DPointWrapper(val point: Point) : - DPoint { - override val size: Int get() = point.size - - override fun get(index: Int): T = point[index] - - override fun iterator(): Iterator = point.iterator() -} - - -/** - * Basic operations on dimension-safe matrices. Operates on [Matrix] - */ -inline class DMatrixContext>(val context: GenericMatrixContext) { - - inline fun Matrix.coerce(): DMatrix = - DMatrix.coerceUnsafe(this) - - /** - * Produce a matrix with this context and given dimensions - */ - inline fun produce(noinline initializer: (i: Int, j: Int) -> T): DMatrix { - val rows = Dimension.dim() - val cols = Dimension.dim() - return context.produce(rows.toInt(), cols.toInt(), initializer).coerce() - } - - inline fun point(noinline initializer: (Int) -> T): DPoint { - val size = Dimension.dim() - return DPoint.coerceUnsafe( - context.point( - size.toInt(), - initializer - ) - ) - } - - inline infix fun DMatrix.dot( - other: DMatrix - ): DMatrix { - return context.run { this@dot dot other }.coerce() - } - - inline infix fun DMatrix.dot(vector: DPoint): DPoint { - return DPoint.coerceUnsafe(context.run { this@dot dot vector }) - } - - inline operator fun DMatrix.times(value: T): DMatrix { - return context.run { this@times.times(value) }.coerce() - } - - inline operator fun T.times(m: DMatrix): DMatrix = - m * this - - - inline operator fun DMatrix.plus(other: DMatrix): DMatrix { - return context.run { this@plus + other }.coerce() - } - - inline operator fun DMatrix.minus(other: DMatrix): DMatrix { - return context.run { this@minus + other }.coerce() - } - - inline operator fun DMatrix.unaryMinus(): DMatrix { - return context.run { this@unaryMinus.unaryMinus() }.coerce() - } - - inline fun DMatrix.transpose(): DMatrix { - return context.run { (this@transpose as Matrix).transpose() }.coerce() - } - - /** - * A square unit matrix - */ - inline fun one(): DMatrix = produce { i, j -> - if (i == j) context.elementContext.one else context.elementContext.zero - } - - inline fun zero(): DMatrix = produce { _, _ -> - context.elementContext.zero - } - - companion object { - val real = DMatrixContext(MatrixContext.real) - } -} \ No newline at end of file diff --git a/kmath-dimensions/src/jsMain/kotlin/scientifik/kmath/dimensions/dim.kt b/kmath-dimensions/src/jsMain/kotlin/scientifik/kmath/dimensions/dim.kt deleted file mode 100644 index 557234d84..000000000 --- a/kmath-dimensions/src/jsMain/kotlin/scientifik/kmath/dimensions/dim.kt +++ /dev/null @@ -1,5 +0,0 @@ -package scientifik.kmath.dimensions - -actual inline fun Dimension.Companion.dim(): UInt { - TODO("KClass::objectInstance does not work") -} \ No newline at end of file diff --git a/kmath-dimensions/src/jvmMain/kotlin/scientifik/kmath/dimensions/dim.kt b/kmath-dimensions/src/jvmMain/kotlin/scientifik/kmath/dimensions/dim.kt deleted file mode 100644 index a16dd2266..000000000 --- a/kmath-dimensions/src/jvmMain/kotlin/scientifik/kmath/dimensions/dim.kt +++ /dev/null @@ -1,4 +0,0 @@ -package scientifik.kmath.dimensions - -actual inline fun Dimension.Companion.dim(): UInt = - D::class.objectInstance?.dim ?: error("Dimension object must be a singleton") \ No newline at end of file diff --git a/kmath-dimensions/src/jvmTest/kotlin/scientifik/kmath/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/jvmTest/kotlin/scientifik/kmath/dimensions/DMatrixContextTest.kt deleted file mode 100644 index 8d4bae810..000000000 --- a/kmath-dimensions/src/jvmTest/kotlin/scientifik/kmath/dimensions/DMatrixContextTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package scientifik.kmath.dimensions - -import kotlin.test.Test - - -class DMatrixContextTest { - @Test - fun testDimensionSafeMatrix() { - val res = DMatrixContext.real.run { - val m = produce { i, j -> (i + j).toDouble() } - - //The dimension of `one()` is inferred from type - (m + one()) - } - } - - @Test - fun testTypeCheck() { - val res = DMatrixContext.real.run { - val m1 = produce { i, j -> (i + j).toDouble() } - val m2 = produce { i, j -> (i + j).toDouble() } - - //Dimension-safe addition - m1.transpose() + m2 - } - } -} \ No newline at end of file diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts deleted file mode 100644 index a8a8975bc..000000000 --- a/kmath-for-real/build.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - id("scientifik.mpp") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } - } -} \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/DoubleMatrixOperations.kt b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/DoubleMatrixOperations.kt deleted file mode 100644 index d9c6b5eab..000000000 --- a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/DoubleMatrixOperations.kt +++ /dev/null @@ -1,146 +0,0 @@ -package scientifik.kmath.real - -import scientifik.kmath.linear.MatrixContext -import scientifik.kmath.linear.RealMatrixContext.elementContext -import scientifik.kmath.linear.VirtualMatrix -import scientifik.kmath.operations.sum -import scientifik.kmath.structures.Buffer -import scientifik.kmath.structures.Matrix -import scientifik.kmath.structures.asSequence -import kotlin.math.pow - -/* - * Functions for convenient "numpy-like" operations with Double matrices. - * - * Initial implementation of these functions is taken from: - * https://github.com/thomasnield/numky/blob/master/src/main/kotlin/org/nield/numky/linear/DoubleOperators.kt - * - */ - -/* - * Functions that help create a real (Double) matrix - */ - -fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double) = - MatrixContext.real.produce(rowNum, colNum, initializer) - -fun Sequence.toMatrix() = toList().let { - MatrixContext.real.produce(it.size, it[0].size) { row, col -> it[row][col] } -} - -fun Matrix.repeatStackVertical(n: Int) = VirtualMatrix(rowNum*n, colNum) { - row, col -> get(if (row == 0) 0 else row % rowNum, col) -} - -/* - * Operations for matrix and real number - */ - -operator fun Matrix.times(double: Double) = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row, col] * double -} - -operator fun Matrix.plus(double: Double) = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row, col] + double -} - -operator fun Matrix.minus(double: Double) = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row, col] - double -} - -operator fun Matrix.div(double: Double) = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row, col] / double -} - -operator fun Double.times(matrix: Matrix) = MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { - row, col -> this * matrix[row, col] -} - -operator fun Double.plus(matrix: Matrix) = MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { - row, col -> this * matrix[row, col] -} - -operator fun Double.minus(matrix: Matrix) = MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { - row, col -> this - matrix[row, col] -} - -// TODO: does this operation make sense? Should it be 'this/matrix[row, col]'? -//operator fun Double.div(matrix: Matrix) = MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { -// row, col -> matrix[row, col] / this -//} - -/* - * Per-element (!) square and power operations - */ - -fun Matrix.square() = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row, col].pow(2) -} - -fun Matrix.pow(n: Int) = MatrixContext.real.produce(rowNum, colNum) { - i, j -> this[i, j].pow(n) -} - -/* - * Operations on two matrices (per-element!) - */ - -operator fun Matrix.times(other: Matrix) = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row, col] * other[row, col] -} - -operator fun Matrix.plus(other: Matrix) = MatrixContext.real.add(this, other) - -operator fun Matrix.minus(other: Matrix) = MatrixContext.real.produce(rowNum, colNum) { - row, col -> this[row,col] - other[row,col] -} - -/* - * Operations on columns - */ - -inline fun Matrix.appendColumn(crossinline mapper: (Buffer) -> Double) = - MatrixContext.real.produce(rowNum,colNum+1) { - row, col -> - if (col < colNum) - this[row, col] - else - mapper(rows[row]) - } - -fun Matrix.extractColumns(columnRange: IntRange) = MatrixContext.real.produce(rowNum, columnRange.count()) { - row, col -> this[row, columnRange.first + col] -} - -fun Matrix.extractColumn(columnIndex: Int) = extractColumns(columnIndex..columnIndex) - -fun Matrix.sumByColumn() = MatrixContext.real.produce(1, colNum) { _, j -> - val column = columns[j] - with(elementContext) { - sum(column.asSequence()) - } -} - -fun Matrix.minByColumn() = MatrixContext.real.produce(1, colNum) { - _, j -> columns[j].asSequence().min() ?: throw Exception("Cannot produce min on empty column") -} - -fun Matrix.maxByColumn() = MatrixContext.real.produce(1, colNum) { - _, j -> columns[j].asSequence().max() ?: throw Exception("Cannot produce min on empty column") -} - -fun Matrix.averageByColumn() = MatrixContext.real.produce(1, colNum) { - _, j -> columns[j].asSequence().average() -} - -/* - * Operations processing all elements - */ - -fun Matrix.sum() = elements().map { (_, value) -> value }.sum() - -fun Matrix.min() = elements().map { (_, value) -> value }.min() - -fun Matrix.max() = elements().map { (_, value) -> value }.max() - -fun Matrix.average() = elements().map { (_, value) -> value }.average() diff --git a/kmath-for-real/src/commonTest/kotlin/scientific.kmath.real/RealMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/scientific.kmath.real/RealMatrixTest.kt deleted file mode 100644 index 808794442..000000000 --- a/kmath-for-real/src/commonTest/kotlin/scientific.kmath.real/RealMatrixTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -package scientific.kmath.real - -import scientifik.kmath.real.average -import scientifik.kmath.real.realMatrix -import scientifik.kmath.real.sum -import kotlin.test.Test -import kotlin.test.assertEquals - -class RealMatrixTest { - @Test - fun testSum() { - val m = realMatrix(10, 10) { i, j -> (i + j).toDouble() } - assertEquals(m.sum(), 900.0) - assertEquals(m.average(), 9.0) - } -} diff --git a/kmath-for-real/src/commonTest/kotlin/scientifik/kmath/linear/VectorTest.kt b/kmath-for-real/src/commonTest/kotlin/scientifik/kmath/linear/VectorTest.kt deleted file mode 100644 index 0e73ee4a5..000000000 --- a/kmath-for-real/src/commonTest/kotlin/scientifik/kmath/linear/VectorTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package scientifik.kmath.linear - -import kotlin.test.Test -import kotlin.test.assertEquals - -class VectorTest { - @Test - fun testSum() { - val vector1 = RealVector(5) { it.toDouble() } - val vector2 = RealVector(5) { 5 - it.toDouble() } - val sum = vector1 + vector2 - assertEquals(5.0, sum[2]) - } - - @Test - fun testVectorToMatrix() { - val vector = RealVector(5) { it.toDouble() } - val matrix = vector.asMatrix() - assertEquals(4.0, matrix[4, 0]) - } - - @Test - fun testDot() { - val vector1 = RealVector(5) { it.toDouble() } - val vector2 = RealVector(5) { 5 - it.toDouble() } - - val matrix1 = vector1.asMatrix() - val matrix2 = vector2.asMatrix().transpose() - val product = MatrixContext.real.run { matrix1 dot matrix2 } - - - assertEquals(5.0, product[1, 0]) - assertEquals(6.0, product[2, 2]) - } - -} \ No newline at end of file diff --git a/kmath-for-real/src/jvmMain/kotlin/.gitkeep b/kmath-for-real/src/jvmMain/kotlin/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts deleted file mode 100644 index 4c158a32e..000000000 --- a/kmath-functions/build.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - id("scientifik.mpp") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } - } -} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt deleted file mode 100644 index 16f8aa12b..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt +++ /dev/null @@ -1,57 +0,0 @@ -package scientifik.kmath.functions - -import scientifik.kmath.operations.Ring - -interface Piecewise { - fun findPiece(arg: T): R? -} - -interface PiecewisePolynomial : - Piecewise> - -/** - * Ordered list of pieces in piecewise function - */ -class OrderedPiecewisePolynomial>(delimeter: T) : - PiecewisePolynomial { - - private val delimiters: ArrayList = arrayListOf(delimeter) - private val pieces: ArrayList> = ArrayList() - - /** - * Dynamically add a piece to the "right" side (beyond maximum argument value of previous piece) - * @param right new rightmost position. If is less then current rightmost position, a error is thrown. - */ - fun putRight(right: T, piece: Polynomial) { - require(right > delimiters.last()) { "New delimiter should be to the right of old one" } - delimiters.add(right) - pieces.add(piece) - } - - fun putLeft(left: T, piece: Polynomial) { - require(left < delimiters.first()) { "New delimiter should be to the left of old one" } - delimiters.add(0, left) - pieces.add(0, piece) - } - - override fun findPiece(arg: T): Polynomial? { - if (arg < delimiters.first() || arg >= delimiters.last()) { - return null - } else { - for (index in 1 until delimiters.size) { - if (arg < delimiters[index]) { - return pieces[index - 1] - } - } - error("Piece not found") - } - } -} - -/** - * Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise definition. - */ -fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = - findPiece(arg)?.value(ring, arg) - -fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt deleted file mode 100644 index b747b521d..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt +++ /dev/null @@ -1,73 +0,0 @@ -package scientifik.kmath.functions - -import scientifik.kmath.operations.Ring -import scientifik.kmath.operations.Space -import kotlin.math.max -import kotlin.math.pow - -/** - * Polynomial coefficients without fixation on specific context they are applied to - * @param coefficients constant is the leftmost coefficient - */ -inline class Polynomial(val coefficients: List) { - constructor(vararg coefficients: T) : this(coefficients.toList()) -} - -fun Polynomial.value() = - coefficients.reduceIndexed { index: Int, acc: Double, d: Double -> acc + d.pow(index) } - - -fun > Polynomial.value(ring: C, arg: T): T = ring.run { - if (coefficients.isEmpty()) return@run zero - var res = coefficients.first() - var powerArg = arg - for (index in 1 until coefficients.size) { - res += coefficients[index] * powerArg - //recalculating power on each step to avoid power costs on long polynomials - powerArg *= arg - } - return@run res -} - -/** - * Represent a polynomial as a context-dependent function - */ -fun > Polynomial.asMathFunction(): MathFunction = object : - MathFunction { - override fun C.invoke(arg: T): T = value(this, arg) -} - -/** - * Represent the polynomial as a regular context-less function - */ -fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - -/** - * An algebra for polynomials - */ -class PolynomialSpace>(val ring: C) : Space> { - - override fun add(a: Polynomial, b: Polynomial): Polynomial { - val dim = max(a.coefficients.size, b.coefficients.size) - ring.run { - return Polynomial(List(dim) { index -> - a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero } - }) - } - } - - override fun multiply(a: Polynomial, k: Number): Polynomial { - ring.run { - return Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * k }) - } - } - - override val zero: Polynomial = - Polynomial(emptyList()) - - operator fun Polynomial.invoke(arg: T): T = value(ring, arg) -} - -fun , R> C.polynomial(block: PolynomialSpace.() -> R): R { - return PolynomialSpace(this).run(block) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/functions.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/functions.kt deleted file mode 100644 index 2b822b3ba..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/functions.kt +++ /dev/null @@ -1,33 +0,0 @@ -package scientifik.kmath.functions - -import scientifik.kmath.operations.Algebra -import scientifik.kmath.operations.RealField - -/** - * A regular function that could be called only inside specific algebra context - * @param T source type - * @param C source algebra constraint - * @param R result type - */ -interface MathFunction, R> { - operator fun C.invoke(arg: T): R -} - -fun MathFunction.invoke(arg: Double): R = RealField.invoke(arg) - -/** - * A suspendable function defined in algebraic context - */ -interface SuspendableMathFunction, R> { - suspend operator fun C.invoke(arg: T): R -} - -suspend fun SuspendableMathFunction.invoke(arg: Double) = RealField.invoke(arg) - - -/** - * A parametric function with parameter - */ -interface ParametricFunction> { - operator fun C.invoke(arg: T, parameter: P): T -} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt deleted file mode 100644 index 8d83e4198..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt +++ /dev/null @@ -1,45 +0,0 @@ -package scientifik.kmath.interpolation - -import scientifik.kmath.functions.PiecewisePolynomial -import scientifik.kmath.functions.value -import scientifik.kmath.operations.Ring -import scientifik.kmath.structures.Buffer -import scientifik.kmath.structures.asBuffer - -interface Interpolator { - fun interpolate(points: XYPointSet): (X) -> Y -} - -interface PolynomialInterpolator> : Interpolator { - val algebra: Ring - - fun getDefaultValue(): T = error("Out of bounds") - - fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial - - override fun interpolate(points: XYPointSet): (T) -> T = { x -> - interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() - } -} - -fun > PolynomialInterpolator.interpolatePolynomials( - x: Buffer, - y: Buffer -): PiecewisePolynomial { - val pointSet = BufferXYPointSet(x, y) - return interpolatePolynomials(pointSet) -} - -fun > PolynomialInterpolator.interpolatePolynomials( - data: Map -): PiecewisePolynomial { - val pointSet = BufferXYPointSet(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) - return interpolatePolynomials(pointSet) -} - -fun > PolynomialInterpolator.interpolatePolynomials( - data: List> -): PiecewisePolynomial { - val pointSet = BufferXYPointSet(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) - return interpolatePolynomials(pointSet) -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt deleted file mode 100644 index 98beb4391..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt +++ /dev/null @@ -1,26 +0,0 @@ -package scientifik.kmath.interpolation - -import scientifik.kmath.functions.OrderedPiecewisePolynomial -import scientifik.kmath.functions.PiecewisePolynomial -import scientifik.kmath.functions.Polynomial -import scientifik.kmath.operations.Field - -/** - * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java - */ -class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - - override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra.run { - require(points.size > 0) { "Point array should not be empty" } - insureSorted(points) - - OrderedPiecewisePolynomial(points.x[0]).apply { - for (i in 0 until points.size - 1) { - val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) - val const = points.y[i] - slope * points.x[i] - val polynomial = Polynomial(const, slope) - putRight(points.x[i + 1], polynomial) - } - } - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LoessInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LoessInterpolator.kt deleted file mode 100644 index 6707bd8bc..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LoessInterpolator.kt +++ /dev/null @@ -1,296 +0,0 @@ -package scientifik.kmath.interpolation -// -//import scientifik.kmath.functions.PiecewisePolynomial -//import scientifik.kmath.operations.Ring -//import scientifik.kmath.structures.Buffer -//import kotlin.math.abs -//import kotlin.math.sqrt -// -// -///** -// * Original code: https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/LoessInterpolator.java -// */ -//class LoessInterpolator>(override val algebra: Ring) : PolynomialInterpolator { -// /** -// * The bandwidth parameter: when computing the loess fit at -// * a particular point, this fraction of source points closest -// * to the current point is taken into account for computing -// * a least-squares regression. -// * -// * -// * A sensible value is usually 0.25 to 0.5. -// */ -// private var bandwidth = 0.0 -// -// /** -// * The number of robustness iterations parameter: this many -// * robustness iterations are done. -// * -// * -// * A sensible value is usually 0 (just the initial fit without any -// * robustness iterations) to 4. -// */ -// private var robustnessIters = 0 -// -// /** -// * If the median residual at a certain robustness iteration -// * is less than this amount, no more iterations are done. -// */ -// private var accuracy = 0.0 -// -// /** -// * Constructs a new [LoessInterpolator] -// * with a bandwidth of [.DEFAULT_BANDWIDTH], -// * [.DEFAULT_ROBUSTNESS_ITERS] robustness iterations -// * and an accuracy of {#link #DEFAULT_ACCURACY}. -// * See [.LoessInterpolator] for an explanation of -// * the parameters. -// */ -// fun LoessInterpolator() { -// bandwidth = DEFAULT_BANDWIDTH -// robustnessIters = DEFAULT_ROBUSTNESS_ITERS -// accuracy = DEFAULT_ACCURACY -// } -// -// fun LoessInterpolator(bandwidth: Double, robustnessIters: Int) { -// this(bandwidth, robustnessIters, DEFAULT_ACCURACY) -// } -// -// fun LoessInterpolator(bandwidth: Double, robustnessIters: Int, accuracy: Double) { -// if (bandwidth < 0 || -// bandwidth > 1 -// ) { -// throw OutOfRangeException(LocalizedFormats.BANDWIDTH, bandwidth, 0, 1) -// } -// this.bandwidth = bandwidth -// if (robustnessIters < 0) { -// throw NotPositiveException(LocalizedFormats.ROBUSTNESS_ITERATIONS, robustnessIters) -// } -// this.robustnessIters = robustnessIters -// this.accuracy = accuracy -// } -// -// fun interpolate( -// xval: DoubleArray, -// yval: DoubleArray -// ): PolynomialSplineFunction { -// return SplineInterpolator().interpolate(xval, smooth(xval, yval)) -// } -// -// fun XYZPointSet.smooth(): XYPointSet { -// checkAllFiniteReal(x) -// checkAllFiniteReal(y) -// checkAllFiniteReal(z) -// MathArrays.checkOrder(xval) -// if (size == 1) { -// return doubleArrayOf(y[0]) -// } -// if (size == 2) { -// return doubleArrayOf(y[0], y[1]) -// } -// val bandwidthInPoints = (bandwidth * size).toInt() -// if (bandwidthInPoints < 2) { -// throw NumberIsTooSmallException( -// LocalizedFormats.BANDWIDTH, -// bandwidthInPoints, 2, true -// ) -// } -// val res = DoubleArray(size) -// val residuals = DoubleArray(size) -// val sortedResiduals = DoubleArray(size) -// val robustnessWeights = DoubleArray(size) -// // Do an initial fit and 'robustnessIters' robustness iterations. -// // This is equivalent to doing 'robustnessIters+1' robustness iterations -// // starting with all robustness weights set to 1. -// Arrays.fill(robustnessWeights, 1.0) -// for (iter in 0..robustnessIters) { -// val bandwidthInterval = intArrayOf(0, bandwidthInPoints - 1) -// // At each x, compute a local weighted linear regression -// for (i in 0 until size) { -//// val x = x[i] -// // Find out the interval of source points on which -// // a regression is to be made. -// if (i > 0) { -// updateBandwidthInterval(x, z, i, bandwidthInterval) -// } -// val ileft = bandwidthInterval[0] -// val iright = bandwidthInterval[1] -// // Compute the point of the bandwidth interval that is -// // farthest from x -// val edge: Int -// edge = if (x[i] - x[ileft] > x[iright] - x[i]) { -// ileft -// } else { -// iright -// } -// // Compute a least-squares linear fit weighted by -// // the product of robustness weights and the tricube -// // weight function. -// // See http://en.wikipedia.org/wiki/Linear_regression -// // (section "Univariate linear case") -// // and http://en.wikipedia.org/wiki/Weighted_least_squares -// // (section "Weighted least squares") -// var sumWeights = 0.0 -// var sumX = 0.0 -// var sumXSquared = 0.0 -// var sumY = 0.0 -// var sumXY = 0.0 -// val denom: Double = abs(1.0 / (x[edge] - x[i])) -// for (k in ileft..iright) { -// val xk = x[k] -// val yk = y[k] -// val dist = if (k < i) x - xk else xk - x[i] -// val w = tricube(dist * denom) * robustnessWeights[k] * z[k] -// val xkw = xk * w -// sumWeights += w -// sumX += xkw -// sumXSquared += xk * xkw -// sumY += yk * w -// sumXY += yk * xkw -// } -// val meanX = sumX / sumWeights -// val meanY = sumY / sumWeights -// val meanXY = sumXY / sumWeights -// val meanXSquared = sumXSquared / sumWeights -// val beta: Double -// beta = if (sqrt(abs(meanXSquared - meanX * meanX)) < accuracy) { -// 0.0 -// } else { -// (meanXY - meanX * meanY) / (meanXSquared - meanX * meanX) -// } -// val alpha = meanY - beta * meanX -// res[i] = beta * x[i] + alpha -// residuals[i] = abs(y[i] - res[i]) -// } -// // No need to recompute the robustness weights at the last -// // iteration, they won't be needed anymore -// if (iter == robustnessIters) { -// break -// } -// // Recompute the robustness weights. -// // Find the median residual. -// // An arraycopy and a sort are completely tractable here, -// // because the preceding loop is a lot more expensive -// java.lang.System.arraycopy(residuals, 0, sortedResiduals, 0, size) -// Arrays.sort(sortedResiduals) -// val medianResidual = sortedResiduals[size / 2] -// if (abs(medianResidual) < accuracy) { -// break -// } -// for (i in 0 until size) { -// val arg = residuals[i] / (6 * medianResidual) -// if (arg >= 1) { -// robustnessWeights[i] = 0.0 -// } else { -// val w = 1 - arg * arg -// robustnessWeights[i] = w * w -// } -// } -// } -// return res -// } -// -// fun smooth(xval: DoubleArray, yval: DoubleArray): DoubleArray { -// if (xval.size != yval.size) { -// throw DimensionMismatchException(xval.size, yval.size) -// } -// val unitWeights = DoubleArray(xval.size) -// Arrays.fill(unitWeights, 1.0) -// return smooth(xval, yval, unitWeights) -// } -// -// /** -// * Given an index interval into xval that embraces a certain number of -// * points closest to `xval[i-1]`, update the interval so that it -// * embraces the same number of points closest to `xval[i]`, -// * ignoring zero weights. -// * -// * @param xval Arguments array. -// * @param weights Weights array. -// * @param i Index around which the new interval should be computed. -// * @param bandwidthInterval a two-element array {left, right} such that: -// * `(left==0 or xval[i] - xval[left-1] > xval[right] - xval[i])` -// * and -// * `(right==xval.length-1 or xval[right+1] - xval[i] > xval[i] - xval[left])`. -// * The array will be updated. -// */ -// private fun updateBandwidthInterval( -// xval: Buffer, weights: Buffer, -// i: Int, -// bandwidthInterval: IntArray -// ) { -// val left = bandwidthInterval[0] -// val right = bandwidthInterval[1] -// // The right edge should be adjusted if the next point to the right -// // is closer to xval[i] than the leftmost point of the current interval -// val nextRight = nextNonzero(weights, right) -// if (nextRight < xval.size && xval[nextRight] - xval[i] < xval[i] - xval[left]) { -// val nextLeft = nextNonzero(weights, bandwidthInterval[0]) -// bandwidthInterval[0] = nextLeft -// bandwidthInterval[1] = nextRight -// } -// } -// -// /** -// * Return the smallest index `j` such that -// * `j > i && (j == weights.length || weights[j] != 0)`. -// * -// * @param weights Weights array. -// * @param i Index from which to start search. -// * @return the smallest compliant index. -// */ -// private fun nextNonzero(weights: Buffer, i: Int): Int { -// var j = i + 1 -// while (j < weights.size && weights[j] == 0.0) { -// ++j -// } -// return j -// } -// -// /** -// * Compute the -// * [tricube](http://en.wikipedia.org/wiki/Local_regression#Weight_function) -// * weight function -// * -// * @param x Argument. -// * @return `(1 - |x|3)3` for |x| < 1, 0 otherwise. -// */ -// private fun tricube(x: Double): Double { -// val absX: Double = FastMath.abs(x) -// if (absX >= 1.0) { -// return 0.0 -// } -// val tmp = 1 - absX * absX * absX -// return tmp * tmp * tmp -// } -// -// /** -// * Check that all elements of an array are finite real numbers. -// * -// * @param values Values array. -// * @throws org.apache.commons.math4.exception.NotFiniteNumberException -// * if one of the values is not a finite real number. -// */ -// private fun checkAllFiniteReal(values: DoubleArray) { -// for (i in values.indices) { -// MathUtils.checkFinite(values[i]) -// } -// } -// -// override fun interpolatePolynomials(points: Collection>): PiecewisePolynomial { -// TODO("not implemented") //To change body of created functions use File | Settings | File Templates. -// } -// -// companion object { -// /** Default value of the bandwidth parameter. */ -// const val DEFAULT_BANDWIDTH = 0.3 -// -// /** Default value of the number of robustness iterations. */ -// const val DEFAULT_ROBUSTNESS_ITERS = 2 -// -// /** -// * Default value for accuracy. -// */ -// const val DEFAULT_ACCURACY = 1e-12 -// } -//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt deleted file mode 100644 index e1af0c1a2..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt +++ /dev/null @@ -1,58 +0,0 @@ -package scientifik.kmath.interpolation - -import scientifik.kmath.functions.OrderedPiecewisePolynomial -import scientifik.kmath.functions.PiecewisePolynomial -import scientifik.kmath.functions.Polynomial -import scientifik.kmath.operations.Field -import scientifik.kmath.structures.MutableBufferFactory - -/** - * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type specific ones. - * Based on https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java - */ -class SplineInterpolator>( - override val algebra: Field, - val bufferFactory: MutableBufferFactory -) : PolynomialInterpolator { - - //TODO possibly optimize zeroed buffers - - override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra.run { - if (points.size < 3) { - error("Can't use spline interpolator with less than 3 points") - } - insureSorted(points) - - // Number of intervals. The number of data points is n + 1. - val n = points.size - 1 - // Differences between knot points - val h = bufferFactory(points.size) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(points.size - 1) { zero } - val z = bufferFactory(points.size) { zero } - - for (i in 1 until n) { - val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] - mu[i] = h[i] / g - z[i] = - (3.0 * (points.y[i + 1] * h[i - 1] - points.x[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) / (h[i - 1] * h[i]) - - h[i - 1] * z[i - 1]) / g - } - - // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - - OrderedPiecewisePolynomial(points.x[points.size - 1]).apply { - var cOld = zero - for (j in n - 1 downTo 0) { - val c = z[j] - mu[j] * cOld - val a = points.y[j] - val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 - val d = (cOld - c) / (3.0 * h[j]) - val polynomial = Polynomial(a, b, c, d) - cOld = c - putLeft(points.x[j], polynomial) - } - } - - } - -} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt deleted file mode 100644 index d8e10b880..000000000 --- a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt +++ /dev/null @@ -1,54 +0,0 @@ -package scientifik.kmath.interpolation - -import scientifik.kmath.structures.Buffer -import scientifik.kmath.structures.Structure2D - -interface XYPointSet { - val size: Int - val x: Buffer - val y: Buffer -} - -interface XYZPointSet : XYPointSet { - val z: Buffer -} - -internal fun > insureSorted(points: XYPointSet) { - for (i in 0 until points.size - 1) { - if (points.x[i + 1] <= points.x[i]) error("Input data is not sorted at index $i") - } -} - -class NDStructureColumn(val structure: Structure2D, val column: Int) : Buffer { - init { - require(column < structure.colNum) { "Column index is outside of structure column range" } - } - - override val size: Int get() = structure.rowNum - - override fun get(index: Int): T = structure[index, column] - - override fun iterator(): Iterator = sequence { - repeat(size) { - yield(get(it)) - } - }.iterator() -} - -class BufferXYPointSet(override val x: Buffer, override val y: Buffer) : XYPointSet { - init { - require(x.size == y.size) { "Sizes of x and y buffers should be the same" } - } - - override val size: Int - get() = x.size -} - -fun Structure2D.asXYPointSet(): XYPointSet { - require(shape[1] == 2) { "Structure second dimension should be of size 2" } - return object : XYPointSet { - override val size: Int get() = this@asXYPointSet.shape[0] - override val x: Buffer get() = NDStructureColumn(this@asXYPointSet, 0) - override val y: Buffer get() = NDStructureColumn(this@asXYPointSet, 1) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt deleted file mode 100644 index 23acd835c..000000000 --- a/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package scientifik.kmath.interpolation - -import scientifik.kmath.functions.PiecewisePolynomial -import scientifik.kmath.functions.asFunction -import scientifik.kmath.operations.RealField -import kotlin.test.Test -import kotlin.test.assertEquals - - -class LinearInterpolatorTest { - @Test - fun testInterpolation() { - val data = listOf( - 0.0 to 0.0, - 1.0 to 1.0, - 2.0 to 3.0, - 3.0 to 4.0 - ) - val polynomial: PiecewisePolynomial = LinearInterpolator(RealField).interpolatePolynomials(data) - val function = polynomial.asFunction(RealField) - - assertEquals(null, function(-1.0)) - assertEquals(0.5, function(0.5)) - assertEquals(2.0, function(1.5)) - assertEquals(3.0, function(2.0)) - } -} \ No newline at end of file diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 993bfed8e..39aa833ad 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -5,6 +5,5 @@ plugins { kotlin.sourceSets.commonMain { dependencies { api(project(":kmath-core")) - api(project(":kmath-for-real")) } } \ No newline at end of file diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt index df2e9847a..30a87228a 100644 --- a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt @@ -1,10 +1,6 @@ package scientifik.memory import java.nio.ByteBuffer -import java.nio.channels.FileChannel -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption /** @@ -15,7 +11,7 @@ actual fun Memory.Companion.allocate(length: Int): Memory { return ByteBufferMemory(buffer) } -private class ByteBufferMemory( +class ByteBufferMemory( val buffer: ByteBuffer, val startOffset: Int = 0, override val size: Int = buffer.limit() @@ -94,13 +90,4 @@ private class ByteBufferMemory( } override fun writer(): MemoryWriter = writer -} - -/** - * Use direct memory-mapped buffer from file to read something and close it afterwards. - */ -fun Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R { - return FileChannel.open(this, StandardOpenOption.READ).use { - ByteBufferMemory(it.map(FileChannel.MapMode.READ_ONLY, position, size)).block() - } } \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt index 804aed089..1af2570b0 100644 --- a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt @@ -11,7 +11,6 @@ import scientifik.kmath.coroutines.mapParallel import scientifik.kmath.operations.* import scientifik.kmath.structures.Buffer import scientifik.kmath.structures.asIterable -import scientifik.kmath.structures.asSequence /** * A function, that transforms a buffer of random quantities to some resulting value @@ -84,9 +83,9 @@ class Mean(val space: Space) : ComposableStatistic, T> { /** * Non-composable median */ -class Median(private val comparator: Comparator) : Statistic { +class Median(comparator: Comparator) : Statistic { override suspend fun invoke(data: Buffer): T { - return data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct + return data.asIterable().toList()[data.size / 2] //TODO check if this is correct } companion object { diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts deleted file mode 100644 index 52ee7c497..000000000 --- a/kmath-viktor/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - id("scientifik.jvm") -} - -description = "Binding for https://github.com/JetBrains-Research/viktor" - -dependencies { - api(project(":kmath-core")) - api("org.jetbrains.bio:viktor:1.0.1") -} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt deleted file mode 100644 index 040eee951..000000000 --- a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt +++ /dev/null @@ -1,20 +0,0 @@ -package scientifik.kmath.viktor - -import org.jetbrains.bio.viktor.F64FlatArray -import scientifik.kmath.structures.MutableBuffer - -@Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") -inline class ViktorBuffer(val flatArray: F64FlatArray) : MutableBuffer { - override val size: Int get() = flatArray.size - - override inline fun get(index: Int): Double = flatArray[index] - override inline fun set(index: Int, value: Double) { - flatArray[index] = value - } - - override fun copy(): MutableBuffer { - return ViktorBuffer(flatArray.copy().flatten()) - } - - override fun iterator(): Iterator = flatArray.data.iterator() -} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt deleted file mode 100644 index 84e927721..000000000 --- a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt +++ /dev/null @@ -1,86 +0,0 @@ -package scientifik.kmath.viktor - -import org.jetbrains.bio.viktor.F64Array -import scientifik.kmath.operations.RealField -import scientifik.kmath.structures.DefaultStrides -import scientifik.kmath.structures.MutableNDStructure -import scientifik.kmath.structures.NDField - -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -inline class ViktorNDStructure(val f64Buffer: F64Array) : MutableNDStructure { - - override val shape: IntArray get() = f64Buffer.shape - - override inline fun get(index: IntArray): Double = f64Buffer.get(*index) - - override inline fun set(index: IntArray, value: Double) { - f64Buffer.set(*index, value = value) - } - - override fun elements(): Sequence> { - return DefaultStrides(shape).indices().map { it to get(it) } - } -} - -fun F64Array.asStructure(): ViktorNDStructure = ViktorNDStructure(this) - -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -class ViktorNDField(override val shape: IntArray) : NDField { - override val zero: ViktorNDStructure - get() = F64Array.full(init = 0.0, shape = *shape).asStructure() - override val one: ViktorNDStructure - get() = F64Array.full(init = 1.0, shape = *shape).asStructure() - - val strides = DefaultStrides(shape) - - override val elementContext: RealField get() = RealField - - override fun produce(initializer: RealField.(IntArray) -> Double): ViktorNDStructure = F64Array(*shape).apply { - this@ViktorNDField.strides.indices().forEach { index -> - set(value = RealField.initializer(index), indices = *index) - } - }.asStructure() - - override fun map(arg: ViktorNDStructure, transform: RealField.(Double) -> Double): ViktorNDStructure = - F64Array(*shape).apply { - this@ViktorNDField.strides.indices().forEach { index -> - set(value = RealField.transform(arg[index]), indices = *index) - } - }.asStructure() - - override fun mapIndexed( - arg: ViktorNDStructure, - transform: RealField.(index: IntArray, Double) -> Double - ): ViktorNDStructure = F64Array(*shape).apply { - this@ViktorNDField.strides.indices().forEach { index -> - set(value = RealField.transform(index, arg[index]), indices = *index) - } - }.asStructure() - - override fun combine( - a: ViktorNDStructure, - b: ViktorNDStructure, - transform: RealField.(Double, Double) -> Double - ): ViktorNDStructure = F64Array(*shape).apply { - this@ViktorNDField.strides.indices().forEach { index -> - set(value = RealField.transform(a[index], b[index]), indices = *index) - } - }.asStructure() - - override fun add(a: ViktorNDStructure, b: ViktorNDStructure): ViktorNDStructure { - return (a.f64Buffer + b.f64Buffer).asStructure() - } - - override fun multiply(a: ViktorNDStructure, k: Number): ViktorNDStructure = - (a.f64Buffer * k.toDouble()).asStructure() - - override inline fun ViktorNDStructure.plus(b: ViktorNDStructure): ViktorNDStructure = - (f64Buffer + b.f64Buffer).asStructure() - - override inline fun ViktorNDStructure.minus(b: ViktorNDStructure): ViktorNDStructure = - (f64Buffer - b.f64Buffer).asStructure() - - override inline fun ViktorNDStructure.times(k: Number): ViktorNDStructure = (f64Buffer * k.toDouble()).asStructure() - - override inline fun ViktorNDStructure.plus(arg: Double): ViktorNDStructure = (f64Buffer.plus(arg)).asStructure() -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 671db444a..f52edfac5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,10 +1,10 @@ pluginManagement { plugins { - id("scientifik.mpp") version "0.4.1" - id("scientifik.jvm") version "0.4.1" - id("scientifik.atomic") version "0.4.1" - id("scientifik.publish") version "0.4.1" + id("scientifik.mpp") version "0.2.5" + id("scientifik.jvm") version "0.2.5" + id("scientifik.atomic") version "0.2.5" + id("scientifik.publish") version "0.2.5" } repositories { @@ -13,14 +13,13 @@ pluginManagement { gradlePluginPortal() maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/mipt-npm/scientifik") - maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/kotlin/kotlinx") } resolutionStrategy { eachPlugin { when (requested.id.id) { - "scientifik.mpp", "scientifik.jvm", "scientifik.publish" -> useModule("scientifik:gradle-tools:${requested.version}") + "scientifik.mpp", "scientifik.publish" -> useModule("scientifik:gradle-tools:${requested.version}") } } } @@ -30,16 +29,12 @@ rootProject.name = "kmath" include( ":kmath-memory", ":kmath-core", - ":kmath-functions", // ":kmath-io", ":kmath-coroutines", ":kmath-histograms", ":kmath-commons", - ":kmath-viktor", ":kmath-koma", ":kmath-prob", ":kmath-io", - ":kmath-dimensions", - ":kmath-for-real", ":examples" )