Drop koma support, add more explicit visibility modifiers
This commit is contained in:
parent
8ae9a071ef
commit
fc5ec8fed7
@ -54,9 +54,6 @@ can be used for a wide variety of purposes from high performance calculations to
|
||||
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.
|
||||
|
||||
* **Koma wrapper** [Koma](https://github.com/kyonifer/koma) is a well established numerics library in Kotlin, specifically linear algebra.
|
||||
The plan is to have wrappers for koma implementations for compatibility with kmath API.
|
||||
|
||||
## Planned features
|
||||
|
||||
* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks.
|
||||
|
@ -12,6 +12,3 @@ api and multiple library back-ends.
|
||||
* [Expressions](./expressions.md)
|
||||
|
||||
* Commons math integration
|
||||
|
||||
* Koma integration
|
||||
|
||||
|
@ -10,7 +10,6 @@ plugins {
|
||||
allOpen.annotation("org.openjdk.jmh.annotations.State")
|
||||
|
||||
repositories {
|
||||
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/kotlin/kotlin-dev/")
|
||||
@ -25,10 +24,8 @@ dependencies {
|
||||
implementation(project(":kmath-coroutines"))
|
||||
implementation(project(":kmath-commons"))
|
||||
implementation(project(":kmath-prob"))
|
||||
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-20")
|
||||
"benchmarksCompile"(sourceSets.main.get().output + sourceSets.main.get().compileClasspath) //sourceSets.main.output + sourceSets.main.runtimeClasspath
|
||||
|
@ -5,44 +5,33 @@ import org.openjdk.jmh.annotations.Scope
|
||||
import org.openjdk.jmh.annotations.State
|
||||
import java.nio.IntBuffer
|
||||
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
class ArrayBenchmark {
|
||||
|
||||
@Benchmark
|
||||
fun benchmarkArrayRead() {
|
||||
var res = 0
|
||||
for (i in 1..size) {
|
||||
res += array[size - i]
|
||||
}
|
||||
for (i in 1..size) res += array[size - i]
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun benchmarkBufferRead() {
|
||||
var res = 0
|
||||
for (i in 1..size) {
|
||||
res += arrayBuffer.get(size - i)
|
||||
}
|
||||
for (i in 1..size) res += arrayBuffer.get(size - i)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
fun nativeBufferRead() {
|
||||
var res = 0
|
||||
for (i in 1..size) {
|
||||
res += nativeBuffer.get(size - i)
|
||||
}
|
||||
for (i in 1..size) res += nativeBuffer.get(size - i)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val size = 1000
|
||||
|
||||
val array = IntArray(size) { it }
|
||||
val arrayBuffer = IntBuffer.wrap(array)
|
||||
val nativeBuffer = IntBuffer.allocate(size).also {
|
||||
for (i in 0 until size) {
|
||||
it.put(i, i)
|
||||
}
|
||||
const val size: Int = 1000
|
||||
val array: IntArray = IntArray(size) { it }
|
||||
val arrayBuffer: IntBuffer = IntBuffer.wrap(array)
|
||||
|
||||
val nativeBuffer: IntBuffer = IntBuffer.allocate(size).also {
|
||||
for (i in 0 until size) it.put(i, i)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +1,70 @@
|
||||
package scientifik.kmath.ast
|
||||
|
||||
import scientifik.kmath.asm.compile
|
||||
import scientifik.kmath.expressions.Expression
|
||||
import scientifik.kmath.expressions.expressionInField
|
||||
import scientifik.kmath.expressions.invoke
|
||||
import scientifik.kmath.operations.Field
|
||||
import scientifik.kmath.operations.RealField
|
||||
import kotlin.random.Random
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
class ExpressionsInterpretersBenchmark {
|
||||
private val algebra: Field<Double> = RealField
|
||||
fun functionalExpression() {
|
||||
val expr = algebra.expressionInField {
|
||||
variable("x") * const(2.0) + const(2.0) / variable("x") - const(16.0)
|
||||
}
|
||||
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
fun mstExpression() {
|
||||
val expr = algebra.mstInField {
|
||||
symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
|
||||
}
|
||||
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
fun asmExpression() {
|
||||
val expr = algebra.mstInField {
|
||||
symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
|
||||
}.compile()
|
||||
|
||||
invokeAndSum(expr)
|
||||
}
|
||||
|
||||
private fun invokeAndSum(expr: Expression<Double>) {
|
||||
val random = Random(0)
|
||||
var sum = 0.0
|
||||
|
||||
repeat(1000000) {
|
||||
sum += expr("x" to random.nextDouble())
|
||||
}
|
||||
|
||||
println(sum)
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val benchmark = ExpressionsInterpretersBenchmark()
|
||||
|
||||
val fe = measureTimeMillis {
|
||||
benchmark.functionalExpression()
|
||||
}
|
||||
|
||||
println("fe=$fe")
|
||||
|
||||
val mst = measureTimeMillis {
|
||||
benchmark.mstExpression()
|
||||
}
|
||||
|
||||
println("mst=$mst")
|
||||
|
||||
val asm = measureTimeMillis {
|
||||
benchmark.asmExpression()
|
||||
}
|
||||
|
||||
println("asm=$asm")
|
||||
}
|
||||
//package scientifik.kmath.ast
|
||||
//
|
||||
//import scientifik.kmath.asm.compile
|
||||
//import scientifik.kmath.expressions.Expression
|
||||
//import scientifik.kmath.expressions.expressionInField
|
||||
//import scientifik.kmath.expressions.invoke
|
||||
//import scientifik.kmath.operations.Field
|
||||
//import scientifik.kmath.operations.RealField
|
||||
//import kotlin.random.Random
|
||||
//import kotlin.system.measureTimeMillis
|
||||
//
|
||||
//class ExpressionsInterpretersBenchmark {
|
||||
// private val algebra: Field<Double> = RealField
|
||||
// fun functionalExpression() {
|
||||
// val expr = algebra.expressionInField {
|
||||
// variable("x") * const(2.0) + const(2.0) / variable("x") - const(16.0)
|
||||
// }
|
||||
//
|
||||
// invokeAndSum(expr)
|
||||
// }
|
||||
//
|
||||
// fun mstExpression() {
|
||||
// val expr = algebra.mstInField {
|
||||
// symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
|
||||
// }
|
||||
//
|
||||
// invokeAndSum(expr)
|
||||
// }
|
||||
//
|
||||
// fun asmExpression() {
|
||||
// val expr = algebra.mstInField {
|
||||
// symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
|
||||
// }.compile()
|
||||
//
|
||||
// invokeAndSum(expr)
|
||||
// }
|
||||
//
|
||||
// private fun invokeAndSum(expr: Expression<Double>) {
|
||||
// val random = Random(0)
|
||||
// var sum = 0.0
|
||||
//
|
||||
// repeat(1000000) {
|
||||
// sum += expr("x" to random.nextDouble())
|
||||
// }
|
||||
//
|
||||
// println(sum)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//fun main() {
|
||||
// val benchmark = ExpressionsInterpretersBenchmark()
|
||||
//
|
||||
// val fe = measureTimeMillis {
|
||||
// benchmark.functionalExpression()
|
||||
// }
|
||||
//
|
||||
// println("fe=$fe")
|
||||
//
|
||||
// val mst = measureTimeMillis {
|
||||
// benchmark.mstExpression()
|
||||
// }
|
||||
//
|
||||
// println("mst=$mst")
|
||||
//
|
||||
// val asm = measureTimeMillis {
|
||||
// benchmark.asmExpression()
|
||||
// }
|
||||
//
|
||||
// println("asm=$asm")
|
||||
//}
|
||||
|
@ -1,55 +0,0 @@
|
||||
package scientifik.kmath.linear
|
||||
|
||||
import koma.matrix.ejml.EJMLMatrixFactory
|
||||
import scientifik.kmath.commons.linear.CMMatrixContext
|
||||
import scientifik.kmath.commons.linear.inverse
|
||||
import scientifik.kmath.commons.linear.toCM
|
||||
import scientifik.kmath.operations.RealField
|
||||
import scientifik.kmath.operations.invoke
|
||||
import scientifik.kmath.structures.Matrix
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.random.Random
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@ExperimentalContracts
|
||||
fun main() {
|
||||
val random = Random(1224)
|
||||
val dim = 100
|
||||
//creating invertible matrix
|
||||
val u = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val l = Matrix.real(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
||||
val matrix = l dot u
|
||||
|
||||
val n = 5000 // iterations
|
||||
|
||||
MatrixContext.real {
|
||||
repeat(50) { val res = inverse(matrix) }
|
||||
val inverseTime = measureTimeMillis { repeat(n) { val res = inverse(matrix) } }
|
||||
println("[kmath] Inversion of $n matrices $dim x $dim finished in $inverseTime millis")
|
||||
}
|
||||
|
||||
//commons-math
|
||||
|
||||
val commonsTime = measureTimeMillis {
|
||||
CMMatrixContext {
|
||||
val cm = matrix.toCM() //avoid overhead on conversion
|
||||
repeat(n) { val res = inverse(cm) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
println("[commons-math] Inversion of $n matrices $dim x $dim finished in $commonsTime millis")
|
||||
|
||||
//koma-ejml
|
||||
|
||||
val komaTime = measureTimeMillis {
|
||||
(KomaMatrixContext(EJMLMatrixFactory(), RealField)) {
|
||||
val km = matrix.toKoma() //avoid overhead on conversion
|
||||
repeat(n) {
|
||||
val res = inverse(km)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println("[koma-ejml] Inversion of $n matrices $dim x $dim finished in $komaTime millis")
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package scientifik.kmath.linear
|
||||
|
||||
import koma.matrix.ejml.EJMLMatrixFactory
|
||||
import scientifik.kmath.commons.linear.CMMatrixContext
|
||||
import scientifik.kmath.commons.linear.toCM
|
||||
import scientifik.kmath.operations.RealField
|
||||
import scientifik.kmath.operations.invoke
|
||||
import scientifik.kmath.structures.Matrix
|
||||
import kotlin.random.Random
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
fun main() {
|
||||
val random = Random(12224)
|
||||
val dim = 1000
|
||||
//creating invertible matrix
|
||||
val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
val matrix2 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||
|
||||
// //warmup
|
||||
// matrix1 dot matrix2
|
||||
|
||||
CMMatrixContext {
|
||||
val cmMatrix1 = matrix1.toCM()
|
||||
val cmMatrix2 = matrix2.toCM()
|
||||
|
||||
val cmTime = measureTimeMillis {
|
||||
cmMatrix1 dot cmMatrix2
|
||||
}
|
||||
|
||||
println("CM implementation time: $cmTime")
|
||||
}
|
||||
|
||||
(KomaMatrixContext(EJMLMatrixFactory(), RealField)) {
|
||||
val komaMatrix1 = matrix1.toKoma()
|
||||
val komaMatrix2 = matrix2.toKoma()
|
||||
|
||||
val komaTime = measureTimeMillis {
|
||||
komaMatrix1 dot komaMatrix2
|
||||
}
|
||||
|
||||
println("Koma-ejml implementation time: $komaTime")
|
||||
}
|
||||
|
||||
val genericTime = measureTimeMillis {
|
||||
val res = matrix1 dot matrix2
|
||||
}
|
||||
|
||||
println("Generic implementation time: $genericTime")
|
||||
}
|
@ -5,6 +5,6 @@ dependencies {
|
||||
api(project(":kmath-core"))
|
||||
api(project(":kmath-coroutines"))
|
||||
api(project(":kmath-prob"))
|
||||
api(project(":kmath-functions"))
|
||||
// api(project(":kmath-functions"))
|
||||
api("org.apache.commons:commons-math3:3.6.1")
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ public interface Chain<out R> : Flow<R> {
|
||||
public companion object
|
||||
}
|
||||
|
||||
|
||||
public fun <T> Iterator<T>.asChain(): Chain<T> = SimpleChain { next() }
|
||||
public fun <T> Sequence<T>.asChain(): Chain<T> = iterator().asChain()
|
||||
|
||||
@ -51,22 +50,20 @@ public fun <T> Sequence<T>.asChain(): Chain<T> = iterator().asChain()
|
||||
* A simple chain of independent tokens
|
||||
*/
|
||||
public class SimpleChain<out R>(private val gen: suspend () -> R) : Chain<R> {
|
||||
override suspend fun next(): R = gen()
|
||||
override fun fork(): Chain<R> = this
|
||||
public override suspend fun next(): R = gen()
|
||||
public override fun fork(): Chain<R> = this
|
||||
}
|
||||
|
||||
/**
|
||||
* A stateless Markov chain
|
||||
*/
|
||||
public class MarkovChain<out R : Any>(private val seed: suspend () -> R, private val gen: suspend (R) -> R) : Chain<R> {
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
private val mutex: Mutex = Mutex()
|
||||
private var value: R? = null
|
||||
|
||||
public fun value(): R? = value
|
||||
|
||||
override suspend fun next(): R {
|
||||
public override suspend fun next(): R {
|
||||
mutex.withLock {
|
||||
val newValue = gen(value ?: seed())
|
||||
value = newValue
|
||||
@ -74,9 +71,7 @@ public class MarkovChain<out R : Any>(private val seed: suspend () -> R, private
|
||||
}
|
||||
}
|
||||
|
||||
override fun fork(): Chain<R> {
|
||||
return MarkovChain(seed = { value ?: seed() }, gen = gen)
|
||||
}
|
||||
public override fun fork(): Chain<R> = MarkovChain(seed = { value ?: seed() }, gen = gen)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,12 +86,11 @@ public class StatefulChain<S, out R>(
|
||||
private val gen: suspend S.(R) -> R
|
||||
) : Chain<R> {
|
||||
private val mutex: Mutex = Mutex()
|
||||
|
||||
private var value: R? = null
|
||||
|
||||
public fun value(): R? = value
|
||||
|
||||
override suspend fun next(): R {
|
||||
public override suspend fun next(): R {
|
||||
mutex.withLock {
|
||||
val newValue = state.gen(value ?: state.seed())
|
||||
value = newValue
|
||||
@ -104,16 +98,15 @@ public class StatefulChain<S, out R>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun fork(): Chain<R> = StatefulChain(forkState(state), seed, forkState, gen)
|
||||
public override fun fork(): Chain<R> = StatefulChain(forkState(state), seed, forkState, gen)
|
||||
}
|
||||
|
||||
/**
|
||||
* A chain that repeats the same value
|
||||
*/
|
||||
public class ConstantChain<out T>(public val value: T) : Chain<T> {
|
||||
override suspend fun next(): T = value
|
||||
|
||||
override fun fork(): Chain<T> = this
|
||||
public override suspend fun next(): T = value
|
||||
public override fun fork(): Chain<T> = this
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ public interface SuspendableMathFunction<T, C : Algebra<T>, R> {
|
||||
public suspend operator fun C.invoke(arg: T): R
|
||||
}
|
||||
|
||||
public suspend fun <R> SuspendableMathFunction<Double, RealField, R>.invoke(arg: Double) = RealField.invoke(arg)
|
||||
public suspend fun <R> SuspendableMathFunction<Double, RealField, R>.invoke(arg: Double): R = RealField.invoke(arg)
|
||||
|
||||
/**
|
||||
* A parametric function with parameter
|
||||
|
@ -29,7 +29,6 @@ public interface Histogram<T : Any, out B : Bin<T>> : Iterable<B> {
|
||||
* Dimension of the histogram
|
||||
*/
|
||||
public val dimension: Int
|
||||
|
||||
}
|
||||
|
||||
public interface MutableHistogram<T : Any, out B : Bin<T>> : Histogram<T, B> {
|
||||
|
@ -44,7 +44,7 @@ public class UnivariateHistogram private constructor(private val factory: (Doubl
|
||||
}
|
||||
|
||||
private fun createBin(value: Double): UnivariateBin = factory(value).also {
|
||||
synchronized(this) { bins.put(it.position, it) }
|
||||
synchronized(this) { bins[it.position] = it }
|
||||
}
|
||||
|
||||
public override operator fun get(point: Buffer<out Double>): UnivariateBin? = get(point[0])
|
||||
@ -87,7 +87,7 @@ public class UnivariateHistogram private constructor(private val factory: (Doubl
|
||||
)
|
||||
|
||||
else -> {
|
||||
val index = (0 until sorted.size).first { value > sorted[it] }
|
||||
val index = sorted.indices.first { value > sorted[it] }
|
||||
val left = sorted[index]
|
||||
val right = sorted[index + 1]
|
||||
UnivariateBin((left + right) / 2, (right - left))
|
||||
|
@ -1,30 +0,0 @@
|
||||
plugins { id("ru.mipt.npm.mpp") }
|
||||
|
||||
repositories.maven("http://dl.bintray.com/kyonifer/maven")
|
||||
|
||||
kotlin.sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api(project(":kmath-core"))
|
||||
api("com.kyonifer:koma-core-api-common:0.12")
|
||||
}
|
||||
}
|
||||
|
||||
jvmMain {
|
||||
dependencies {
|
||||
api("com.kyonifer:koma-core-api-jvm:0.12")
|
||||
}
|
||||
}
|
||||
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation("com.kyonifer:koma-core-ejml:0.12")
|
||||
}
|
||||
}
|
||||
|
||||
jsMain {
|
||||
dependencies {
|
||||
api("com.kyonifer:koma-core-api-js:0.12")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package scientifik.kmath.linear
|
||||
|
||||
import koma.extensions.fill
|
||||
import koma.matrix.MatrixFactory
|
||||
import scientifik.kmath.operations.Space
|
||||
import scientifik.kmath.operations.invoke
|
||||
import scientifik.kmath.structures.Matrix
|
||||
import scientifik.kmath.structures.NDStructure
|
||||
|
||||
public class KomaMatrixContext<T : Any>(
|
||||
private val factory: MatrixFactory<koma.matrix.Matrix<T>>,
|
||||
private val space: Space<T>
|
||||
) : MatrixContext<T> {
|
||||
public override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): KomaMatrix<T> =
|
||||
KomaMatrix(factory.zeros(rows, columns).fill(initializer))
|
||||
|
||||
public fun Matrix<T>.toKoma(): KomaMatrix<T> = if (this is KomaMatrix)
|
||||
this
|
||||
else
|
||||
produce(rowNum, colNum) { i, j -> get(i, j) }
|
||||
|
||||
public fun Point<T>.toKoma(): KomaVector<T> = if (this is KomaVector)
|
||||
this
|
||||
else
|
||||
KomaVector(factory.zeros(size, 1).fill { i, _ -> get(i) })
|
||||
|
||||
public override fun Matrix<T>.dot(other: Matrix<T>): KomaMatrix<T> =
|
||||
KomaMatrix(toKoma().origin * other.toKoma().origin)
|
||||
|
||||
public override fun Matrix<T>.dot(vector: Point<T>): KomaVector<T> =
|
||||
KomaVector(toKoma().origin * vector.toKoma().origin)
|
||||
|
||||
public override operator fun Matrix<T>.unaryMinus(): KomaMatrix<T> =
|
||||
KomaMatrix(toKoma().origin.unaryMinus())
|
||||
|
||||
public override fun add(a: Matrix<T>, b: Matrix<T>): KomaMatrix<T> =
|
||||
KomaMatrix(a.toKoma().origin + b.toKoma().origin)
|
||||
|
||||
public override operator fun Matrix<T>.minus(b: Matrix<T>): KomaMatrix<T> =
|
||||
KomaMatrix(toKoma().origin - b.toKoma().origin)
|
||||
|
||||
public override fun multiply(a: Matrix<T>, k: Number): Matrix<T> =
|
||||
produce(a.rowNum, a.colNum) { i, j -> space { a[i, j] * k } }
|
||||
|
||||
public override operator fun Matrix<T>.times(value: T): KomaMatrix<T> =
|
||||
KomaMatrix(toKoma().origin * value)
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
public fun <T : Any> KomaMatrixContext<T>.solve(a: Matrix<T>, b: Matrix<T>): KomaMatrix<T> =
|
||||
KomaMatrix(a.toKoma().origin.solve(b.toKoma().origin))
|
||||
|
||||
public fun <T : Any> KomaMatrixContext<T>.solve(a: Matrix<T>, b: Point<T>): KomaVector<T> =
|
||||
KomaVector(a.toKoma().origin.solve(b.toKoma().origin))
|
||||
|
||||
public fun <T : Any> KomaMatrixContext<T>.inverse(a: Matrix<T>): KomaMatrix<T> =
|
||||
KomaMatrix(a.toKoma().origin.inv())
|
||||
|
||||
public class KomaMatrix<T : Any>(public val origin: koma.matrix.Matrix<T>, features: Set<MatrixFeature>? = null) :
|
||||
FeaturedMatrix<T> {
|
||||
public override val rowNum: Int get() = origin.numRows()
|
||||
public override val colNum: Int get() = origin.numCols()
|
||||
|
||||
public override val shape: IntArray get() = intArrayOf(origin.numRows(), origin.numCols())
|
||||
|
||||
public override val features: Set<MatrixFeature> = features ?: hashSetOf(
|
||||
object : DeterminantFeature<T> {
|
||||
override val determinant: T get() = origin.det()
|
||||
},
|
||||
|
||||
object : LUPDecompositionFeature<T> {
|
||||
private val lup by lazy { origin.LU() }
|
||||
override val l: FeaturedMatrix<T> get() = KomaMatrix(lup.second)
|
||||
override val u: FeaturedMatrix<T> get() = KomaMatrix(lup.third)
|
||||
override val p: FeaturedMatrix<T> get() = KomaMatrix(lup.first)
|
||||
}
|
||||
)
|
||||
|
||||
override fun suggestFeature(vararg features: MatrixFeature): FeaturedMatrix<T> =
|
||||
KomaMatrix(this.origin, this.features + features)
|
||||
|
||||
override operator fun get(i: Int, j: Int): T = origin.getGeneric(i, j)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return NDStructure.equals(this, other as? NDStructure<*> ?: return false)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = origin.hashCode()
|
||||
result = 31 * result + features.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public class KomaVector<T : Any> internal constructor(public val origin: koma.matrix.Matrix<T>) : Point<T> {
|
||||
override val size: Int get() = origin.numRows()
|
||||
|
||||
init {
|
||||
require(origin.numCols() == 1) { error("Only single column matrices are allowed") }
|
||||
}
|
||||
|
||||
override operator fun get(index: Int): T = origin.getGeneric(index)
|
||||
override operator fun iterator(): Iterator<T> = origin.toIterable().iterator()
|
||||
}
|
@ -73,5 +73,5 @@ public fun <T : Any> Sampler<T>.sampleBuffer(
|
||||
/**
|
||||
* Generate a bunch of samples from real distributions
|
||||
*/
|
||||
public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int) =
|
||||
public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> =
|
||||
sampleBuffer(generator, size, Buffer.Companion::real)
|
||||
|
@ -6,42 +6,38 @@ import scientifik.kmath.chains.SimpleChain
|
||||
/**
|
||||
* A multivariate distribution which takes a map of parameters
|
||||
*/
|
||||
interface NamedDistribution<T> : Distribution<Map<String, T>>
|
||||
public interface NamedDistribution<T> : Distribution<Map<String, T>>
|
||||
|
||||
/**
|
||||
* A multivariate distribution that has independent distributions for separate axis
|
||||
*/
|
||||
class FactorizedDistribution<T>(val distributions: Collection<NamedDistribution<T>>) : NamedDistribution<T> {
|
||||
|
||||
override fun probability(arg: Map<String, T>): Double {
|
||||
return distributions.fold(1.0) { acc, distr -> acc * distr.probability(arg) }
|
||||
}
|
||||
public class FactorizedDistribution<T>(public val distributions: Collection<NamedDistribution<T>>) :
|
||||
NamedDistribution<T> {
|
||||
override fun probability(arg: Map<String, T>): Double =
|
||||
distributions.fold(1.0) { acc, distr -> acc * distr.probability(arg) }
|
||||
|
||||
override fun sample(generator: RandomGenerator): Chain<Map<String, T>> {
|
||||
val chains = distributions.map { it.sample(generator) }
|
||||
return SimpleChain<Map<String, T>> {
|
||||
chains.fold(emptyMap()) { acc, chain -> acc + chain.next() }
|
||||
}
|
||||
return SimpleChain { chains.fold(emptyMap()) { acc, chain -> acc + chain.next() } }
|
||||
}
|
||||
}
|
||||
|
||||
class NamedDistributionWrapper<T : Any>(val name: String, val distribution: Distribution<T>) : NamedDistribution<T> {
|
||||
public class NamedDistributionWrapper<T : Any>(public val name: String, public val distribution: Distribution<T>) :
|
||||
NamedDistribution<T> {
|
||||
override fun probability(arg: Map<String, T>): Double = distribution.probability(
|
||||
arg[name] ?: error("Argument with name $name not found in input parameters")
|
||||
)
|
||||
|
||||
override fun sample(generator: RandomGenerator): Chain<Map<String, T>> {
|
||||
val chain = distribution.sample(generator)
|
||||
return SimpleChain {
|
||||
mapOf(name to chain.next())
|
||||
}
|
||||
return SimpleChain { mapOf(name to chain.next()) }
|
||||
}
|
||||
}
|
||||
|
||||
class DistributionBuilder<T: Any>{
|
||||
public class DistributionBuilder<T : Any> {
|
||||
private val distributions = ArrayList<NamedDistribution<T>>()
|
||||
|
||||
infix fun String.to(distribution: Distribution<T>){
|
||||
distributions.add(NamedDistributionWrapper(this,distribution))
|
||||
public infix fun String.to(distribution: Distribution<T>) {
|
||||
distributions.add(NamedDistributionWrapper(this, distribution))
|
||||
}
|
||||
}
|
@ -5,10 +5,13 @@ import scientifik.kmath.chains.Chain
|
||||
/**
|
||||
* A possibly stateful chain producing random values.
|
||||
*/
|
||||
class RandomChain<out R>(val generator: RandomGenerator, private val gen: suspend RandomGenerator.() -> R) : Chain<R> {
|
||||
public class RandomChain<out R>(
|
||||
public val generator: RandomGenerator,
|
||||
private val gen: suspend RandomGenerator.() -> R
|
||||
) : Chain<R> {
|
||||
override suspend fun next(): R = generator.gen()
|
||||
|
||||
override fun fork(): Chain<R> = RandomChain(generator.fork(), gen)
|
||||
}
|
||||
|
||||
fun <R> RandomGenerator.chain(gen: suspend RandomGenerator.() -> R): RandomChain<R> = RandomChain(this, gen)
|
||||
public fun <R> RandomGenerator.chain(gen: suspend RandomGenerator.() -> R): RandomChain<R> = RandomChain(this, gen)
|
||||
|
@ -5,17 +5,15 @@ import kotlin.random.Random
|
||||
/**
|
||||
* A basic generator
|
||||
*/
|
||||
interface RandomGenerator {
|
||||
fun nextBoolean(): Boolean
|
||||
|
||||
fun nextDouble(): Double
|
||||
fun nextInt(): Int
|
||||
fun nextInt(until: Int): Int
|
||||
fun nextLong(): Long
|
||||
fun nextLong(until: Long): Long
|
||||
|
||||
fun fillBytes(array: ByteArray, fromIndex: Int = 0, toIndex: Int = array.size)
|
||||
fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) }
|
||||
public interface RandomGenerator {
|
||||
public fun nextBoolean(): Boolean
|
||||
public fun nextDouble(): Double
|
||||
public fun nextInt(): Int
|
||||
public fun nextInt(until: Int): Int
|
||||
public fun nextLong(): Long
|
||||
public fun nextLong(until: Long): Long
|
||||
public fun fillBytes(array: ByteArray, fromIndex: Int = 0, toIndex: Int = array.size)
|
||||
public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) }
|
||||
|
||||
/**
|
||||
* Create a new generator which is independent from current generator (operations on new generator do not affect this one
|
||||
@ -24,32 +22,27 @@ interface RandomGenerator {
|
||||
*
|
||||
* The thread safety of this operation is not guaranteed since it could affect the state of the generator.
|
||||
*/
|
||||
fun fork(): RandomGenerator
|
||||
public fun fork(): RandomGenerator
|
||||
|
||||
companion object {
|
||||
val default by lazy { DefaultGenerator() }
|
||||
public companion object {
|
||||
public val default: DefaultGenerator by lazy { DefaultGenerator() }
|
||||
|
||||
fun default(seed: Long) = DefaultGenerator(Random(seed))
|
||||
public fun default(seed: Long): DefaultGenerator = DefaultGenerator(Random(seed))
|
||||
}
|
||||
}
|
||||
|
||||
inline class DefaultGenerator(val random: Random = Random) : RandomGenerator {
|
||||
override fun nextBoolean(): Boolean = random.nextBoolean()
|
||||
public inline class DefaultGenerator(public val random: Random = Random) : RandomGenerator {
|
||||
public override fun nextBoolean(): Boolean = random.nextBoolean()
|
||||
public override fun nextDouble(): Double = random.nextDouble()
|
||||
public override fun nextInt(): Int = random.nextInt()
|
||||
public override fun nextInt(until: Int): Int = random.nextInt(until)
|
||||
public override fun nextLong(): Long = random.nextLong()
|
||||
public override fun nextLong(until: Long): Long = random.nextLong(until)
|
||||
|
||||
override fun nextDouble(): Double = random.nextDouble()
|
||||
|
||||
override fun nextInt(): Int = random.nextInt()
|
||||
override fun nextInt(until: Int): Int = random.nextInt(until)
|
||||
|
||||
override fun nextLong(): Long = random.nextLong()
|
||||
|
||||
override fun nextLong(until: Long): Long = random.nextLong(until)
|
||||
|
||||
override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) {
|
||||
public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) {
|
||||
random.nextBytes(array, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
override fun nextBytes(size: Int): ByteArray = random.nextBytes(size)
|
||||
|
||||
override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong())
|
||||
public override fun nextBytes(size: Int): ByteArray = random.nextBytes(size)
|
||||
public override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong())
|
||||
}
|
@ -7,26 +7,25 @@ import scientifik.kmath.chains.zip
|
||||
import scientifik.kmath.operations.Space
|
||||
import scientifik.kmath.operations.invoke
|
||||
|
||||
class BasicSampler<T : Any>(val chainBuilder: (RandomGenerator) -> Chain<T>) : Sampler<T> {
|
||||
override fun sample(generator: RandomGenerator): Chain<T> = chainBuilder(generator)
|
||||
public class BasicSampler<T : Any>(public val chainBuilder: (RandomGenerator) -> Chain<T>) : Sampler<T> {
|
||||
public override fun sample(generator: RandomGenerator): Chain<T> = chainBuilder(generator)
|
||||
}
|
||||
|
||||
class ConstantSampler<T : Any>(val value: T) : Sampler<T> {
|
||||
override fun sample(generator: RandomGenerator): Chain<T> = ConstantChain(value)
|
||||
public class ConstantSampler<T : Any>(public val value: T) : Sampler<T> {
|
||||
public override fun sample(generator: RandomGenerator): Chain<T> = ConstantChain(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* A space for samplers. Allows to perform simple operations on distributions
|
||||
*/
|
||||
class SamplerSpace<T : Any>(val space: Space<T>) : Space<Sampler<T>> {
|
||||
public class SamplerSpace<T : Any>(public val space: Space<T>) : Space<Sampler<T>> {
|
||||
public override val zero: Sampler<T> = ConstantSampler(space.zero)
|
||||
|
||||
override val zero: Sampler<T> = ConstantSampler(space.zero)
|
||||
|
||||
override fun add(a: Sampler<T>, b: Sampler<T>): Sampler<T> = BasicSampler { generator ->
|
||||
public override fun add(a: Sampler<T>, b: Sampler<T>): Sampler<T> = BasicSampler { generator ->
|
||||
a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> space { aValue + bValue } }
|
||||
}
|
||||
|
||||
override fun multiply(a: Sampler<T>, k: Number): Sampler<T> = BasicSampler { generator ->
|
||||
public override fun multiply(a: Sampler<T>, k: Number): Sampler<T> = BasicSampler { generator ->
|
||||
a.sample(generator).map { space { it * k.toDouble() } }
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.scanReduce
|
||||
import kotlinx.coroutines.flow.runningReduce
|
||||
import scientifik.kmath.coroutines.mapParallel
|
||||
import scientifik.kmath.operations.*
|
||||
import scientifik.kmath.structures.Buffer
|
||||
@ -16,8 +16,8 @@ import scientifik.kmath.structures.asSequence
|
||||
/**
|
||||
* A function, that transforms a buffer of random quantities to some resulting value
|
||||
*/
|
||||
interface Statistic<T, R> {
|
||||
suspend operator fun invoke(data: Buffer<T>): R
|
||||
public interface Statistic<T, R> {
|
||||
public suspend operator fun invoke(data: Buffer<T>): R
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,17 +26,17 @@ interface Statistic<T, R> {
|
||||
* @param I - intermediate block type
|
||||
* @param R - result type
|
||||
*/
|
||||
interface ComposableStatistic<T, I, R> : Statistic<T, R> {
|
||||
public interface ComposableStatistic<T, I, R> : Statistic<T, R> {
|
||||
//compute statistic on a single block
|
||||
suspend fun computeIntermediate(data: Buffer<T>): I
|
||||
public suspend fun computeIntermediate(data: Buffer<T>): I
|
||||
|
||||
//Compose two blocks
|
||||
suspend fun composeIntermediate(first: I, second: I): I
|
||||
public suspend fun composeIntermediate(first: I, second: I): I
|
||||
|
||||
//Transform block to result
|
||||
suspend fun toResult(intermediate: I): R
|
||||
public suspend fun toResult(intermediate: I): R
|
||||
|
||||
override suspend fun invoke(data: Buffer<T>): R = toResult(computeIntermediate(data))
|
||||
public override suspend fun invoke(data: Buffer<T>): R = toResult(computeIntermediate(data))
|
||||
}
|
||||
|
||||
@FlowPreview
|
||||
@ -46,7 +46,7 @@ private fun <T, I, R> ComposableStatistic<T, I, R>.flowIntermediate(
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.Default
|
||||
): Flow<I> = flow
|
||||
.mapParallel(dispatcher) { computeIntermediate(it) }
|
||||
.scanReduce(::composeIntermediate)
|
||||
.runningReduce(::composeIntermediate)
|
||||
|
||||
|
||||
/**
|
||||
@ -57,7 +57,7 @@ private fun <T, I, R> ComposableStatistic<T, I, R>.flowIntermediate(
|
||||
*/
|
||||
@FlowPreview
|
||||
@ExperimentalCoroutinesApi
|
||||
fun <T, I, R> ComposableStatistic<T, I, R>.flow(
|
||||
public fun <T, I, R> ComposableStatistic<T, I, R>.flow(
|
||||
flow: Flow<Buffer<T>>,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.Default
|
||||
): Flow<R> = flowIntermediate(flow, dispatcher).map(::toResult)
|
||||
@ -65,32 +65,32 @@ fun <T, I, R> ComposableStatistic<T, I, R>.flow(
|
||||
/**
|
||||
* Arithmetic mean
|
||||
*/
|
||||
class Mean<T>(val space: Space<T>) : ComposableStatistic<T, Pair<T, Int>, T> {
|
||||
override suspend fun computeIntermediate(data: Buffer<T>): Pair<T, Int> =
|
||||
public class Mean<T>(public val space: Space<T>) : ComposableStatistic<T, Pair<T, Int>, T> {
|
||||
public override suspend fun computeIntermediate(data: Buffer<T>): Pair<T, Int> =
|
||||
space { sum(data.asIterable()) } to data.size
|
||||
|
||||
override suspend fun composeIntermediate(first: Pair<T, Int>, second: Pair<T, Int>): Pair<T, Int> =
|
||||
public override suspend fun composeIntermediate(first: Pair<T, Int>, second: Pair<T, Int>): Pair<T, Int> =
|
||||
space { first.first + second.first } to (first.second + second.second)
|
||||
|
||||
override suspend fun toResult(intermediate: Pair<T, Int>): T =
|
||||
public override suspend fun toResult(intermediate: Pair<T, Int>): T =
|
||||
space { intermediate.first / intermediate.second }
|
||||
|
||||
companion object {
|
||||
public companion object {
|
||||
//TODO replace with optimized version which respects overflow
|
||||
val real: Mean<Double> = Mean(RealField)
|
||||
val int: Mean<Int> = Mean(IntRing)
|
||||
val long: Mean<Long> = Mean(LongRing)
|
||||
public val real: Mean<Double> = Mean(RealField)
|
||||
public val int: Mean<Int> = Mean(IntRing)
|
||||
public val long: Mean<Long> = Mean(LongRing)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-composable median
|
||||
*/
|
||||
class Median<T>(private val comparator: Comparator<T>) : Statistic<T, T> {
|
||||
override suspend fun invoke(data: Buffer<T>): T =
|
||||
public class Median<T>(private val comparator: Comparator<T>) : Statistic<T, T> {
|
||||
public override suspend fun invoke(data: Buffer<T>): T =
|
||||
data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct
|
||||
|
||||
companion object {
|
||||
val real: Median<Double> = Median(Comparator { a: Double, b: Double -> a.compareTo(b) })
|
||||
public companion object {
|
||||
public val real: Median<Double> = Median { a: Double, b: Double -> a.compareTo(b) }
|
||||
}
|
||||
}
|
||||
|
@ -3,32 +3,20 @@ package scientifik.kmath.prob
|
||||
import scientifik.kmath.chains.Chain
|
||||
import scientifik.kmath.chains.SimpleChain
|
||||
|
||||
class UniformDistribution(val range: ClosedFloatingPointRange<Double>) : UnivariateDistribution<Double> {
|
||||
public class UniformDistribution(public val range: ClosedFloatingPointRange<Double>) : UnivariateDistribution<Double> {
|
||||
private val length: Double = range.endInclusive - range.start
|
||||
|
||||
private val length = range.endInclusive - range.start
|
||||
override fun probability(arg: Double): Double = if (arg in range) 1.0 / length else 0.0
|
||||
|
||||
override fun probability(arg: Double): Double {
|
||||
return if (arg in range) {
|
||||
return 1.0 / length
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
override fun sample(generator: RandomGenerator): Chain<Double> =
|
||||
SimpleChain { range.start + generator.nextDouble() * length }
|
||||
|
||||
override fun sample(generator: RandomGenerator): Chain<Double> {
|
||||
return SimpleChain {
|
||||
range.start + generator.nextDouble() * length
|
||||
}
|
||||
}
|
||||
|
||||
override fun cumulative(arg: Double): Double {
|
||||
return when {
|
||||
override fun cumulative(arg: Double): Double = when {
|
||||
arg < range.start -> 0.0
|
||||
arg >= range.endInclusive -> 1.0
|
||||
else -> (arg - range.start) / length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Distribution.Companion.uniform(range: ClosedFloatingPointRange<Double>): UniformDistribution =
|
||||
public fun Distribution.Companion.uniform(range: ClosedFloatingPointRange<Double>): UniformDistribution =
|
||||
UniformDistribution(range)
|
@ -15,8 +15,8 @@ public abstract class ContinuousSamplerDistribution : Distribution<Double> {
|
||||
private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingRealChain() {
|
||||
private val sampler = buildCMSampler(generator)
|
||||
|
||||
public override fun nextDouble(): Double = sampler.sample()
|
||||
public override fun fork(): Chain<Double> = ContinuousSamplerChain(generator.fork())
|
||||
override fun nextDouble(): Double = sampler.sample()
|
||||
override fun fork(): Chain<Double> = ContinuousSamplerChain(generator.fork())
|
||||
}
|
||||
|
||||
protected abstract fun buildCMSampler(generator: RandomGenerator): ContinuousSampler
|
||||
@ -28,8 +28,8 @@ public abstract class DiscreteSamplerDistribution : Distribution<Int> {
|
||||
private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingIntChain() {
|
||||
private val sampler = buildSampler(generator)
|
||||
|
||||
public override fun nextInt(): Int = sampler.sample()
|
||||
public override fun fork(): Chain<Int> = ContinuousSamplerChain(generator.fork())
|
||||
override fun nextInt(): Int = sampler.sample()
|
||||
override fun fork(): Chain<Int> = ContinuousSamplerChain(generator.fork())
|
||||
}
|
||||
|
||||
protected abstract fun buildSampler(generator: RandomGenerator): DiscreteSampler
|
||||
@ -58,9 +58,7 @@ public fun Distribution.Companion.normal(
|
||||
return normalSampler(method, provider)
|
||||
}
|
||||
|
||||
override fun probability(arg: Double): Double {
|
||||
return exp(-arg.pow(2) / 2) / sqrt(PI * 2)
|
||||
}
|
||||
override fun probability(arg: Double): Double = exp(-arg.pow(2) / 2) / sqrt(PI * 2)
|
||||
}
|
||||
|
||||
public fun Distribution.Companion.normal(
|
||||
|
@ -26,14 +26,12 @@ rootProject.name = "kmath"
|
||||
include(
|
||||
":kmath-memory",
|
||||
":kmath-core",
|
||||
":kmath-functions",
|
||||
// ":kmath-functions",
|
||||
":kmath-coroutines",
|
||||
":kmath-histograms",
|
||||
":kmath-commons",
|
||||
":kmath-viktor",
|
||||
":kmath-koma",
|
||||
":kmath-prob",
|
||||
":kmath-io",
|
||||
":kmath-dimensions",
|
||||
":kmath-for-real",
|
||||
":kmath-geometry",
|
||||
|
Loading…
Reference in New Issue
Block a user