Complete refactor of histograms API #476

Merged
altavir merged 15 commits from refactor/histogram into dev 2022-04-10 20:59:05 +03:00
2 changed files with 39 additions and 1 deletions
Showing only changes of commit a2c0bc8a10 - Show all commits

View File

@ -81,6 +81,30 @@ public class UniformHistogram1DGroup<V : Any, A>(
builder.block() builder.block()
return UniformHistogram1D(this, map) return UniformHistogram1D(this, map)
} }
/**
* Re-bin given histogram to be compatible if exiting bin fully falls inside existing bin, this bin value
* is increased by one. If not, all bins including values from this bin are increased by fraction
* (conserving the norming).
*/
@UnstableKMathAPI
public fun produceFrom(histogram: Histogram1D<Double, V>): UniformHistogram1D<V> =
if ((histogram as? UniformHistogram1D)?.group == this) histogram
else {
val map = HashMap<Int, V>()
histogram.bins.forEach { bin ->
val range = bin.domain.range
val indexOfLeft = getIndex(range.start)
val indexOfRight = getIndex(range.endInclusive)
val numBins = indexOfRight - indexOfLeft + 1
for (i in indexOfLeft..indexOfRight) {
map[indexOfLeft] = with(valueAlgebra) {
(map[indexOfLeft] ?: zero) + bin.binValue / numBins
}
}
}
UniformHistogram1D(this, map)
}
} }
public fun <V : Any, A> Histogram.Companion.uniform1D( public fun <V : Any, A> Histogram.Companion.uniform1D(

View File

@ -12,14 +12,15 @@ import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.RandomGenerator
import space.kscience.kmath.stat.nextBuffer import space.kscience.kmath.stat.nextBuffer
import kotlin.native.concurrent.ThreadLocal
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@OptIn(ExperimentalCoroutinesApi::class, UnstableKMathAPI::class) @OptIn(ExperimentalCoroutinesApi::class, UnstableKMathAPI::class)
internal class UniformHistogram1DTest { internal class UniformHistogram1DTest {
@Test @Test
fun normal() = runTest { fun normal() = runTest {
val generator = RandomGenerator.default(123)
val distribution = NormalDistribution(0.0, 1.0) val distribution = NormalDistribution(0.0, 1.0)
with(Histogram.uniform1D(DoubleField, 0.1)) { with(Histogram.uniform1D(DoubleField, 0.1)) {
val h1 = produce(distribution.nextBuffer(generator, 10000)) val h1 = produce(distribution.nextBuffer(generator, 10000))
@ -31,4 +32,17 @@ internal class UniformHistogram1DTest {
assertEquals(60000, h3.bins.sumOf { it.binValue }.toInt()) assertEquals(60000, h3.bins.sumOf { it.binValue }.toInt())
} }
} }
@Test
fun rebin() = runTest {
val h1 = Histogram.uniform1D(DoubleField, 0.1).produce(generator.nextDoubleBuffer(10000))
val h2 = Histogram.uniform1D(DoubleField,0.3).produceFrom(h1)
assertEquals(10000, h2.bins.sumOf { it.binValue }.toInt())
}
@ThreadLocal
companion object{
private val generator = RandomGenerator.default(123)
}
} }