Implement Commons RNG-like samplers in kmath-prob module for Multiplatform #164

Merged
CommanderTvis merged 44 commits from feature/mp-samplers into dev 2021-03-31 09:25:44 +03:00
30 changed files with 234 additions and 262 deletions
Showing only changes of commit 9574099f9b - Show all commits

View File

@ -106,6 +106,7 @@ kotlin.sourceSets.all {
with(languageSettings) { with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
} }
} }

View File

@ -1,20 +1,22 @@
package kscience.kmath.commons.fit package space.kscience.kmath.commons.fit
import kotlinx.html.br import kotlinx.html.br
import kotlinx.html.h3 import kotlinx.html.h3
import kscience.kmath.commons.optimization.chiSquared
import kscience.kmath.commons.optimization.minimize
import kscience.kmath.expressions.symbol
import kscience.kmath.real.RealVector
import kscience.kmath.real.map
import kscience.kmath.real.step
import kscience.kmath.stat.*
import kscience.kmath.stat.distributions.NormalDistribution
import kscience.kmath.structures.asIterable
import kscience.kmath.structures.toList
import kscience.plotly.* import kscience.plotly.*
import kscience.plotly.models.ScatterMode import kscience.plotly.models.ScatterMode
import kscience.plotly.models.TraceValues import kscience.plotly.models.TraceValues
import space.kscience.kmath.commons.optimization.chiSquared
import space.kscience.kmath.commons.optimization.minimize
import space.kscience.kmath.misc.symbol
import space.kscience.kmath.optimization.FunctionOptimization
import space.kscience.kmath.optimization.OptimizationResult
import space.kscience.kmath.real.DoubleVector
import space.kscience.kmath.real.map
import space.kscience.kmath.real.step
import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.stat.distributions.NormalDistribution
import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.toList
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
@ -27,7 +29,7 @@ private val c by symbol
/** /**
* Shortcut to use buffers in plotly * Shortcut to use buffers in plotly
*/ */
operator fun TraceValues.invoke(vector: RealVector) { operator fun TraceValues.invoke(vector: DoubleVector) {
numbers = vector.asIterable() numbers = vector.asIterable()
} }
@ -58,12 +60,12 @@ suspend fun main() {
val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma) val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma)
// compute differentiable chi^2 sum for given model ax^2 + bx + c // compute differentiable chi^2 sum for given model ax^2 + bx + c
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 -> val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
//bind variables to autodiff context //bind variables to autodiff context
val a = bind(a) val a = bind(a)
val b = bind(b) val b = bind(b)
//Include default value for c if it is not provided as a parameter //Include default value for c if it is not provided as a parameter
val c = bindOrNull(c) ?: one val c = bindSymbolOrNull(c) ?: one
a * x1.pow(2) + b * x1 + c a * x1.pow(2) + b * x1 + c
} }
@ -90,10 +92,10 @@ suspend fun main() {
} }
} }
br() br()
h3{ h3 {
+"Fit result: $result" +"Fit result: $result"
} }
h3{ h3 {
+"Chi2/dof = ${result.value / (x.size - 3)}" +"Chi2/dof = ${result.value / (x.size - 3)}"
} }
} }

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat package space.kscience.kmath.stat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kscience.kmath.stat.samplers.GaussianSampler import space.kscience.kmath.stat.samplers.GaussianSampler
import org.apache.commons.rng.simple.RandomSource import org.apache.commons.rng.simple.RandomSource
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat package space.kscience.kmath.stat
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.chains.collectWithState import space.kscience.kmath.chains.collectWithState
import kscience.kmath.stat.distributions.NormalDistribution import space.kscience.kmath.stat.distributions.NormalDistribution
/** /**
* The state of distribution averager. * The state of distribution averager.

View File

@ -1,13 +1,13 @@
package kscience.kmath.commons.optimization package space.kscience.kmath.commons.optimization
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kscience.kmath.commons.expressions.DerivativeStructureExpression import space.kscience.kmath.commons.expressions.DerivativeStructureExpression
import kscience.kmath.expressions.symbol import space.kscience.kmath.misc.symbol
import kscience.kmath.stat.Fitting import space.kscience.kmath.optimization.FunctionOptimization
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.distributions.NormalDistribution import space.kscience.kmath.stat.distributions.NormalDistribution
import org.junit.jupiter.api.Test
import kotlin.math.pow import kotlin.math.pow
import kotlin.test.Test
internal class OptimizeTest { internal class OptimizeTest {
val x by symbol val x by symbol
@ -34,6 +34,7 @@ internal class OptimizeTest {
simplexSteps(x to 2.0, y to 0.5) simplexSteps(x to 2.0, y to 0.5)
//this sets simplex optimizer //this sets simplex optimizer
} }
println(result.point) println(result.point)
println(result.value) println(result.value)
} }
@ -43,15 +44,20 @@ internal class OptimizeTest {
val a by symbol val a by symbol
val b by symbol val b by symbol
val c by symbol val c by symbol
val sigma = 1.0 val sigma = 1.0
val generator = NormalDistribution(0.0, sigma) val generator = NormalDistribution(0.0, sigma)
val chain = generator.sample(RandomGenerator.default(112667)) val chain = generator.sample(RandomGenerator.default(112667))
val x = (1..100).map(Int::toDouble) val x = (1..100).map(Int::toDouble)
val y = x.map { it.pow(2) + it + 1.0 + chain.next() }
val y = x.map {
it.pow(2) + it + 1 + chain.next()
}
val yErr = List(x.size) { sigma } val yErr = List(x.size) { sigma }
val chi2 = Fitting.chiSquared(x, y, yErr) { x1 -> val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
val cWithDefault = bindOrNull(c) ?: one val cWithDefault = bindSymbolOrNull(c) ?: one
bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault bind(a) * x1.pow(2) + bind(b) * x1 + cWithDefault
} }
@ -59,5 +65,4 @@ internal class OptimizeTest {
println(result) println(result)
println("Chi2/dof = ${result.value / (x.size - 3)}") println("Chi2/dof = ${result.value / (x.size - 3)}")
} }
} }

View File

@ -1,4 +1,4 @@
package kscience.kmath.structures package space.kscience.kmath.structures
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -17,11 +17,13 @@ public typealias BufferFactory<T> = (Int, (Int) -> T) -> Buffer<T>
public typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T> public typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
/** /**
* A generic immutable random-access structure for both primitives and objects. * A generic read-only random-access structure for both primitives and objects.
*
* [Buffer] is in general identity-free. [Buffer.contentEquals] should be used for content equality checks.
* *
* @param T the type of elements contained in the buffer. * @param T the type of elements contained in the buffer.
*/ */
public interface Buffer<T> { public interface Buffer<out T> {
/** /**
* The size of this buffer. * The size of this buffer.
*/ */
@ -37,49 +39,45 @@ public interface Buffer<T> {
*/ */
public operator fun iterator(): Iterator<T> public operator fun iterator(): Iterator<T>
/**
* Checks content equality with another buffer.
*/
public fun contentEquals(other: Buffer<*>): Boolean =
asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
public companion object { public companion object {
/** /**
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified * Check the element-by-element match of content of two buffers.
* [initializer] function.
*/ */
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer = public fun <T: Any> contentEquals(first: Buffer<T>, second: Buffer<T>): Boolean{
RealBuffer(size) { initializer(it) } if (first.size != second.size) return false
for (i in first.indices) {
if (first[i] != second[i]) return false
}
return true
}
/** /**
* Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the * Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
* specified [initializer] function. * specified [initializer] function.
*/ */
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> = public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
ListBuffer(List(size, initializer)) List(size, initializer).asBuffer()
// TODO add resolution based on Annotation or companion resolution
/** /**
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer], * Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
* [RealBuffer], etc.), [ListBuffer] is returned otherwise. * [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
* *
* The [size] is specified, and each element is calculated by calling the specified [initializer] function. * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> = public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
when (type) { when (type) {
Double::class -> real(size) { initializer(it) as Double } as Buffer<T> Double::class -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer<T>
Short::class -> ShortBuffer(size) { initializer(it) as Short } as Buffer<T> Short::class -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
Int::class -> IntBuffer(size) { initializer(it) as Int } as Buffer<T> Int::class -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
Long::class -> LongBuffer(size) { initializer(it) as Long } as Buffer<T> Long::class -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
Float::class -> FloatBuffer(size) { initializer(it) as Float } as Buffer<T> Float::class -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
else -> boxing(size, initializer) else -> boxing(size, initializer)
} }
/** /**
* Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer], * Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer],
* [RealBuffer], etc.), [ListBuffer] is returned otherwise. * [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
* *
* The [size] is specified, and each element is calculated by calling the specified [initializer] function. * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/ */
@ -89,21 +87,6 @@ public interface Buffer<T> {
} }
} }
/**
* Creates a sequence that returns all elements from this [Buffer].
*/
public fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator)
/**
* Creates an iterable that returns all elements from this [Buffer].
*/
public fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator)
/**
* Converts this [Buffer] to a new [List]
*/
public fun <T> Buffer<T>.toList(): List<T> = asSequence().toList()
/** /**
* Returns an [IntRange] of the valid indices for this [Buffer]. * Returns an [IntRange] of the valid indices for this [Buffer].
*/ */
@ -126,6 +109,43 @@ public interface MutableBuffer<T> : Buffer<T> {
public fun copy(): MutableBuffer<T> public fun copy(): MutableBuffer<T>
public companion object { public companion object {
/**
* Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer =
DoubleBuffer(size, initializer)
/**
* Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer =
ShortBuffer(size, initializer)
/**
* Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer =
IntBuffer(size, initializer)
/**
* Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer =
LongBuffer(size, initializer)
/**
* Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer =
FloatBuffer(size, initializer)
/** /**
* Create a boxing mutable buffer of given type * Create a boxing mutable buffer of given type
*/ */
@ -134,37 +154,30 @@ public interface MutableBuffer<T> : Buffer<T> {
/** /**
* Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
* ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise. * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
* *
* The [size] is specified, and each element is calculated by calling the specified [initializer] function. * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> = public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
when (type) { when (type) {
Double::class -> RealBuffer(size) { initializer(it) as Double } as MutableBuffer<T> Double::class -> double(size) { initializer(it) as Double } as MutableBuffer<T>
Short::class -> ShortBuffer(size) { initializer(it) as Short } as MutableBuffer<T> Short::class -> short(size) { initializer(it) as Short } as MutableBuffer<T>
Int::class -> IntBuffer(size) { initializer(it) as Int } as MutableBuffer<T> Int::class -> int(size) { initializer(it) as Int } as MutableBuffer<T>
Float::class -> FloatBuffer(size) { initializer(it) as Float } as MutableBuffer<T> Float::class -> float(size) { initializer(it) as Float } as MutableBuffer<T>
Long::class -> LongBuffer(size) { initializer(it) as Long } as MutableBuffer<T> Long::class -> long(size) { initializer(it) as Long } as MutableBuffer<T>
else -> boxing(size, initializer) else -> boxing(size, initializer)
} }
/** /**
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
* ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise. * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise.
* *
* The [size] is specified, and each element is calculated by calling the specified [initializer] function. * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> = public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
auto(T::class, size, initializer) auto(T::class, size, initializer)
/**
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
RealBuffer(size) { initializer(it) }
} }
} }
@ -187,15 +200,6 @@ public inline class ListBuffer<T>(public val list: List<T>) : Buffer<T> {
*/ */
public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this) public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
/**
* Creates a new [ListBuffer] with the specified [size], where each element is calculated by calling the specified
* [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an array element given its index.
*/
public inline fun <T> ListBuffer(size: Int, init: (Int) -> T): ListBuffer<T> = List(size, init).asBuffer()
/** /**
* [MutableBuffer] implementation over [MutableList]. * [MutableBuffer] implementation over [MutableList].
* *
@ -216,16 +220,20 @@ public inline class MutableListBuffer<T>(public val list: MutableList<T>) : Muta
override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list)) override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list))
} }
/**
* Returns an [ListBuffer] that wraps the original list.
*/
public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
/** /**
* [MutableBuffer] implementation over [Array]. * [MutableBuffer] implementation over [Array].
* *
* @param T the type of elements contained in the buffer. * @param T the type of elements contained in the buffer.
* @property array The underlying array. * @property array The underlying array.
*/ */
public class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> { public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
// Can't inline because array is invariant // Can't inline because array is invariant
override val size: Int override val size: Int get() = array.size
get() = array.size
override operator fun get(index: Int): T = array[index] override operator fun get(index: Int): T = array[index]
@ -237,6 +245,7 @@ public class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> {
override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf()) override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf())
} }
/** /**
* Returns an [ArrayBuffer] that wraps the original array. * Returns an [ArrayBuffer] that wraps the original array.
*/ */
@ -269,27 +278,9 @@ public class VirtualBuffer<T>(override val size: Int, private val generator: (In
} }
override operator fun iterator(): Iterator<T> = (0 until size).asSequence().map(generator).iterator() override operator fun iterator(): Iterator<T> = (0 until size).asSequence().map(generator).iterator()
override fun contentEquals(other: Buffer<*>): Boolean {
return if (other is VirtualBuffer) {
this.size == other.size && this.generator == other.generator
} else {
super.contentEquals(other)
}
}
} }
/** /**
* Convert this buffer to read-only buffer. * Convert this buffer to read-only buffer.
*/ */
public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
/**
* Typealias for buffer transformations.
*/
public typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
/**
* Typealias for buffer transformations with suspend function.
*/
public typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>

