forked from kscience/kmath
Another histogram refactor
This commit is contained in:
parent
0b2e8ff25e
commit
39640498fc
@ -11,7 +11,7 @@ allprojects {
|
||||
}
|
||||
|
||||
group = "space.kscience"
|
||||
version = "0.3.0-dev-20"
|
||||
version = "0.3.0-dev-21"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
@ -5,4 +5,4 @@
|
||||
|
||||
kotlin.code.style=official
|
||||
|
||||
toolsVersion=0.11.1-kotlin-1.6.10
|
||||
toolsVersion=0.11.2-kotlin-1.6.10
|
||||
|
@ -7,6 +7,7 @@ package space.kscience.kmath.domains
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.DoubleBuffer
|
||||
import space.kscience.kmath.structures.indices
|
||||
|
||||
/**
|
||||
@ -16,9 +17,17 @@ import space.kscience.kmath.structures.indices
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public class HyperSquareDomain(private val lower: Buffer<Double>, private val upper: Buffer<Double>) : DoubleDomain {
|
||||
public class HyperSquareDomain(public val lower: Buffer<Double>, public val upper: Buffer<Double>) : DoubleDomain {
|
||||
init {
|
||||
require(lower.size == upper.size) {
|
||||
"Domain borders size mismatch. Lower borders size is ${lower.size}, but upper borders size is ${upper.size}"
|
||||
}
|
||||
}
|
||||
|
||||
override val dimension: Int get() = lower.size
|
||||
|
||||
public val center: DoubleBuffer get() = DoubleBuffer(dimension) { (lower[it] + upper[it]) / 2.0 }
|
||||
|
||||
override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
|
||||
point[i] in lower[i]..upper[i]
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
package space.kscience.kmath.histogram
|
||||
|
||||
import space.kscience.kmath.domains.Domain
|
||||
import space.kscience.kmath.domains.HyperSquareDomain
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.*
|
||||
@ -13,6 +12,9 @@ import space.kscience.kmath.operations.DoubleField
|
||||
import space.kscience.kmath.structures.*
|
||||
import kotlin.math.floor
|
||||
|
||||
/**
|
||||
* Multivariate histogram space for hyper-square real-field bins.
|
||||
*/
|
||||
public class DoubleHistogramSpace(
|
||||
private val lower: Buffer<Double>,
|
||||
private val upper: Buffer<Double>,
|
||||
@ -47,7 +49,7 @@ public class DoubleHistogramSpace(
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
override fun getDomain(index: IntArray): Domain<Double> {
|
||||
override fun getDomain(index: IntArray): HyperSquareDomain {
|
||||
val lowerBoundary = index.mapIndexed { axis, i ->
|
||||
when (i) {
|
||||
0 -> Double.NEGATIVE_INFINITY
|
||||
@ -67,8 +69,13 @@ public class DoubleHistogramSpace(
|
||||
return HyperSquareDomain(lowerBoundary, upperBoundary)
|
||||
}
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public val Bin<Double>.domain: HyperSquareDomain
|
||||
get() = (this as? DomainBin<Double>)?.domain as? HyperSquareDomain
|
||||
?: error("Im a teapot. This is not my bin")
|
||||
|
||||
override fun produceBin(index: IntArray, value: Double): Bin<Double> {
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
override fun produceBin(index: IntArray, value: Double): DomainBin<Double> {
|
||||
val domain = getDomain(index)
|
||||
return DomainBin(domain, value)
|
||||
}
|
||||
@ -96,7 +103,9 @@ public class DoubleHistogramSpace(
|
||||
*)
|
||||
*```
|
||||
*/
|
||||
public fun fromRanges(vararg ranges: ClosedFloatingPointRange<Double>): DoubleHistogramSpace = DoubleHistogramSpace(
|
||||
public fun fromRanges(
|
||||
vararg ranges: ClosedFloatingPointRange<Double>,
|
||||
): DoubleHistogramSpace = DoubleHistogramSpace(
|
||||
ranges.map(ClosedFloatingPointRange<Double>::start).asBuffer(),
|
||||
ranges.map(ClosedFloatingPointRange<Double>::endInclusive).asBuffer()
|
||||
)
|
||||
@ -110,8 +119,9 @@ public class DoubleHistogramSpace(
|
||||
*)
|
||||
*```
|
||||
*/
|
||||
public fun fromRanges(vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>): DoubleHistogramSpace =
|
||||
DoubleHistogramSpace(
|
||||
public fun fromRanges(
|
||||
vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
|
||||
): DoubleHistogramSpace = DoubleHistogramSpace(
|
||||
ListBuffer(
|
||||
ranges
|
||||
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
|
||||
|
@ -7,7 +7,6 @@ package space.kscience.kmath.histogram
|
||||
|
||||
import space.kscience.kmath.domains.Domain
|
||||
import space.kscience.kmath.linear.Point
|
||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.DefaultStrides
|
||||
import space.kscience.kmath.nd.FieldND
|
||||
import space.kscience.kmath.nd.Shape
|
||||
@ -24,22 +23,21 @@ public data class DomainBin<in T : Comparable<T>>(
|
||||
override val value: Number,
|
||||
) : Bin<T>, Domain<T> by domain
|
||||
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public class IndexedHistogram<T : Comparable<T>, V : Any>(
|
||||
public val context: IndexedHistogramSpace<T, V>,
|
||||
public val histogramSpace: IndexedHistogramSpace<T, V>,
|
||||
public val values: StructureND<V>,
|
||||
) : Histogram<T, Bin<T>> {
|
||||
|
||||
override fun get(point: Point<T>): Bin<T>? {
|
||||
val index = context.getIndex(point) ?: return null
|
||||
return context.produceBin(index, values[index])
|
||||
val index = histogramSpace.getIndex(point) ?: return null
|
||||
return histogramSpace.produceBin(index, values[index])
|
||||
}
|
||||
|
||||
override val dimension: Int get() = context.shape.size
|
||||
override val dimension: Int get() = histogramSpace.shape.size
|
||||
|
||||
override val bins: Iterable<Bin<T>>
|
||||
get() = DefaultStrides(context.shape).asSequence().map {
|
||||
context.produceBin(it, values[it])
|
||||
get() = DefaultStrides(histogramSpace.shape).asSequence().map {
|
||||
histogramSpace.produceBin(it, values[it])
|
||||
}.asIterable()
|
||||
}
|
||||
|
||||
@ -67,13 +65,13 @@ public interface IndexedHistogramSpace<T : Comparable<T>, V : Any>
|
||||
public fun produce(builder: HistogramBuilder<T>.() -> Unit): IndexedHistogram<T, V>
|
||||
|
||||
override fun add(left: IndexedHistogram<T, V>, right: IndexedHistogram<T, V>): IndexedHistogram<T, V> {
|
||||
require(left.context == this) { "Can't operate on a histogram produced by external space" }
|
||||
require(right.context == this) { "Can't operate on a histogram produced by external space" }
|
||||
require(left.histogramSpace == this) { "Can't operate on a histogram produced by external space" }
|
||||
require(right.histogramSpace == this) { "Can't operate on a histogram produced by external space" }
|
||||
return IndexedHistogram(this, histogramValueSpace { left.values + right.values })
|
||||
}
|
||||
|
||||
override fun scale(a: IndexedHistogram<T, V>, value: Double): IndexedHistogram<T, V> {
|
||||
require(a.context == this) { "Can't operate on a histogram produced by external space" }
|
||||
require(a.histogramSpace == this) { "Can't operate on a histogram produced by external space" }
|
||||
return IndexedHistogram(this, histogramValueSpace { a.values * value })
|
||||
}
|
||||
|
||||
|
@ -37,26 +37,6 @@ public class UnivariateBin(
|
||||
public interface UnivariateHistogram : Histogram<Double, UnivariateBin> {
|
||||
public operator fun get(value: Double): UnivariateBin?
|
||||
override operator fun get(point: Buffer<Double>): UnivariateBin? = get(point[0])
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Build and fill a [UnivariateHistogram]. Returns a read-only histogram.
|
||||
*/
|
||||
public inline fun uniform(
|
||||
binSize: Double,
|
||||
start: Double = 0.0,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).fill(builder)
|
||||
|
||||
/**
|
||||
* Build and fill a histogram with custom borders. Returns a read-only histogram.
|
||||
*/
|
||||
public inline fun custom(
|
||||
borders: DoubleArray,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
@ -49,7 +49,9 @@ internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain
|
||||
fun createBin(value: Double): BinCounter {
|
||||
val binDefinition = binFactory(value)
|
||||
val newBin = BinCounter(binDefinition)
|
||||
synchronized(this) { bins[binDefinition.center] = newBin }
|
||||
synchronized(this) {
|
||||
bins[binDefinition.center] = newBin
|
||||
}
|
||||
return newBin
|
||||
}
|
||||
|
||||
@ -131,6 +133,24 @@ public class TreeHistogramSpace(
|
||||
override val zero: UnivariateHistogram by lazy { fill { } }
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Build and fill a [UnivariateHistogram]. Returns a read-only histogram.
|
||||
*/
|
||||
public inline fun uniform(
|
||||
binSize: Double,
|
||||
start: Double = 0.0,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = uniform(binSize, start).fill(builder)
|
||||
|
||||
/**
|
||||
* Build and fill a histogram with custom borders. Returns a read-only histogram.
|
||||
*/
|
||||
public inline fun custom(
|
||||
borders: DoubleArray,
|
||||
builder: UnivariateHistogramBuilder.() -> Unit,
|
||||
): UnivariateHistogram = custom(borders).fill(builder)
|
||||
|
||||
|
||||
/**
|
||||
* Build and fill a [UnivariateHistogram]. Returns a read-only histogram.
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@ class TreeHistogramTest {
|
||||
|
||||
@Test
|
||||
fun normalFill() {
|
||||
val histogram = UnivariateHistogram.uniform(0.1) {
|
||||
val histogram = TreeHistogramSpace.uniform(0.1) {
|
||||
repeat(100_000) {
|
||||
putValue(Random.nextDouble())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user