0.3.0 #480

Merged
altavir merged 30 commits from dev into master 2022-04-12 10:59:28 +03:00
8 changed files with 71 additions and 54 deletions
Showing only changes of commit 39640498fc - Show all commits

View File

@ -11,7 +11,7 @@ allprojects {
} }
group = "space.kscience" group = "space.kscience"
version = "0.3.0-dev-20" version = "0.3.0-dev-21"
} }
subprojects { subprojects {

View File

@ -5,4 +5,4 @@
kotlin.code.style=official kotlin.code.style=official
toolsVersion=0.11.1-kotlin-1.6.10 toolsVersion=0.11.2-kotlin-1.6.10

View File

@ -7,6 +7,7 @@ package space.kscience.kmath.domains
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.indices import space.kscience.kmath.structures.indices
/** /**
@ -16,9 +17,17 @@ import space.kscience.kmath.structures.indices
* @author Alexander Nozik * @author Alexander Nozik
*/ */
@UnstableKMathAPI @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 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 -> override operator fun contains(point: Point<Double>): Boolean = point.indices.all { i ->
point[i] in lower[i]..upper[i] point[i] in lower[i]..upper[i]
} }

View File

@ -5,7 +5,6 @@
package space.kscience.kmath.histogram package space.kscience.kmath.histogram
import space.kscience.kmath.domains.Domain
import space.kscience.kmath.domains.HyperSquareDomain import space.kscience.kmath.domains.HyperSquareDomain
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.* import space.kscience.kmath.nd.*
@ -13,6 +12,9 @@ import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.structures.* import space.kscience.kmath.structures.*
import kotlin.math.floor import kotlin.math.floor
/**
* Multivariate histogram space for hyper-square real-field bins.
*/
public class DoubleHistogramSpace( public class DoubleHistogramSpace(
private val lower: Buffer<Double>, private val lower: Buffer<Double>,
private val upper: Buffer<Double>, private val upper: Buffer<Double>,
@ -47,7 +49,7 @@ public class DoubleHistogramSpace(
} }
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
override fun getDomain(index: IntArray): Domain<Double> { override fun getDomain(index: IntArray): HyperSquareDomain {
val lowerBoundary = index.mapIndexed { axis, i -> val lowerBoundary = index.mapIndexed { axis, i ->
when (i) { when (i) {
0 -> Double.NEGATIVE_INFINITY 0 -> Double.NEGATIVE_INFINITY
@ -67,8 +69,13 @@ public class DoubleHistogramSpace(
return HyperSquareDomain(lowerBoundary, upperBoundary) 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) val domain = getDomain(index)
return DomainBin(domain, value) 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>::start).asBuffer(),
ranges.map(ClosedFloatingPointRange<Double>::endInclusive).asBuffer() ranges.map(ClosedFloatingPointRange<Double>::endInclusive).asBuffer()
) )
@ -110,21 +119,22 @@ public class DoubleHistogramSpace(
*) *)
*``` *```
*/ */
public fun fromRanges(vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>): DoubleHistogramSpace = public fun fromRanges(
DoubleHistogramSpace( vararg ranges: Pair<ClosedFloatingPointRange<Double>, Int>,
ListBuffer( ): DoubleHistogramSpace = DoubleHistogramSpace(
ranges ListBuffer(
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first) ranges
.map(ClosedFloatingPointRange<Double>::start) .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
), .map(ClosedFloatingPointRange<Double>::start)
),
ListBuffer( ListBuffer(
ranges ranges
.map(Pair<ClosedFloatingPointRange<Double>, Int>::first) .map(Pair<ClosedFloatingPointRange<Double>, Int>::first)
.map(ClosedFloatingPointRange<Double>::endInclusive) .map(ClosedFloatingPointRange<Double>::endInclusive)
), ),
ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray() ranges.map(Pair<ClosedFloatingPointRange<Double>, Int>::second).toIntArray()
) )
} }
} }