View File

@ -1,9 +0,0 @@
package kscience.kmath.chains
/**
* Performance optimized chain for real values
*/
public interface BlockingRealChain : Chain<Double> {
public override suspend fun next(): Double
public suspend fun nextBlock(size: Int): DoubleArray = DoubleArray(size) { next() }
}

View File

@ -1,12 +1,13 @@
package space.kscience.kmath.chains package space.kscience.kmath.chains
/** /**
* Performance optimized chain for real values * Chunked, specialized chain for real values.
*/ */
public abstract class BlockingDoubleChain : Chain<Double> { public interface BlockingDoubleChain : Chain<Double> {
public abstract fun nextDouble(): Double public override suspend fun next(): Double
override suspend fun next(): Double = nextDouble() /**
* Returns an [DoubleArray] chunk of [size] values of [next].
public open fun nextBlock(size: Int): DoubleArray = DoubleArray(size) { nextDouble() } */
public suspend fun nextBlock(size: Int): DoubleArray = DoubleArray(size) { next() }
} }

View File

@ -1,4 +1,4 @@
package kscience.dimensions package space.kscience.dimensions
import space.kscience.kmath.dimensions.D2 import space.kscience.kmath.dimensions.D2
import space.kscience.kmath.dimensions.D3 import space.kscience.kmath.dimensions.D3

