diff --git a/CHANGELOG.md b/CHANGELOG.md index a19b1f467..d710c330b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ - Operations -> Ops - Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes. - Tensor algebra takes read-only structures as input and inherits AlgebraND +- `UnivariateDistribution` renamed to `Distribution1D` ### Deprecated - Specialized `DoubleBufferAlgebra` diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt index ccd1c3edb..3d531349c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt @@ -35,6 +35,23 @@ public class DoubleDomain1D( } override fun volume(): Double = range.endInclusive - range.start + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as DoubleDomain1D + + if (doubleRange != other.doubleRange) return false + + return true + } + + override fun hashCode(): Int = doubleRange.hashCode() + + override fun toString(): String = doubleRange.toString() + + } @UnstableKMathAPI diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt index a144e49b4..dc5421136 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt @@ -3,43 +3,71 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ + package space.kscience.kmath.misc -import kotlin.comparisons.* import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.VirtualBuffer /** - * Return a new list filled with buffer indices. Indice order is defined by sorting associated buffer value. - * This feature allows to sort buffer values without reordering its content. + * Return a new array filled with buffer indices. Indices order is defined by sorting associated buffer value. + * This feature allows sorting buffer values without reordering its content. * - * @return List of buffer indices, sorted by associated value. + * @return Buffer indices, sorted by associated value. */ -@PerformancePitfall @UnstableKMathAPI -public fun > Buffer.permSort() : IntArray = _permSortWith(compareBy { get(it) }) +public fun > Buffer.indicesSorted(): IntArray = permSortIndicesWith(compareBy { get(it) }) + +/** + * Create a zero-copy virtual buffer that contains the same elements but in ascending order + */ +@OptIn(UnstableKMathAPI::class) +public fun > Buffer.sorted(): Buffer { + val permutations = indicesSorted() + return VirtualBuffer(size) { this[permutations[it]] } +} -@PerformancePitfall @UnstableKMathAPI -public fun > Buffer.permSortDescending() : IntArray = _permSortWith(compareByDescending { get(it) }) +public fun > Buffer.indicesSortedDescending(): IntArray = + permSortIndicesWith(compareByDescending { get(it) }) + +/** + * Create a zero-copy virtual buffer that contains the same elements but in descending order + */ +@OptIn(UnstableKMathAPI::class) +public fun > Buffer.sortedDescending(): Buffer { + val permutations = indicesSortedDescending() + return VirtualBuffer(size) { this[permutations[it]] } +} -@PerformancePitfall @UnstableKMathAPI -public fun > Buffer.permSortBy(selector: (V) -> C) : IntArray = _permSortWith(compareBy { selector(get(it)) }) +public fun > Buffer.indicesSortedBy(selector: (V) -> C): IntArray = + permSortIndicesWith(compareBy { selector(get(it)) }) + +@OptIn(UnstableKMathAPI::class) +public fun > Buffer.sortedBy(selector: (V) -> C): Buffer { + val permutations = indicesSortedBy(selector) + return VirtualBuffer(size) { this[permutations[it]] } +} -@PerformancePitfall @UnstableKMathAPI -public fun > Buffer.permSortByDescending(selector: (V) -> C) : IntArray = _permSortWith(compareByDescending { selector(get(it)) }) +public fun > Buffer.indicesSortedByDescending(selector: (V) -> C): IntArray = + permSortIndicesWith(compareByDescending { selector(get(it)) }) + +@OptIn(UnstableKMathAPI::class) +public fun > Buffer.sortedByDescending(selector: (V) -> C): Buffer { + val permutations = indicesSortedByDescending(selector) + return VirtualBuffer(size) { this[permutations[it]] } +} -@PerformancePitfall @UnstableKMathAPI -public fun Buffer.permSortWith(comparator : Comparator) : IntArray = _permSortWith { i1, i2 -> comparator.compare(get(i1), get(i2)) } +public fun Buffer.indicesSortedWith(comparator: Comparator): IntArray = + permSortIndicesWith { i1, i2 -> comparator.compare(get(i1), get(i2)) } -@PerformancePitfall -@UnstableKMathAPI -private fun Buffer._permSortWith(comparator : Comparator) : IntArray { - if (size < 2) return IntArray(size) +private fun Buffer.permSortIndicesWith(comparator: Comparator): IntArray { + if (size < 2) return IntArray(size) { 0 } - /* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indice + /* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indices * arrays more efficiently by copying subpart of cached one. For bigger needs, we could copy entire * cached array, then fill remaining indices manually. Not done for now, because: * 1. doing it right would require some statistics about common used buffer sizes. @@ -53,3 +81,12 @@ private fun Buffer._permSortWith(comparator : Comparator) : IntArray */ return packedIndices.sortedWith(comparator).toIntArray() } + +/** + * Checks that the [Buffer] is sorted (ascending) and throws [IllegalArgumentException] if it is not. + */ +public fun > Buffer.requireSorted() { + for (i in 0..(size - 2)) { + require(get(i + 1) >= get(i)) { "The buffer is not sorted at index $i" } + } +} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt index 0a2bb9138..4a724ac5f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt @@ -6,14 +6,13 @@ package space.kscience.kmath.misc import space.kscience.kmath.misc.PermSortTest.Platform.* -import kotlin.random.Random -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - import space.kscience.kmath.structures.IntBuffer import space.kscience.kmath.structures.asBuffer +import kotlin.random.Random +import kotlin.test.Test import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertTrue class PermSortTest { @@ -29,9 +28,9 @@ class PermSortTest { @Test fun testOnEmptyBuffer() { val emptyBuffer = IntBuffer(0) {it} - var permutations = emptyBuffer.permSort() + var permutations = emptyBuffer.indicesSorted() assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") - permutations = emptyBuffer.permSortDescending() + permutations = emptyBuffer.indicesSortedDescending() assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") } @@ -47,25 +46,25 @@ class PermSortTest { @Test fun testPermSortBy() { - val permutations = platforms.permSortBy { it.name } + val permutations = platforms.indicesSortedBy { it.name } val expected = listOf(ANDROID, JS, JVM, NATIVE, WASM) assertContentEquals(expected, permutations.map { platforms[it] }, "Ascending PermSort by name") } @Test fun testPermSortByDescending() { - val permutations = platforms.permSortByDescending { it.name } + val permutations = platforms.indicesSortedByDescending { it.name } val expected = listOf(WASM, NATIVE, JVM, JS, ANDROID) assertContentEquals(expected, permutations.map { platforms[it] }, "Descending PermSort by name") } @Test fun testPermSortWith() { - var permutations = platforms.permSortWith { p1, p2 -> p1.name.length.compareTo(p2.name.length) } + var permutations = platforms.indicesSortedWith { p1, p2 -> p1.name.length.compareTo(p2.name.length) } val expected = listOf(JS, JVM, WASM, NATIVE, ANDROID) assertContentEquals(expected, permutations.map { platforms[it] }, "PermSort using custom ascending comparator") - permutations = platforms.permSortWith(compareByDescending { it.name.length }) + permutations = platforms.indicesSortedWith(compareByDescending { it.name.length }) assertContentEquals(expected.reversed(), permutations.map { platforms[it] }, "PermSort using custom descending comparator") } @@ -75,7 +74,7 @@ class PermSortTest { println("Test randomization seed: $seed") val buffer = Random(seed).buffer(bufferSize) - val indices = buffer.permSort() + val indices = buffer.indicesSorted() assertEquals(bufferSize, indices.size) // Ensure no doublon is present in indices @@ -87,7 +86,7 @@ class PermSortTest { assertTrue(current <= next, "Permutation indices not properly sorted") } - val descIndices = buffer.permSortDescending() + val descIndices = buffer.indicesSortedDescending() assertEquals(bufferSize, descIndices.size) // Ensure no doublon is present in indices assertEquals(descIndices.toSet().size, descIndices.size) diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index 4cccaef5c..18c2c50ad 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -21,19 +21,22 @@ readme { feature( id = "DoubleVector", - description = "Numpy-like operations for Buffers/Points", ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt" - ) + ){ + "Numpy-like operations for Buffers/Points" + } feature( id = "DoubleMatrix", - description = "Numpy-like operations for 2d real structures", ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt" - ) + ){ + "Numpy-like operations for 2d real structures" + } feature( id = "grids", - description = "Uniform grid generators", ref = "src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt" - ) + ){ + "Uniform grid generators" + } } diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 7e511faa0..51271bb0a 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -17,6 +17,8 @@ kotlin.sourceSets { commonTest { dependencies { implementation(project(":kmath-for-real")) + implementation(projects.kmath.kmathStat) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0") } } } diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramGroup.kt similarity index 96% rename from kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt rename to kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramGroup.kt index c0df8c2cc..a80ed119c 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramGroup.kt @@ -16,11 +16,11 @@ import kotlin.math.floor /** * Multivariate histogram space for hyper-square real-field bins. */ -public class DoubleHistogramSpace( +public class DoubleHistogramGroup( private val lower: Buffer, private val upper: Buffer, private val binNums: IntArray = IntArray(lower.size) { 20 }, -) : IndexedHistogramSpace { +) : IndexedHistogramGroup { init { // argument checks @@ -105,7 +105,7 @@ public class DoubleHistogramSpace( */ public fun fromRanges( vararg ranges: ClosedFloatingPointRange, - ): DoubleHistogramSpace = DoubleHistogramSpace( + ): DoubleHistogramGroup = DoubleHistogramGroup( ranges.map(ClosedFloatingPointRange::start).asBuffer(), ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer() ) @@ -121,7 +121,7 @@ public class DoubleHistogramSpace( */ public fun fromRanges( vararg ranges: Pair, Int>, - ): DoubleHistogramSpace = DoubleHistogramSpace( + ): DoubleHistogramGroup = DoubleHistogramGroup( ListBuffer( ranges .map(Pair, Int>::first) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt index 4f193f943..237bd87b9 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram1D.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.histogram import space.kscience.kmath.domains.Domain1D +import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer @@ -18,7 +19,7 @@ import space.kscience.kmath.structures.Buffer * @property standardDeviation Standard deviation of the bin value. Zero or negative if not applicable */ @UnstableKMathAPI -public class Bin1D, out V>( +public data class Bin1D, out V>( public val domain: Domain1D, override val binValue: V, ) : Bin, ClosedRange by domain.range { @@ -35,12 +36,15 @@ public interface Histogram1D, V> : Histogram override operator fun get(point: Buffer): Bin1D? = get(point[0]) } -@UnstableKMathAPI public interface Histogram1DBuilder : HistogramBuilder { /** * Thread safe put operation */ public fun putValue(at: T, value: V = defaultValue) + + override fun putValue(point: Point, value: V) { + putValue(point[0], value) + } } @UnstableKMathAPI @@ -52,5 +56,5 @@ public fun Histogram1DBuilder.fill(array: DoubleArray): Unit = array.forEach(this::putValue) @UnstableKMathAPI -public fun Histogram1DBuilder.fill(buffer: Buffer): Unit = +public fun Histogram1DBuilder.fill(buffer: Buffer): Unit = buffer.asSequence().forEach(this::putValue) \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramGroup.kt similarity index 93% rename from kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt rename to kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramGroup.kt index 3e4b07984..9749f8403 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramGroup.kt @@ -28,7 +28,7 @@ public data class DomainBin, out V>( * @param V the type of bin value */ public class IndexedHistogram, V : Any>( - public val histogramSpace: IndexedHistogramSpace, + public val histogramSpace: IndexedHistogramGroup, public val values: StructureND, ) : Histogram> { @@ -48,8 +48,8 @@ public class IndexedHistogram, V : Any>( /** * A space for producing histograms with values in a NDStructure */ -public interface IndexedHistogramSpace, V : Any> - : Group>, ScaleOperations> { +public interface IndexedHistogramGroup, V : Any> : Group>, + ScaleOperations> { public val shape: Shape public val histogramValueAlgebra: FieldND //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape), diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt index ed8b2e29d..44638c29b 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/UniformHistogram1D.kt @@ -5,8 +5,92 @@ package space.kscience.kmath.histogram -//class UniformHistogram1D( -// public val borders: Buffer, -// public val values: Buffer, -//) : Histogram1D { -//} \ No newline at end of file +import space.kscience.kmath.domains.DoubleDomain1D +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.Group +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.ScaleOperations +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.structures.Buffer +import kotlin.math.floor + +@OptIn(UnstableKMathAPI::class) +public class UniformHistogram1D( + public val group: UniformHistogram1DGroup, + public val values: Map, +) : Histogram1D { + + private val startPoint get() = group.startPoint + private val binSize get() = group.binSize + + private fun produceBin(index: Int, value: V): Bin1D { + val domain = DoubleDomain1D((startPoint + index * binSize)..(startPoint + (index + 1) * binSize)) + return Bin1D(domain, value) + } + + override val bins: Iterable> get() = values.map { produceBin(it.key, it.value) } + + override fun get(value: Double): Bin1D? { + val index: Int = group.getIndex(value) + val v = values[index] + return v?.let { produceBin(index, it) } + } +} + +public class UniformHistogram1DGroup( + public val valueAlgebra: A, + public val binSize: Double, + public val startPoint: Double = 0.0, +) : Group>, ScaleOperations> where A : Ring, A : ScaleOperations { + override val zero: UniformHistogram1D by lazy { UniformHistogram1D(this, emptyMap()) } + + public fun getIndex(at: Double): Int = floor((at - startPoint) / binSize).toInt() + + override fun add(left: UniformHistogram1D, right: UniformHistogram1D): UniformHistogram1D = valueAlgebra { + require(left.group == this@UniformHistogram1DGroup) + require(right.group == this@UniformHistogram1DGroup) + val keys = left.values.keys + right.values.keys + UniformHistogram1D( + this@UniformHistogram1DGroup, + keys.associateWith { (left.values[it] ?: valueAlgebra.zero) + (right.values[it] ?: valueAlgebra.zero) } + ) + } + + override fun UniformHistogram1D.unaryMinus(): UniformHistogram1D = valueAlgebra { + UniformHistogram1D(this@UniformHistogram1DGroup, values.mapValues { -it.value }) + } + + override fun scale( + a: UniformHistogram1D, + value: Double, + ): UniformHistogram1D = UniformHistogram1D( + this@UniformHistogram1DGroup, + a.values.mapValues { valueAlgebra.scale(it.value, value) } + ) + + public inline fun produce(block: Histogram1DBuilder.() -> Unit): UniformHistogram1D { + val map = HashMap() + val builder = object : Histogram1DBuilder { + override val defaultValue: V get() = valueAlgebra.zero + + override fun putValue(at: Double, value: V) { + val index = getIndex(at) + map[index] = with(valueAlgebra) { (map[index] ?: zero) + one } + } + } + builder.block() + return UniformHistogram1D(this, map) + } +} + +public fun Histogram.Companion.uniform1D( + algebra: A, + binSize: Double, + startPoint: Double = 0.0, +): UniformHistogram1DGroup where A : Ring, A : ScaleOperations = + UniformHistogram1DGroup(algebra, binSize, startPoint) + +@UnstableKMathAPI +public fun UniformHistogram1DGroup.produce( + buffer: Buffer, +): UniformHistogram1D = produce { fill(buffer) } \ No newline at end of file diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt index 31a29676c..1426b35fa 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt @@ -14,7 +14,7 @@ import kotlin.test.* internal class MultivariateHistogramTest { @Test fun testSinglePutHistogram() { - val hSpace = DoubleHistogramSpace.fromRanges( + val hSpace = DoubleHistogramGroup.fromRanges( (-1.0..1.0), (-1.0..1.0) ) @@ -29,7 +29,7 @@ internal class MultivariateHistogramTest { @Test fun testSequentialPut() { - val hSpace = DoubleHistogramSpace.fromRanges( + val hSpace = DoubleHistogramGroup.fromRanges( (-1.0..1.0), (-1.0..1.0), (-1.0..1.0) @@ -49,7 +49,7 @@ internal class MultivariateHistogramTest { @Test fun testHistogramAlgebra() { - DoubleHistogramSpace.fromRanges( + DoubleHistogramGroup.fromRanges( (-1.0..1.0), (-1.0..1.0), (-1.0..1.0) diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt new file mode 100644 index 000000000..d23afdb8b --- /dev/null +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/UniformHistogram1DTest.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.histogram + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import space.kscience.kmath.distributions.NormalDistribution +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.stat.nextBuffer +import kotlin.test.Test +import kotlin.test.assertEquals + +@OptIn(ExperimentalCoroutinesApi::class, UnstableKMathAPI::class) +internal class UniformHistogram1DTest { + @Test + fun normal() = runTest { + val generator = RandomGenerator.default(123) + val distribution = NormalDistribution(0.0, 1.0) + with(Histogram.uniform1D(DoubleField, 0.1)) { + val h1 = produce(distribution.nextBuffer(generator, 10000)) + + val h2 = produce(distribution.nextBuffer(generator, 50000)) + + val h3 = h1 + h2 + + assertEquals(60000, h3.bins.sumOf { it.binValue }.toInt()) + } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index 3d3f95f8f..8dbcb3367 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -27,7 +27,7 @@ public interface Distribution : Sampler { public companion object } -public interface UnivariateDistribution> : Distribution { +public interface Distribution1D> : Distribution { /** * Cumulative distribution for ordered parameter (CDF) */ @@ -37,7 +37,7 @@ public interface UnivariateDistribution> : Distribution { /** * Compute probability integral in an interval */ -public fun > UnivariateDistribution.integral(from: T, to: T): Double { +public fun > Distribution1D.integral(from: T, to: T): Double { require(to > from) return cumulative(to) - cumulative(from) } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt index 66e041f05..cfc6eba04 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt @@ -14,14 +14,9 @@ import space.kscience.kmath.stat.RandomGenerator import kotlin.math.* /** - * Implements [UnivariateDistribution] for the normal (gaussian) distribution. + * Implements [Distribution1D] for the normal (gaussian) distribution. */ -public class NormalDistribution(public val sampler: GaussianSampler) : UnivariateDistribution { - public constructor( - mean: Double, - standardDeviation: Double, - normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, - ) : this(GaussianSampler(mean, standardDeviation, normalized)) +public class NormalDistribution(public val sampler: GaussianSampler) : Distribution1D { override fun probability(arg: Double): Double { val x1 = (arg - sampler.mean) / sampler.standardDeviation @@ -43,3 +38,9 @@ public class NormalDistribution(public val sampler: GaussianSampler) : Univariat private val SQRT2 = sqrt(2.0) } } + +public fun NormalDistribution( + mean: Double, + standardDeviation: Double, + normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, +): NormalDistribution = NormalDistribution(GaussianSampler(mean, standardDeviation, normalized)) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 0dd121f3b..c96ecdc8c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -67,3 +67,12 @@ public fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int): @JvmName("sampleIntBuffer") public fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int): Chain> = sampleBuffer(generator, size, ::IntBuffer) + + +/** + * Samples a [Buffer] of values from this [Sampler]. + */ +public suspend fun Sampler.nextBuffer(generator: RandomGenerator, size: Int): Buffer = + sampleBuffer(generator, size).first() + +//TODO add `context(RandomGenerator) Sampler.nextBuffer \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt index 970a3aab5..20cc0e802 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt @@ -8,9 +8,9 @@ package space.kscience.kmath.stat import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.SimpleChain import space.kscience.kmath.distributions.Distribution -import space.kscience.kmath.distributions.UnivariateDistribution +import space.kscience.kmath.distributions.Distribution1D -public class UniformDistribution(public val range: ClosedFloatingPointRange) : UnivariateDistribution { +public class UniformDistribution(public val range: ClosedFloatingPointRange) : Distribution1D { private val length: Double = range.endInclusive - range.start override fun probability(arg: Double): Double = if (arg in range) 1.0 / length else 0.0