View File

@ -7,7 +7,6 @@ package space.kscience.kmath.histogram
import space.kscience.kmath.domains.Domain import space.kscience.kmath.domains.Domain
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.DefaultStrides
import space.kscience.kmath.nd.FieldND import space.kscience.kmath.nd.FieldND
import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.Shape
@ -24,22 +23,21 @@ public data class DomainBin<in T : Comparable<T>>(
override val value: Number, override val value: Number,
) : Bin<T>, Domain<T> by domain ) : Bin<T>, Domain<T> by domain
@OptIn(UnstableKMathAPI::class)
public class IndexedHistogram<T : Comparable<T>, V : Any>( 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>, public val values: StructureND<V>,
) : Histogram<T, Bin<T>> { ) : Histogram<T, Bin<T>> {
override fun get(point: Point<T>): Bin<T>? { override fun get(point: Point<T>): Bin<T>? {
val index = context.getIndex(point) ?: return null val index = histogramSpace.getIndex(point) ?: return null
return context.produceBin(index, values[index]) 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>> override val bins: Iterable<Bin<T>>
get() = DefaultStrides(context.shape).asSequence().map { get() = DefaultStrides(histogramSpace.shape).asSequence().map {
context.produceBin(it, values[it]) histogramSpace.produceBin(it, values[it])
}.asIterable() }.asIterable()
} }
@ -67,13 +65,13 @@ public interface IndexedHistogramSpace<T : Comparable<T>, V : Any>
public fun produce(builder: HistogramBuilder<T>.() -> Unit): IndexedHistogram<T, V> public fun produce(builder: HistogramBuilder<T>.() -> Unit): IndexedHistogram<T, V>
override fun add(left: IndexedHistogram<T, V>, right: IndexedHistogram<T, V>): 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(left.histogramSpace == 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(right.histogramSpace == this) { "Can't operate on a histogram produced by external space" }
return IndexedHistogram(this, histogramValueSpace { left.values + right.values }) return IndexedHistogram(this, histogramValueSpace { left.values + right.values })
} }
override fun scale(a: IndexedHistogram<T, V>, value: Double): IndexedHistogram<T, V> { 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 }) return IndexedHistogram(this, histogramValueSpace { a.values * value })
} }

View File

@ -37,26 +37,6 @@ public class UnivariateBin(
public interface UnivariateHistogram : Histogram<Double, UnivariateBin> { public interface UnivariateHistogram : Histogram<Double, UnivariateBin> {
public operator fun get(value: Double): UnivariateBin? public operator fun get(value: Double): UnivariateBin?
override operator fun get(point: Buffer<Double>): UnivariateBin? = get(point[0]) 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 @UnstableKMathAPI

View File

@ -49,7 +49,9 @@ internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain
fun createBin(value: Double): BinCounter { fun createBin(value: Double): BinCounter {
val binDefinition = binFactory(value) val binDefinition = binFactory(value)
val newBin = BinCounter(binDefinition) val newBin = BinCounter(binDefinition)
synchronized(this) { bins[binDefinition.center] = newBin } synchronized(this) {
bins[binDefinition.center] = newBin
}
return newBin return newBin
} }
@ -131,6 +133,24 @@ public class TreeHistogramSpace(
override val zero: UnivariateHistogram by lazy { fill { } } override val zero: UnivariateHistogram by lazy { fill { } }
public companion object { 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. * Build and fill a [UnivariateHistogram]. Returns a read-only histogram.
*/ */

View File

@ -13,7 +13,7 @@ class TreeHistogramTest {
@Test @Test
fun normalFill() { fun normalFill() {
val histogram = UnivariateHistogram.uniform(0.1) { val histogram = TreeHistogramSpace.uniform(0.1) {
repeat(100_000) { repeat(100_000) {
putValue(Random.nextDouble()) putValue(Random.nextDouble())
} }