View File

@ -1,34 +0,0 @@
package kscience.kmath.stat
import kscience.kmath.chains.Chain
import kscience.kmath.chains.ConstantChain
import kscience.kmath.chains.map
import kscience.kmath.chains.zip
import kscience.kmath.operations.Space
import kscience.kmath.operations.invoke
/**
* Implements [Sampler] by sampling only certain [value].
*
* @property value the value to sample.
*/
public class ConstantSampler<T : Any>(public val value: T) : Sampler<T> {
public override fun sample(generator: RandomGenerator): Chain<T> = ConstantChain(value)
}
/**
* A space of samplers. Allows to perform simple operations on distributions.
*
* @property space the space to provide addition and scalar multiplication for [T].
*/
public class SamplerSpace<T : Any>(public val space: Space<T>) : Space<Sampler<T>> {
public override val zero: Sampler<T> = ConstantSampler(space.zero)
public override fun add(a: Sampler<T>, b: Sampler<T>): Sampler<T> = Sampler { generator ->
a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> space { aValue + bValue } }
}
public override fun multiply(a: Sampler<T>, k: Number): Sampler<T> = Sampler { generator ->
a.sample(generator).map { space { it * k.toDouble() } }
}
}

View File

@ -1,11 +1,12 @@
package kscience.kmath.stat package space.kscience.kmath.stat
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.chains.collect import space.kscience.kmath.chains.collect
import kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.BufferFactory
import kscience.kmath.structures.IntBuffer import space.kscience.kmath.structures.IntBuffer
import space.kscience.kmath.structures.MutableBuffer
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
/** /**
@ -22,7 +23,7 @@ public fun interface Sampler<T : Any> {
} }
/** /**
* A distribution of typed objects * A distribution of typed objects.
*/ */
public interface Distribution<T : Any> : Sampler<T> { public interface Distribution<T : Any> : Sampler<T> {
/** /**
@ -60,7 +61,7 @@ public fun <T : Comparable<T>> UnivariateDistribution<T>.integral(from: T, to: T
public fun <T : Any> Sampler<T>.sampleBuffer( public fun <T : Any> Sampler<T>.sampleBuffer(
generator: RandomGenerator, generator: RandomGenerator,
size: Int, size: Int,
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
): Chain<Buffer<T>> { ): Chain<Buffer<T>> {
require(size > 1) require(size > 1)
//creating temporary storage once //creating temporary storage once
@ -86,7 +87,7 @@ public suspend fun <T : Any> Sampler<T>.next(generator: RandomGenerator): T = sa
*/ */
@JvmName("sampleRealBuffer") @JvmName("sampleRealBuffer")
public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> = public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> =
sampleBuffer(generator, size, Buffer.Companion::real) sampleBuffer(generator, size, MutableBuffer.Companion::double)
/** /**
* Generates [size] integer samples and chunks them into some buffers. * Generates [size] integer samples and chunks them into some buffers.

View File

@ -1,8 +1,8 @@
package kscience.kmath.stat package space.kscience.kmath.stat
import kscience.kmath.chains.BlockingIntChain import space.kscience.kmath.chains.BlockingDoubleChain
import kscience.kmath.chains.BlockingRealChain import space.kscience.kmath.chains.BlockingIntChain
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
/** /**
* A possibly stateful chain producing random values. * A possibly stateful chain producing random values.
@ -18,5 +18,5 @@ public class RandomChain<out R>(
} }
public 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)
public fun Chain<Double>.blocking(): BlockingRealChain = object : Chain<Double> by this, BlockingRealChain {} public fun Chain<Double>.blocking(): BlockingDoubleChain = object : Chain<Double> by this, BlockingDoubleChain {}
public fun Chain<Int>.blocking(): BlockingIntChain = object : Chain<Int> by this, BlockingIntChain {} public fun Chain<Int>.blocking(): BlockingIntChain = object : Chain<Int> by this, BlockingIntChain {}

View File

@ -8,16 +8,28 @@ import space.kscience.kmath.operations.Group
import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
public class BasicSampler<T : Any>(public val chainBuilder: (RandomGenerator) -> Chain<T>) : Sampler<T> { /**
public override fun sample(generator: RandomGenerator): Chain<T> = chainBuilder(generator) * Implements [Sampler] by sampling only certain [value].
} *
* @property value the value to sample.
*/
public class ConstantSampler<T : Any>(public val value: T) : Sampler<T> { public class ConstantSampler<T : Any>(public val value: T) : Sampler<T> {
public override fun sample(generator: RandomGenerator): Chain<T> = ConstantChain(value) public override fun sample(generator: RandomGenerator): Chain<T> = ConstantChain(value)
} }
/** /**
* A space for samplers. Allows to perform simple operations on distributions * Implements [Sampler] by delegating sampling to value of [chainBuilder].
*
* @property chainBuilder the provider of [Chain].
*/
public class BasicSampler<T : Any>(public val chainBuilder: (RandomGenerator) -> Chain<T>) : Sampler<T> {
public override fun sample(generator: RandomGenerator): Chain<T> = chainBuilder(generator)
}
/**
* A space of samplers. Allows to perform simple operations on distributions.
*
* @property algebra the space to provide addition and scalar multiplication for [T].
*/ */
public class SamplerSpace<T : Any, S>(public val algebra: S) : Group<Sampler<T>>, public class SamplerSpace<T : Any, S>(public val algebra: S) : Group<Sampler<T>>,
ScaleOperations<Sampler<T>> where S : Group<T>, S : ScaleOperations<T> { ScaleOperations<Sampler<T>> where S : Group<T>, S : ScaleOperations<T> {
@ -29,8 +41,10 @@ public class SamplerSpace<T : Any, S>(public val algebra: S) : Group<Sampler<T>>
} }
public override fun scale(a: Sampler<T>, value: Double): Sampler<T> = BasicSampler { generator -> public override fun scale(a: Sampler<T>, value: Double): Sampler<T> = BasicSampler { generator ->
a.sample(generator).map { algebra { it * value } } a.sample(generator).map { a ->
algebra { a * value }
}
} }
override fun Sampler<T>.unaryMinus(): Sampler<T> = scale(this, -1.0) public override fun Sampler<T>.unaryMinus(): Sampler<T> = scale(this, -1.0)
} }

View File

@ -1,12 +1,12 @@
package kscience.kmath.stat.distributions package space.kscience.kmath.stat.distributions
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.UnivariateDistribution import space.kscience.kmath.stat.UnivariateDistribution
import kscience.kmath.stat.internal.InternalErf import space.kscience.kmath.stat.internal.InternalErf
import kscience.kmath.stat.samplers.GaussianSampler import space.kscience.kmath.stat.samplers.GaussianSampler
import kscience.kmath.stat.samplers.NormalizedGaussianSampler import space.kscience.kmath.stat.samplers.NormalizedGaussianSampler
import kscience.kmath.stat.samplers.ZigguratNormalizedGaussianSampler import space.kscience.kmath.stat.samplers.ZigguratNormalizedGaussianSampler
import kotlin.math.* import kotlin.math.*
/** /**

View File

@ -1,4 +1,4 @@
package kscience.kmath.stat.internal package space.kscience.kmath.stat.internal
import kotlin.math.abs import kotlin.math.abs

View File

@ -1,4 +1,4 @@
package kscience.kmath.stat.internal package space.kscience.kmath.stat.internal
import kotlin.math.* import kotlin.math.*

View File

@ -1,4 +1,4 @@
package kscience.kmath.stat.internal package space.kscience.kmath.stat.internal
import kotlin.math.ln import kotlin.math.ln
import kotlin.math.min import kotlin.math.min

View File

@ -1,10 +1,10 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kscience.kmath.stat.internal.InternalUtils import space.kscience.kmath.stat.internal.InternalUtils
import kotlin.math.ln import kotlin.math.ln
import kotlin.math.pow import kotlin.math.pow

View File

@ -1,10 +1,10 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kscience.kmath.stat.next import space.kscience.kmath.stat.next
import kotlin.math.* import kotlin.math.*
/** /**

View File

@ -1,10 +1,10 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kscience.kmath.stat.internal.InternalUtils import space.kscience.kmath.stat.internal.InternalUtils
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kotlin.math.* import kotlin.math.*
/** /**

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.chains.map import space.kscience.kmath.chains.map
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
/** /**
* Sampling from a Gaussian distribution with given mean and standard deviation. * Sampling from a Gaussian distribution with given mean and standard deviation.

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kotlin.math.exp import kotlin.math.exp
/** /**

View File

@ -1,12 +1,12 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.chains.ConstantChain import space.kscience.kmath.chains.ConstantChain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kscience.kmath.stat.internal.InternalUtils import space.kscience.kmath.stat.internal.InternalUtils
import kscience.kmath.stat.next import space.kscience.kmath.stat.next
import kotlin.math.* import kotlin.math.*
/** /**

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kotlin.math.ln import kotlin.math.ln
import kotlin.math.sqrt import kotlin.math.sqrt

View File

@ -1,6 +1,6 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
/** /**
* Marker interface for a sampler that generates values from an N(0,1) * Marker interface for a sampler that generates values from an N(0,1)

View File

@ -1,8 +1,8 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
/** /**
* Sampler for the Poisson distribution. * Sampler for the Poisson distribution.

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.exp import kotlin.math.exp

View File

@ -1,9 +1,9 @@
package kscience.kmath.stat.samplers package space.kscience.kmath.stat.samplers
import kscience.kmath.chains.Chain import space.kscience.kmath.chains.Chain
import kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import kscience.kmath.stat.Sampler import space.kscience.kmath.stat.Sampler
import kscience.kmath.stat.chain import space.kscience.kmath.stat.chain
import kotlin.math.* import kotlin.math.*
/** /**

View File

@ -3,9 +3,9 @@ package space.kscience.kmath.stat
import kotlinx.coroutines.flow.take import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kscience.kmath.stat.samplers.GaussianSampler
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import space.kscience.kmath.stat.samplers.GaussianSampler
internal class CommonsDistributionsTest { internal class CommonsDistributionsTest {
@Test @Test