forked from kscience/kmath
Buffer views
This commit is contained in:
parent
bf504ae6c5
commit
a1351aa942
@ -12,8 +12,6 @@ import space.kscience.kmath.commons.optimization.CMOptimizer
|
|||||||
import space.kscience.kmath.distributions.NormalDistribution
|
import space.kscience.kmath.distributions.NormalDistribution
|
||||||
import space.kscience.kmath.expressions.chiSquaredExpression
|
import space.kscience.kmath.expressions.chiSquaredExpression
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import space.kscience.kmath.operations.asIterable
|
|
||||||
import space.kscience.kmath.operations.toList
|
|
||||||
import space.kscience.kmath.optimization.FunctionOptimizationTarget
|
import space.kscience.kmath.optimization.FunctionOptimizationTarget
|
||||||
import space.kscience.kmath.optimization.optimizeWith
|
import space.kscience.kmath.optimization.optimizeWith
|
||||||
import space.kscience.kmath.optimization.resultPoint
|
import space.kscience.kmath.optimization.resultPoint
|
||||||
@ -22,6 +20,8 @@ import space.kscience.kmath.real.DoubleVector
|
|||||||
import space.kscience.kmath.real.map
|
import space.kscience.kmath.real.map
|
||||||
import space.kscience.kmath.real.step
|
import space.kscience.kmath.real.step
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
|
import space.kscience.kmath.structures.toList
|
||||||
import space.kscience.plotly.*
|
import space.kscience.plotly.*
|
||||||
import space.kscience.plotly.models.ScatterMode
|
import space.kscience.plotly.models.ScatterMode
|
||||||
import space.kscience.plotly.models.TraceValues
|
import space.kscience.plotly.models.TraceValues
|
||||||
|
@ -13,8 +13,6 @@ import space.kscience.kmath.distributions.NormalDistribution
|
|||||||
import space.kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.expressions.Symbol
|
||||||
import space.kscience.kmath.expressions.binding
|
import space.kscience.kmath.expressions.binding
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import space.kscience.kmath.operations.asIterable
|
|
||||||
import space.kscience.kmath.operations.toList
|
|
||||||
import space.kscience.kmath.optimization.QowOptimizer
|
import space.kscience.kmath.optimization.QowOptimizer
|
||||||
import space.kscience.kmath.optimization.chiSquaredOrNull
|
import space.kscience.kmath.optimization.chiSquaredOrNull
|
||||||
import space.kscience.kmath.optimization.fitWith
|
import space.kscience.kmath.optimization.fitWith
|
||||||
@ -22,6 +20,8 @@ import space.kscience.kmath.optimization.resultPoint
|
|||||||
import space.kscience.kmath.real.map
|
import space.kscience.kmath.real.map
|
||||||
import space.kscience.kmath.real.step
|
import space.kscience.kmath.real.step
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
|
import space.kscience.kmath.structures.toList
|
||||||
import space.kscience.plotly.*
|
import space.kscience.plotly.*
|
||||||
import space.kscience.plotly.models.ScatterMode
|
import space.kscience.plotly.models.ScatterMode
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
@ -1,37 +1,43 @@
|
|||||||
package space.kscience.kmath.series
|
package space.kscience.kmath.series
|
||||||
|
|
||||||
|
|
||||||
import net.jafama.StrictFastMath.abs
|
import kotlinx.html.FlowContent
|
||||||
|
import kotlinx.html.h1
|
||||||
import space.kscience.kmath.operations.algebra
|
import space.kscience.kmath.operations.algebra
|
||||||
import space.kscience.kmath.operations.bufferAlgebra
|
import space.kscience.kmath.operations.bufferAlgebra
|
||||||
import space.kscience.kmath.operations.invoke
|
|
||||||
import space.kscience.kmath.operations.toList
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.plotly.Plotly
|
import space.kscience.kmath.structures.toList
|
||||||
import space.kscience.plotly.makeFile
|
import space.kscience.plotly.*
|
||||||
import space.kscience.plotly.scatter
|
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
fun main() = Double.algebra.bufferAlgebra.seriesAlgebra(0..100).invoke {
|
fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) {
|
||||||
fun Buffer<Double>.plot() {
|
fun FlowContent.plotSeries(buffer: Buffer<Double>) {
|
||||||
val ls = labels
|
val ls = buffer.labels
|
||||||
Plotly.plot {
|
plot {
|
||||||
scatter {
|
scatter {
|
||||||
x.numbers = ls
|
x.numbers = ls
|
||||||
y.numbers = toList()
|
y.numbers = buffer.toList()
|
||||||
}
|
}
|
||||||
|
layout {
|
||||||
|
xaxis {
|
||||||
|
range(0.0..100.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val s1 = series(100) { sin(2 * PI * it / 100) + 1.0 }
|
||||||
|
val s2 = s1.slice(20..50).moveTo(40)
|
||||||
|
|
||||||
|
val s3: Buffer<Double> = s1.zip(s2) { l, r -> l + r } //s1 + s2
|
||||||
|
val s4 = ln(s3)
|
||||||
|
|
||||||
|
Plotly.page {
|
||||||
|
h1 { +"This is my plot" }
|
||||||
|
plotSeries(s1)
|
||||||
|
plotSeries(s2)
|
||||||
|
plotSeries(s4)
|
||||||
}.makeFile()
|
}.makeFile()
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val s1 = series(100) { sin(2 * PI * it / 100) }
|
|
||||||
val s2 = series(100) { 1.0 }
|
|
||||||
|
|
||||||
(s1 - s2).plot()
|
|
||||||
|
|
||||||
// Kolmogorov-Smirnov test statistic
|
|
||||||
val kst = (s1 - s2).fold(0.0) { sup, arg -> max(sup, abs(arg))}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -7,10 +7,11 @@ package space.kscience.kmath.commons.random
|
|||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import space.kscience.kmath.misc.PerformancePitfall
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
import space.kscience.kmath.samplers.GaussianSampler
|
|
||||||
import space.kscience.kmath.misc.toIntExact
|
import space.kscience.kmath.misc.toIntExact
|
||||||
|
import space.kscience.kmath.samplers.GaussianSampler
|
||||||
|
import space.kscience.kmath.samplers.next
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.next
|
|
||||||
|
|
||||||
public class CMRandomGeneratorWrapper(
|
public class CMRandomGeneratorWrapper(
|
||||||
public val factory: (IntArray) -> RandomGenerator,
|
public val factory: (IntArray) -> RandomGenerator,
|
||||||
|
@ -10,13 +10,9 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.apache.commons.math3.transform.*
|
import org.apache.commons.math3.transform.*
|
||||||
import space.kscience.kmath.complex.Complex
|
import space.kscience.kmath.complex.Complex
|
||||||
import space.kscience.kmath.operations.SuspendBufferTransform
|
|
||||||
import space.kscience.kmath.streaming.chunked
|
import space.kscience.kmath.streaming.chunked
|
||||||
import space.kscience.kmath.streaming.spread
|
import space.kscience.kmath.streaming.spread
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.*
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
|
||||||
import space.kscience.kmath.structures.VirtualBuffer
|
|
||||||
import space.kscience.kmath.structures.asBuffer
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,11 +13,11 @@ import space.kscience.kmath.expressions.Symbol.Companion.x
|
|||||||
import space.kscience.kmath.expressions.Symbol.Companion.y
|
import space.kscience.kmath.expressions.Symbol.Companion.y
|
||||||
import space.kscience.kmath.expressions.chiSquaredExpression
|
import space.kscience.kmath.expressions.chiSquaredExpression
|
||||||
import space.kscience.kmath.expressions.symbol
|
import space.kscience.kmath.expressions.symbol
|
||||||
import space.kscience.kmath.operations.map
|
|
||||||
import space.kscience.kmath.optimization.*
|
import space.kscience.kmath.optimization.*
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.asBuffer
|
import space.kscience.kmath.structures.asBuffer
|
||||||
|
import space.kscience.kmath.structures.map
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
@ -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.indices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
package space.kscience.kmath.expressions
|
package space.kscience.kmath.expressions
|
||||||
|
|
||||||
import space.kscience.kmath.operations.ExtendedField
|
import space.kscience.kmath.operations.ExtendedField
|
||||||
import space.kscience.kmath.operations.asIterable
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
|
import space.kscience.kmath.structures.indices
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,6 +13,7 @@ import space.kscience.kmath.operations.*
|
|||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
import space.kscience.kmath.structures.VirtualBuffer
|
import space.kscience.kmath.structures.VirtualBuffer
|
||||||
|
import space.kscience.kmath.structures.indices
|
||||||
|
|
||||||
|
|
||||||
public class BufferedLinearSpace<T, out A : Ring<T>>(
|
public class BufferedLinearSpace<T, out A : Ring<T>>(
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
package space.kscience.kmath.nd
|
package space.kscience.kmath.nd
|
||||||
|
|
||||||
import space.kscience.kmath.misc.PerformancePitfall
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
import space.kscience.kmath.operations.asSequence
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.asMutableBuffer
|
import space.kscience.kmath.structures.asMutableBuffer
|
||||||
|
import space.kscience.kmath.structures.asSequence
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,6 @@ package space.kscience.kmath.operations
|
|||||||
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.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
|
||||||
import space.kscience.kmath.structures.ShortBuffer
|
import space.kscience.kmath.structures.ShortBuffer
|
||||||
|
|
||||||
public interface WithSize {
|
public interface WithSize {
|
||||||
@ -183,7 +182,7 @@ public class BufferField<T, A : Field<T>>(
|
|||||||
/**
|
/**
|
||||||
* Generate full buffer field from given buffer operations
|
* Generate full buffer field from given buffer operations
|
||||||
*/
|
*/
|
||||||
public fun <T, A : Field<T>> BufferFieldOps<T, A>.withSize(size: Int): BufferField<T, A> =
|
public fun <T, A : Field<T>> BufferAlgebra<T, A>.withSize(size: Int): BufferField<T, A> =
|
||||||
BufferField(elementAlgebra, bufferFactory, size)
|
BufferField(elementAlgebra, bufferFactory, size)
|
||||||
|
|
||||||
//Double buffer specialization
|
//Double buffer specialization
|
||||||
@ -196,6 +195,4 @@ public fun BufferField<Double, *>.buffer(vararg elements: Number): Buffer<Double
|
|||||||
public fun <T, A : Field<T>> A.bufferAlgebra(bufferFactory: BufferFactory<T>): BufferFieldOps<T, A> =
|
public fun <T, A : Field<T>> A.bufferAlgebra(bufferFactory: BufferFactory<T>): BufferFieldOps<T, A> =
|
||||||
BufferFieldOps(this, bufferFactory)
|
BufferFieldOps(this, bufferFactory)
|
||||||
|
|
||||||
public val DoubleField.bufferAlgebra: BufferFieldOps<Double, DoubleField>
|
public val DoubleField.bufferAlgebra: DoubleBufferOps get() = DoubleBufferOps
|
||||||
get() = BufferFieldOps(DoubleField, ::DoubleBuffer)
|
|
||||||
|
|
||||||
|
@ -7,10 +7,7 @@ package space.kscience.kmath.operations
|
|||||||
|
|
||||||
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.*
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
|
||||||
import space.kscience.kmath.structures.asBuffer
|
|
||||||
|
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.kmath.operations.asSequence
|
import space.kscience.kmath.operations.WithSize
|
||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -30,11 +30,11 @@ public typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
|
|||||||
*
|
*
|
||||||
* @param T the type of elements contained in the buffer.
|
* @param T the type of elements contained in the buffer.
|
||||||
*/
|
*/
|
||||||
public interface Buffer<out T> {
|
public interface Buffer<out T> : WithSize {
|
||||||
/**
|
/**
|
||||||
* The size of this buffer.
|
* The size of this buffer.
|
||||||
*/
|
*/
|
||||||
public val size: Int
|
override val size: Int
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets element at given index.
|
* Gets element at given index.
|
||||||
@ -44,15 +44,10 @@ public interface Buffer<out T> {
|
|||||||
/**
|
/**
|
||||||
* Iterates over all elements.
|
* Iterates over all elements.
|
||||||
*/
|
*/
|
||||||
public operator fun iterator(): Iterator<T>
|
public operator fun iterator(): Iterator<T> = indices.asSequence().map(::get).iterator()
|
||||||
|
|
||||||
override fun toString(): String
|
override fun toString(): String
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an [IntRange] of the valid indices for this [Buffer].
|
|
||||||
*/
|
|
||||||
public val indices: IntRange get() = 0 until size
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
public fun toString(buffer: Buffer<*>): String =
|
public fun toString(buffer: Buffer<*>): String =
|
||||||
@ -105,7 +100,12 @@ public interface Buffer<out T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public operator fun<T> Buffer<T>.get(index: UInt): T = get(index.toInt())
|
/**
|
||||||
|
* Returns an [IntRange] of the valid indices for this [Buffer].
|
||||||
|
*/
|
||||||
|
public val <T> Buffer<T>.indices: IntRange get() = 0 until size
|
||||||
|
|
||||||
|
public operator fun <T> Buffer<T>.get(index: UInt): T = get(index.toInt())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if index is in range of buffer, return the value. Otherwise, return null.
|
* if index is in range of buffer, return the value. Otherwise, return null.
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer that wraps an original buffer
|
||||||
|
*/
|
||||||
|
public interface BufferView<T> : Buffer<T> {
|
||||||
|
public val origin: Buffer<T>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index in [origin] buffer from index in this buffer.
|
||||||
|
* Return -1 if element not present in the original buffer
|
||||||
|
* This method should be used internally to optimize non-boxing access.
|
||||||
|
*/
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun originIndex(index: Int): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zero-copy buffer that "sees" only part of original buffer. Slice can't go beyond original buffer borders.
|
||||||
|
*/
|
||||||
|
public class BufferSlice<T>(
|
||||||
|
override val origin: Buffer<T>,
|
||||||
|
public val offset: UInt = 0U,
|
||||||
|
override val size: Int,
|
||||||
|
) : BufferView<T> {
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(size > 0) { "Size must be positive" }
|
||||||
|
require(offset + size.toUInt() <= origin.size.toUInt()) {
|
||||||
|
"End of buffer ${offset + size.toUInt()} is beyond the end of origin buffer size ${origin.size}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(index: Int): T = if (index >= size) {
|
||||||
|
throw IndexOutOfBoundsException("$index is out of ${0 until size} rage")
|
||||||
|
} else {
|
||||||
|
origin[index.toUInt() + offset]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<T> =
|
||||||
|
(offset until (offset + size.toUInt())).asSequence().map { origin[it] }.iterator()
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
override fun originIndex(index: Int): Int = if (index >= size) -1 else index - offset.toInt()
|
||||||
|
|
||||||
|
override fun toString(): String = "$origin[$offset..${offset + size.toUInt()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An expanded buffer that could include the whole initial buffer ot its part and fills all space beyond it borders with [defaultValue].
|
||||||
|
*
|
||||||
|
* The [offset] parameter shows the shift of expanded buffer start relative to origin start and could be both positive and negative.
|
||||||
|
*/
|
||||||
|
public class BufferExpanded<T>(
|
||||||
|
override val origin: Buffer<T>,
|
||||||
|
public val defaultValue: T,
|
||||||
|
public val offset: Int = 0,
|
||||||
|
override val size: Int = origin.size,
|
||||||
|
) : BufferView<T> {
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(size > 0) { "Size must be positive" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(index: Int): T = when (index) {
|
||||||
|
!in 0 until size -> throw IndexOutOfBoundsException("Index $index is not in $indices")
|
||||||
|
in -offset until origin.size - offset -> origin[index + offset]
|
||||||
|
else -> defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
override fun originIndex(index: Int): Int = if (index in -offset until origin.size - offset) index + offset else -1
|
||||||
|
|
||||||
|
override fun toString(): String = "$origin[$offset..${offset + size}]"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zero-copy select a slice inside the original buffer
|
||||||
|
*/
|
||||||
|
public fun <T> Buffer<T>.slice(range: UIntRange): BufferView<T> = BufferSlice(
|
||||||
|
this,
|
||||||
|
range.first,
|
||||||
|
(range.last - range.first).toInt() + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize original buffer to a given range using given [range], filling additional segments with [defaultValue].
|
||||||
|
* Range left border could be negative to designate adding new blank segment to the beginning of the buffer
|
||||||
|
*/
|
||||||
|
public fun <T> Buffer<T>.expand(
|
||||||
|
range: IntRange,
|
||||||
|
defaultValue: T,
|
||||||
|
): BufferView<T> = if (range.first >= 0 && range.last < size) {
|
||||||
|
BufferSlice(
|
||||||
|
this,
|
||||||
|
range.first.toUInt(),
|
||||||
|
(range.last - range.first) + 1
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
BufferExpanded(
|
||||||
|
this,
|
||||||
|
defaultValue,
|
||||||
|
range.first,
|
||||||
|
(range.last - range.first) + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [BufferView] that overrides indexing of the original buffer
|
||||||
|
*/
|
||||||
|
public class PermutatedBuffer<T>(
|
||||||
|
override val origin: Buffer<T>,
|
||||||
|
private val permutations: IntArray,
|
||||||
|
) : BufferView<T> {
|
||||||
|
init {
|
||||||
|
permutations.forEach { index ->
|
||||||
|
if (index !in origin.indices) {
|
||||||
|
throw IndexOutOfBoundsException("Index $index is not in ${origin.indices}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val size: Int get() = permutations.size
|
||||||
|
|
||||||
|
override fun get(index: Int): T = origin[permutations[index]]
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<T> = permutations.asSequence().map { origin[it] }.iterator()
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
override fun originIndex(index: Int): Int = if (index in permutations.indices) permutations[index] else -1
|
||||||
|
|
||||||
|
override fun toString(): String = Buffer.toString(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created a permuted view of given buffer using provided [indices]
|
||||||
|
*/
|
||||||
|
public fun <T> Buffer<T>.view(indices: IntArray): PermutatedBuffer<T> = PermutatedBuffer(this, indices)
|
@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline
|
|||||||
* @property array the underlying array.
|
* @property array the underlying array.
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer<Double> {
|
public value class DoubleBuffer(public val array: DoubleArray) : PrimitiveBuffer<Double> {
|
||||||
override val size: Int get() = array.size
|
override val size: Int get() = array.size
|
||||||
|
|
||||||
override operator fun get(index: Int): Double = array[index]
|
override operator fun get(index: Int): Double = array[index]
|
||||||
|
@ -14,7 +14,7 @@ import kotlin.jvm.JvmInline
|
|||||||
* @author Iaroslav Postovalov
|
* @author Iaroslav Postovalov
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class FloatBuffer(public val array: FloatArray) : MutableBuffer<Float> {
|
public value class FloatBuffer(public val array: FloatArray) : PrimitiveBuffer<Float> {
|
||||||
override val size: Int get() = array.size
|
override val size: Int get() = array.size
|
||||||
|
|
||||||
override operator fun get(index: Int): Float = array[index]
|
override operator fun get(index: Int): Float = array[index]
|
||||||
|
@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline
|
|||||||
* @property array the underlying array.
|
* @property array the underlying array.
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class IntBuffer(public val array: IntArray) : MutableBuffer<Int> {
|
public value class IntBuffer(public val array: IntArray) : PrimitiveBuffer<Int> {
|
||||||
override val size: Int get() = array.size
|
override val size: Int get() = array.size
|
||||||
|
|
||||||
override operator fun get(index: Int): Int = array[index]
|
override operator fun get(index: Int): Int = array[index]
|
||||||
|
@ -13,7 +13,7 @@ import kotlin.jvm.JvmInline
|
|||||||
* @property array the underlying array.
|
* @property array the underlying array.
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class LongBuffer(public val array: LongArray) : MutableBuffer<Long> {
|
public value class LongBuffer(public val array: LongArray) : PrimitiveBuffer<Long> {
|
||||||
override val size: Int get() = array.size
|
override val size: Int get() = array.size
|
||||||
|
|
||||||
override operator fun get(index: Int): Long = array[index]
|
override operator fun get(index: Int): Long = array[index]
|
||||||
|
@ -95,3 +95,6 @@ public interface MutableBuffer<T> : Buffer<T> {
|
|||||||
auto(T::class, size, initializer)
|
auto(T::class, size, initializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public sealed interface PrimitiveBuffer<T>: MutableBuffer<T>
|
@ -3,10 +3,9 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.operations
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.structures.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typealias for buffer transformations.
|
* Typealias for buffer transformations.
|
||||||
@ -104,3 +103,39 @@ public inline fun <T1, T2, reified R : Any> Buffer<T1>.zip(
|
|||||||
require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" }
|
require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" }
|
||||||
return bufferFactory(size) { transform(get(it), other[it]) }
|
return bufferFactory(size) { transform(get(it), other[it]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simular to https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/binary-search.html.
|
||||||
|
* The implementation is copied from Kotlin stdlib
|
||||||
|
*/
|
||||||
|
public fun <T : Comparable<T>> Buffer<T>.binarySearch(element: T, fromIndex: Int = 0, toIndex: Int = size): Int {
|
||||||
|
var low = fromIndex
|
||||||
|
var high = toIndex - 1
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
val mid = (low + high).ushr(1) // safe from overflows
|
||||||
|
val midVal = get(mid)
|
||||||
|
val cmp = compareValues(midVal, element)
|
||||||
|
|
||||||
|
when {
|
||||||
|
cmp < 0 -> low = mid + 1
|
||||||
|
cmp > 0 -> high = mid - 1
|
||||||
|
else -> return mid // key found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -(low + 1) // key not found
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a buffer containing sorted elements of this buffer.
|
||||||
|
*/
|
||||||
|
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||||
|
public fun <T : Comparable<T>> Buffer<T>.sorted(): Buffer<T> = when (this) {
|
||||||
|
is PrimitiveBuffer -> when (this) {
|
||||||
|
is LongBuffer -> toLongArray().apply { sort() } as Buffer<T>
|
||||||
|
is FloatBuffer -> toFloatArray().apply { sort() } as Buffer<T>
|
||||||
|
is IntBuffer -> toIntArray().apply { sort() } as Buffer<T>
|
||||||
|
is DoubleBuffer -> toDoubleArray().apply { sort() } as Buffer<T>
|
||||||
|
}
|
||||||
|
else -> asIterable().sorted().asBuffer()
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFails
|
||||||
|
|
||||||
|
internal class BufferExpandedTest {
|
||||||
|
private val buffer = (0..100).toList().asBuffer()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun shrink(){
|
||||||
|
val view = buffer.slice(20U..30U)
|
||||||
|
assertEquals(20, view[0])
|
||||||
|
assertEquals(30, view[10])
|
||||||
|
assertFails { view[11] }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun expandNegative(){
|
||||||
|
val view: BufferView<Int> = buffer.expand(-20..113,0)
|
||||||
|
assertEquals(0,view[4])
|
||||||
|
assertEquals(0,view[123])
|
||||||
|
assertEquals(100, view[120])
|
||||||
|
assertFails { view[-2] }
|
||||||
|
assertFails { view[134] }
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ package space.kscience.kmath.streaming
|
|||||||
|
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import space.kscience.kmath.operations.asSequence
|
import space.kscience.kmath.structures.asSequence
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ import space.kscience.kmath.misc.PerformancePitfall
|
|||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.operations.DoubleField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.operations.algebra
|
import space.kscience.kmath.operations.algebra
|
||||||
import space.kscience.kmath.operations.asIterable
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -11,6 +11,7 @@ import space.kscience.kmath.operations.DoubleL2Norm
|
|||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer.Companion.double
|
import space.kscience.kmath.structures.MutableBuffer.Companion.double
|
||||||
import space.kscience.kmath.structures.asBuffer
|
import space.kscience.kmath.structures.asBuffer
|
||||||
|
import space.kscience.kmath.structures.indices
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
public typealias DoubleVector = Point<Double>
|
public typealias DoubleVector = Point<Double>
|
||||||
|
@ -8,6 +8,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI
|
|||||||
import space.kscience.kmath.operations.Field
|
import space.kscience.kmath.operations.Field
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.asBuffer
|
import space.kscience.kmath.structures.asBuffer
|
||||||
|
import space.kscience.kmath.structures.indices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple one-pass integrator based on Gauss rule
|
* A simple one-pass integrator based on Gauss rule
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.integration
|
package space.kscience.kmath.integration
|
||||||
|
|
||||||
import space.kscience.kmath.operations.map
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.asBuffer
|
import space.kscience.kmath.structures.asBuffer
|
||||||
|
import space.kscience.kmath.structures.map
|
||||||
import kotlin.jvm.Synchronized
|
import kotlin.jvm.Synchronized
|
||||||
import kotlin.math.ulp
|
import kotlin.math.ulp
|
||||||
import kotlin.native.concurrent.ThreadLocal
|
import kotlin.native.concurrent.ThreadLocal
|
||||||
|
@ -12,10 +12,14 @@ import space.kscience.kmath.interpolation.SplineInterpolator
|
|||||||
import space.kscience.kmath.interpolation.interpolatePolynomials
|
import space.kscience.kmath.interpolation.interpolatePolynomials
|
||||||
import space.kscience.kmath.misc.PerformancePitfall
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
import space.kscience.kmath.operations.Field
|
||||||
|
import space.kscience.kmath.operations.invoke
|
||||||
|
import space.kscience.kmath.operations.sum
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import space.kscience.kmath.structures.MutableBufferFactory
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
import space.kscience.kmath.structures.map
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact
|
* Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package space.kscience.kmath.geometry
|
package space.kscience.kmath.geometry
|
||||||
|
|
||||||
import space.kscience.kmath.operations.toList
|
|
||||||
|
import space.kscience.kmath.structures.toList
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package space.kscience.kmath.geometry
|
package space.kscience.kmath.geometry
|
||||||
|
|
||||||
import space.kscience.kmath.operations.toList
|
import space.kscience.kmath.structures.toList
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ package space.kscience.kmath.histogram
|
|||||||
|
|
||||||
import space.kscience.kmath.domains.UnivariateDomain
|
import space.kscience.kmath.domains.UnivariateDomain
|
||||||
import space.kscience.kmath.misc.UnstableKMathAPI
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.operations.asSequence
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.asSequence
|
||||||
|
|
||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
|
@ -21,9 +21,9 @@ import space.kscience.kmath.expressions.MST
|
|||||||
import space.kscience.kmath.expressions.MstRing
|
import space.kscience.kmath.expressions.MstRing
|
||||||
import space.kscience.kmath.misc.PerformancePitfall
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
import space.kscience.kmath.nd.Structure2D
|
import space.kscience.kmath.nd.Structure2D
|
||||||
import space.kscience.kmath.operations.asSequence
|
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.asSequence
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function for conversion of number to MST for pretty print
|
* A function for conversion of number to MST for pretty print
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
package space.kscience.kmath.distributions
|
package space.kscience.kmath.distributions
|
||||||
|
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
|
import space.kscience.kmath.samplers.Sampler
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A distribution of typed objects.
|
* A distribution of typed objects.
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
package space.kscience.kmath.distributions
|
package space.kscience.kmath.distributions
|
||||||
|
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.internal.InternalErf
|
|
||||||
import space.kscience.kmath.samplers.GaussianSampler
|
import space.kscience.kmath.samplers.GaussianSampler
|
||||||
|
import space.kscience.kmath.samplers.InternalErf
|
||||||
import space.kscience.kmath.samplers.NormalizedGaussianSampler
|
import space.kscience.kmath.samplers.NormalizedGaussianSampler
|
||||||
import space.kscience.kmath.samplers.ZigguratNormalizedGaussianSampler
|
import space.kscience.kmath.samplers.ZigguratNormalizedGaussianSampler
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
@ -3,12 +3,11 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.stat
|
package space.kscience.kmath.distributions
|
||||||
|
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.chains.SimpleChain
|
import space.kscience.kmath.chains.SimpleChain
|
||||||
import space.kscience.kmath.distributions.Distribution
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.distributions.UnivariateDistribution
|
|
||||||
|
|
||||||
public class UniformDistribution(public val range: ClosedFloatingPointRange<Double>) : UnivariateDistribution<Double> {
|
public class UniformDistribution(public val range: ClosedFloatingPointRange<Double>) : UnivariateDistribution<Double> {
|
||||||
private val length: Double = range.endInclusive - range.start
|
private val length: Double = range.endInclusive - range.start
|
@ -7,7 +7,6 @@ package space.kscience.kmath.samplers
|
|||||||
|
|
||||||
import space.kscience.kmath.chains.BlockingDoubleChain
|
import space.kscience.kmath.chains.BlockingDoubleChain
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
import space.kscience.kmath.structures.DoubleBuffer
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
import kotlin.math.ln
|
import kotlin.math.ln
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -67,7 +66,7 @@ public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler<D
|
|||||||
var qi = 0.0
|
var qi = 0.0
|
||||||
|
|
||||||
DoubleArray(16) { i ->
|
DoubleArray(16) { i ->
|
||||||
qi += ln2.pow(i + 1.0) / space.kscience.kmath.internal.InternalUtils.factorial(i + 1)
|
qi += ln2.pow(i + 1.0) / InternalUtils.factorial(i + 1)
|
||||||
qi
|
qi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,7 @@ package space.kscience.kmath.samplers
|
|||||||
|
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
import space.kscience.kmath.stat.chain
|
import space.kscience.kmath.stat.chain
|
||||||
import space.kscience.kmath.stat.next
|
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
package space.kscience.kmath.samplers
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.internal.InternalUtils
|
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
import space.kscience.kmath.stat.chain
|
import space.kscience.kmath.stat.chain
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.internal
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.internal
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.internal
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import kotlin.math.ln
|
import kotlin.math.ln
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
@ -7,7 +7,6 @@ package space.kscience.kmath.samplers
|
|||||||
|
|
||||||
import space.kscience.kmath.chains.BlockingIntChain
|
import space.kscience.kmath.chains.BlockingIntChain
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
import space.kscience.kmath.structures.IntBuffer
|
import space.kscience.kmath.structures.IntBuffer
|
||||||
import kotlin.math.exp
|
import kotlin.math.exp
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ package space.kscience.kmath.samplers
|
|||||||
|
|
||||||
import space.kscience.kmath.chains.BlockingDoubleChain
|
import space.kscience.kmath.chains.BlockingDoubleChain
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
|
|
||||||
public interface BlockingDoubleSampler: Sampler<Double>{
|
public interface BlockingDoubleSampler: Sampler<Double>{
|
||||||
override fun sample(generator: RandomGenerator): BlockingDoubleChain
|
override fun sample(generator: RandomGenerator): BlockingDoubleChain
|
||||||
|
@ -6,10 +6,8 @@
|
|||||||
package space.kscience.kmath.samplers
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import space.kscience.kmath.chains.BlockingIntChain
|
import space.kscience.kmath.chains.BlockingIntChain
|
||||||
import space.kscience.kmath.internal.InternalUtils
|
|
||||||
import space.kscience.kmath.misc.toIntExact
|
import space.kscience.kmath.misc.toIntExact
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
|
||||||
import space.kscience.kmath.structures.IntBuffer
|
import space.kscience.kmath.structures.IntBuffer
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
|
@ -3,12 +3,16 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.stat
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.chains.collect
|
import space.kscience.kmath.chains.collect
|
||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
|
import space.kscience.kmath.structures.DoubleBuffer
|
||||||
|
import space.kscience.kmath.structures.IntBuffer
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
/**
|
/**
|
@ -3,7 +3,7 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* 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.stat
|
package space.kscience.kmath.samplers
|
||||||
|
|
||||||
import space.kscience.kmath.chains.Chain
|
import space.kscience.kmath.chains.Chain
|
||||||
import space.kscience.kmath.chains.ConstantChain
|
import space.kscience.kmath.chains.ConstantChain
|
||||||
@ -12,6 +12,7 @@ import space.kscience.kmath.chains.zip
|
|||||||
import space.kscience.kmath.operations.Group
|
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
|
||||||
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements [Sampler] by sampling only certain [value].
|
* Implements [Sampler] by sampling only certain [value].
|
@ -1,80 +1,125 @@
|
|||||||
package space.kscience.kmath.series
|
package space.kscience.kmath.series
|
||||||
|
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.BufferAlgebra
|
||||||
|
import space.kscience.kmath.operations.Ring
|
||||||
|
import space.kscience.kmath.operations.RingOps
|
||||||
|
import space.kscience.kmath.stat.StatisticalAlgebra
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferView
|
||||||
import space.kscience.kmath.structures.getOrNull
|
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
private fun IntRange.intersect(other: IntRange): IntRange =
|
@PublishedApi
|
||||||
|
internal fun IntRange.intersect(other: IntRange): IntRange =
|
||||||
max(first, other.first)..min(last, other.last)
|
max(first, other.first)..min(last, other.last)
|
||||||
|
|
||||||
private val IntRange.size get() = last - first + 1
|
@PublishedApi
|
||||||
|
internal val IntRange.size
|
||||||
|
get() = last - first + 1
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal operator fun IntRange.contains(other: IntRange): Boolean = (other.first in this) && (other.last in this)
|
||||||
|
|
||||||
|
//TODO add permutated buffer
|
||||||
|
//TODO add rank function
|
||||||
|
|
||||||
|
|
||||||
|
public interface Series<T> : Buffer<T> {
|
||||||
|
public val origin: Buffer<T>
|
||||||
|
/**
|
||||||
|
* Absolute position of start of this [Series] in [SeriesAlgebra]
|
||||||
|
*/
|
||||||
|
public val position: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
public val <T> Series<T>.absoluteIndices: IntRange get() = position until position + size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [BufferView] with index offset (both positive and negative) and possible size change
|
||||||
|
*/
|
||||||
|
private class OffsetBufer<T>(
|
||||||
|
override val origin: Buffer<T>,
|
||||||
|
override val position: Int,
|
||||||
|
override val size: Int = origin.size,
|
||||||
|
) : Series<T>, Buffer<T> by origin {
|
||||||
|
|
||||||
private class BufferView<T>(val buffer: Buffer<T>, val offset: Int, override val size: Int) : Buffer<T> {
|
|
||||||
init {
|
init {
|
||||||
require(offset >= 0) { " Range offset must be positive" }
|
|
||||||
require(offset < buffer.size) { "Range offset is beyond the buffer size" }
|
|
||||||
require(size > 0) { "Size must be positive" }
|
require(size > 0) { "Size must be positive" }
|
||||||
require(size < buffer.size) { "Slice size is larger than the buffer" }
|
require(size <= origin.size) { "Slice size is larger than the original buffer" }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(index: Int): T = buffer[index - offset]
|
override fun toString(): String = "$origin-->${position}"
|
||||||
|
|
||||||
override fun iterator(): Iterator<T> = buffer.asSequence().drop(offset).take(size).iterator()
|
|
||||||
|
|
||||||
override fun toString(): String = "$buffer[${offset}:${offset + size - 1}]"
|
|
||||||
|
|
||||||
override val indices: IntRange = offset until offset + size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scope to operation on series
|
* A scope to operation on series
|
||||||
*/
|
*/
|
||||||
public class SeriesAlgebra<T, A : Ring<T>, L>(
|
public class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>, L>(
|
||||||
public val bufferAlgebra: BufferRingOps<T, A>,
|
override val bufferAlgebra: BA,
|
||||||
private val labelResolver: (Int) -> L,
|
private val labelResolver: (Int) -> L,
|
||||||
) : RingOps<Buffer<T>> {
|
) : RingOps<Buffer<T>>, StatisticalAlgebra<T, A, BA> {
|
||||||
|
|
||||||
public val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
public val Buffer<T>.indices: IntRange
|
||||||
public val bufferFactory: BufferFactory<T> get() = bufferAlgebra.bufferFactory
|
get() = if (this is Series) {
|
||||||
|
absoluteIndices
|
||||||
|
} else {
|
||||||
|
0 until size
|
||||||
|
}
|
||||||
|
|
||||||
public val Buffer<T>.offset: UInt get() = indices.first.toUInt()
|
/**
|
||||||
|
* Get the value by absolute index in the series algebra or return null if index is out of range
|
||||||
|
*/
|
||||||
|
public fun Buffer<T>.getAbsoluteOrNull(index: Int): T? = when {
|
||||||
|
index !in indices -> null
|
||||||
|
this is Series -> origin[index - position]
|
||||||
|
else -> get(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value by absolute index in the series algebra or throw [IndexOutOfBoundsException] if index is out of range
|
||||||
|
*/
|
||||||
|
public fun Buffer<T>.getAbsolute(index: Int): T =
|
||||||
|
getAbsoluteOrNull(index) ?: throw IndexOutOfBoundsException("Index $index is not in $indices")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an offset series with index starting point at [index]
|
||||||
|
*/
|
||||||
|
public fun Buffer<T>.moveTo(index: Int): Series<T> = if (this is Series) {
|
||||||
|
OffsetBufer(origin, index, size)
|
||||||
|
} else {
|
||||||
|
OffsetBufer(this, index, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a buffer view using given absolute range
|
||||||
|
*/
|
||||||
|
public fun Buffer<T>.slice(range: IntRange): Series<T> {
|
||||||
|
val size = range.size
|
||||||
|
return if (this is Series) {
|
||||||
|
OffsetBufer(this, indices.first + range.first, size)
|
||||||
|
} else {
|
||||||
|
OffsetBufer(this, range.first, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun Buffer<T>.expand(range: IntRange, defaultValue: T): Series<T> = if (range in indices) {
|
||||||
|
slice(range)
|
||||||
|
} else {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
public val Buffer<T>.offset: Int get() = if (this is Series) position else 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a new series
|
* Build a new series
|
||||||
*/
|
*/
|
||||||
public fun series(size: Int, fromIndex: Int = 0, block: A.(label: L) -> T): Buffer<T> {
|
public fun series(size: Int, fromIndex: Int = 0, block: A.(label: L) -> T): Series<T> {
|
||||||
return bufferFactory(size) {
|
return bufferFactory(size) {
|
||||||
val index = it + fromIndex
|
val index = it + fromIndex
|
||||||
elementAlgebra.block(labelResolver(index))
|
elementAlgebra.block(labelResolver(index))
|
||||||
}.moveTo(fromIndex)
|
}.moveTo(fromIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Move a series starting to start at a given index
|
|
||||||
*/
|
|
||||||
public fun Buffer<T>.moveTo(index: Int): Buffer<T> = if (index == 0) {
|
|
||||||
this
|
|
||||||
} else if (this is BufferView) {
|
|
||||||
BufferView(buffer, index.toInt(), size)
|
|
||||||
} else {
|
|
||||||
BufferView(this, index.toInt(), size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a buffer view using given range
|
|
||||||
*/
|
|
||||||
public fun Buffer<T>.get(range: IntRange): Buffer<T> {
|
|
||||||
val size = range.size
|
|
||||||
return if (this is BufferView) {
|
|
||||||
BufferView(this, indices.first + range.first, size)
|
|
||||||
} else {
|
|
||||||
BufferView(this, range.first, size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a label buffer for given buffer.
|
* Get a label buffer for given buffer.
|
||||||
*/
|
*/
|
||||||
@ -87,34 +132,15 @@ public class SeriesAlgebra<T, A : Ring<T>, L>(
|
|||||||
public operator fun Buffer<T>.get(label: L): T? {
|
public operator fun Buffer<T>.get(label: L): T? {
|
||||||
val index = labels.indexOf(label)
|
val index = labels.indexOf(label)
|
||||||
if (index == -1) return null
|
if (index == -1) return null
|
||||||
return get(index + offset.toInt())
|
return getAbsolute(index + offset.toInt())
|
||||||
}
|
|
||||||
|
|
||||||
override fun add(left: Buffer<T>, right: Buffer<T>): Buffer<T> = elementAlgebra.invoke {
|
|
||||||
val newRange = left.indices.intersect(right.indices)
|
|
||||||
//TODO optimize copy at BufferAlgebra level
|
|
||||||
bufferFactory(newRange.size) {
|
|
||||||
val offset = it + newRange.first
|
|
||||||
left[offset] + right[offset]
|
|
||||||
}.moveTo(newRange.first)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun Buffer<T>.unaryMinus(): Buffer<T> = map { -it }
|
|
||||||
|
|
||||||
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = elementAlgebra.invoke {
|
|
||||||
val newRange = left.indices.intersect(right.indices)
|
|
||||||
bufferFactory(newRange.size) {
|
|
||||||
val offset = it + newRange.first
|
|
||||||
left[offset] * right[offset]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map a series to another series of the same size
|
* Map a series to another series of the same size
|
||||||
*/
|
*/
|
||||||
public inline fun Buffer<T>.map(crossinline transform: A.(T) -> T): Buffer<T> {
|
public inline fun Buffer<T>.map(crossinline transform: A.(T) -> T): Series<T> {
|
||||||
val buf = bufferFactory(size) {
|
val buf = bufferFactory(size) {
|
||||||
elementAlgebra.transform(get(it))
|
elementAlgebra.transform(getAbsolute(it))
|
||||||
}
|
}
|
||||||
return buf.moveTo(indices.first)
|
return buf.moveTo(indices.first)
|
||||||
}
|
}
|
||||||
@ -122,49 +148,63 @@ public class SeriesAlgebra<T, A : Ring<T>, L>(
|
|||||||
/**
|
/**
|
||||||
* Map series to another series of the same size with label
|
* Map series to another series of the same size with label
|
||||||
*/
|
*/
|
||||||
public inline fun Buffer<T>.mapWithLabel(crossinline transform: A.(arg: T, label: L) -> T): Buffer<T> {
|
public inline fun Buffer<T>.mapWithLabel(crossinline transform: A.(arg: T, label: L) -> T): Series<T> {
|
||||||
val labels = labels
|
val labels = labels
|
||||||
val buf = bufferFactory(size) {
|
val buf = bufferFactory(size) {
|
||||||
elementAlgebra.transform(get(it), labels[it])
|
elementAlgebra.transform(getAbsolute(it), labels[it])
|
||||||
}
|
}
|
||||||
return buf.moveTo(indices.first)
|
return buf.moveTo(indices.first)
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <R> Buffer<T>.fold(initial: R, operation: A.(acc: R, T) -> R): R {
|
public inline fun <R> Buffer<T>.fold(initial: R, operation: A.(acc: R, T) -> R): R {
|
||||||
var accumulator = initial
|
var accumulator = initial
|
||||||
for (index in this.indices) accumulator = elementAlgebra.operation(accumulator, get(index))
|
for (index in this.indices) accumulator = elementAlgebra.operation(accumulator, getAbsolute(index))
|
||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <R> Buffer<T>.foldWithLabel(initial: R, operation: A.(acc: R, arg: T, label: L) -> R): R {
|
public inline fun <R> Buffer<T>.foldWithLabel(initial: R, operation: A.(acc: R, arg: T, label: L) -> R): R {
|
||||||
val labels = labels
|
val labels = labels
|
||||||
var accumulator = initial
|
var accumulator = initial
|
||||||
for (index in this.indices) accumulator = elementAlgebra.operation(accumulator, get(index), labels[index])
|
for (index in this.indices) accumulator =
|
||||||
|
elementAlgebra.operation(accumulator, getAbsolute(index), labels[index])
|
||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zip two buffers replacing missing values with [defaultValue]
|
* Zip two buffers in the range whe they overlap
|
||||||
*/
|
*/
|
||||||
public inline fun Buffer<T>.zip(
|
public inline fun Buffer<T>.zip(
|
||||||
other: Buffer<T>,
|
other: Buffer<T>,
|
||||||
defaultValue: T,
|
crossinline operation: A.(left: T, right: T) -> T,
|
||||||
crossinline operation: A.(left: T?, right: T?) -> T?,
|
): Series<T> {
|
||||||
): Buffer<T> {
|
val newRange = indices.intersect(other.indices)
|
||||||
val start = min(indices.first, other.indices.first)
|
return bufferFactory(newRange.size) {
|
||||||
val size = max(indices.last, other.indices.last) - start
|
|
||||||
return bufferFactory(size) {
|
|
||||||
elementAlgebra.operation(
|
elementAlgebra.operation(
|
||||||
getOrNull(it) ?: defaultValue,
|
getAbsolute(it),
|
||||||
other.getOrNull(it) ?: defaultValue
|
other.getAbsolute(it)
|
||||||
) ?: defaultValue
|
)
|
||||||
}
|
}.moveTo(newRange.first)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun Buffer<T>.unaryMinus(): Buffer<T> = map { -it }
|
||||||
|
|
||||||
|
override fun add(left: Buffer<T>, right: Buffer<T>): Series<T> = left.zip(right) { l, r -> l + r }
|
||||||
|
|
||||||
|
override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = left.zip(right) { l, r -> l * r }
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <T, A : Ring<T>, L> BufferRingOps<T, A>.seriesAlgebra(labels: Iterable<L>): SeriesAlgebra<T, A, L> {
|
public fun <T, A : Ring<T>, BA : BufferAlgebra<T, A>, L> BA.seriesAlgebra(labels: Iterable<L>): SeriesAlgebra<T, A, BA, L> {
|
||||||
val l = labels.toList()
|
val l = labels.toList()
|
||||||
return SeriesAlgebra(this) {
|
return SeriesAlgebra(this) {
|
||||||
if (it in l.indices) l[it] else error("Index $it is outside of labels range ${l.indices}")
|
if (it in l.indices) l[it] else error("Index $it is outside of labels range ${l.indices}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun <T, A : Ring<T>, BA : BufferAlgebra<T, A>, L> BA.seriesAlgebra(labelGenerator: (Int) -> L): SeriesAlgebra<T, A, BA, L> =
|
||||||
|
SeriesAlgebra(this, labelGenerator)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a series algebra using offset as a label
|
||||||
|
*/
|
||||||
|
public fun <T, A : Ring<T>, BA : BufferAlgebra<T, A>> BA.seriesAlgebra(): SeriesAlgebra<T, A, BA, Int> =
|
||||||
|
SeriesAlgebra(this) { it }
|
@ -0,0 +1,97 @@
|
|||||||
|
package space.kscience.kmath.series
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.BufferAlgebra
|
||||||
|
import space.kscience.kmath.operations.ExponentialOperations
|
||||||
|
import space.kscience.kmath.operations.PowerOperations
|
||||||
|
import space.kscience.kmath.operations.TrigonometricOperations
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
|
||||||
|
|
||||||
|
//trigonometric
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.sin(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : TrigonometricOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.sin(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.cos(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : TrigonometricOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.cos(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.tan(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : TrigonometricOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.tan(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.asin(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : TrigonometricOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.asin(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.acos(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : TrigonometricOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.acos(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.atan(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : TrigonometricOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.atan(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
|
||||||
|
//exponential
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.exp(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.exp(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.ln(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.ln(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.sinh(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.sinh(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.cosh(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.cosh(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.tanh(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.tanh(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.asinh(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.asinh(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.acosh(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.acosh(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.atanh(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : ExponentialOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.atanh(arg).moveTo(arg.offset)
|
||||||
|
|
||||||
|
|
||||||
|
//power
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.power(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
pow: Number,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : PowerOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.power(arg, pow).moveTo(arg.offset)
|
||||||
|
|
||||||
|
public fun <T, BA> SeriesAlgebra<T, *, BA, *>.sqrt(
|
||||||
|
arg: Buffer<T>,
|
||||||
|
): Series<T> where BA : BufferAlgebra<T, *>, BA : PowerOperations<Buffer<T>> =
|
||||||
|
bufferAlgebra.sqrt(arg).moveTo(arg.offset)
|
@ -7,6 +7,7 @@ package space.kscience.kmath.stat
|
|||||||
|
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.indices
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arithmetic mean
|
* Arithmetic mean
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.stat
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
import space.kscience.kmath.operations.asSequence
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.asSequence
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-composable median
|
* Non-composable median
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
|
|
||||||
|
public class Rank<T: Comparable<T>>: BlockingStatistic<T, IntArray> {
|
||||||
|
override fun evaluateBlocking(data: Buffer<T>): IntArray {
|
||||||
|
// https://www.geeksforgeeks.org/rank-elements-array/
|
||||||
|
val permutations = ArrayList<Pair<T, Int>>(data.size)
|
||||||
|
data.asIterable().mapIndexedTo(permutations) { i, v -> v to i }
|
||||||
|
permutations.sortBy { it.first }
|
||||||
|
var rank = 1
|
||||||
|
var i = 0
|
||||||
|
val r = IntArray(data.size) { 0 }
|
||||||
|
while (i < data.size) {
|
||||||
|
var j = i
|
||||||
|
while (j < data.size - 1 && permutations[j].first == permutations[j + 1]) ++j
|
||||||
|
val n = j - i + 1
|
||||||
|
(0 until n).map { k ->
|
||||||
|
val idx = permutations[i + k].second
|
||||||
|
r[idx] = rank + ((n - 1) * 0.5f).toInt()
|
||||||
|
}
|
||||||
|
rank += n
|
||||||
|
i += n
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.*
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
|
import space.kscience.kmath.structures.asIterable
|
||||||
|
import space.kscience.kmath.structures.sorted
|
||||||
|
|
||||||
|
public interface StatisticalAlgebra<T, out A : Algebra<T>, out BA : BufferAlgebra<T, A>> : Algebra<Buffer<T>> {
|
||||||
|
public val bufferAlgebra: BA
|
||||||
|
public val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
||||||
|
public val bufferFactory: BufferFactory<T> get() = bufferAlgebra.bufferFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute [empirical CDF function](https://en.wikipedia.org/wiki/Empirical_distribution_function)
|
||||||
|
*/
|
||||||
|
public fun <T : Comparable<T>> StatisticalAlgebra<T, *, *>.ecdf(buffer: Buffer<T>): (T) -> Double = { arg ->
|
||||||
|
buffer.asIterable().count { it < arg }.toDouble() / buffer.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation copied from https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/index.html?org/apache/commons/math3/stat/inference/KolmogorovSmirnovTest.html
|
||||||
|
*/
|
||||||
|
public fun <T : Comparable<T>, A, BA : BufferAlgebra<T, A>> StatisticalAlgebra<T, A, BA>.kolmogorovSmirnovTest(
|
||||||
|
x: Buffer<T>,
|
||||||
|
y: Buffer<T>,
|
||||||
|
): T where A : Group<T>, A : NumericAlgebra<T> = elementAlgebra.invoke {
|
||||||
|
// Copy and sort the sample arrays
|
||||||
|
val sx = x.sorted()
|
||||||
|
val sy = y.sorted()
|
||||||
|
val n = sx.size
|
||||||
|
val m = sy.size
|
||||||
|
|
||||||
|
var rankX = 0
|
||||||
|
var rankY = 0
|
||||||
|
var curD: T = zero
|
||||||
|
|
||||||
|
// Find the max difference between cdf_x and cdf_y
|
||||||
|
var supD: T = zero
|
||||||
|
do {
|
||||||
|
val z = if (sx[rankX] <= sy[rankY]) sx[rankX] else sy[rankY]
|
||||||
|
while (rankX < n && sx[rankX].compareTo(z) == 0) {
|
||||||
|
rankX += 1;
|
||||||
|
curD += number(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (rankY < m && sy[rankY].compareTo(z) == 0) {
|
||||||
|
rankY += 1;
|
||||||
|
curD -= number(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
when {
|
||||||
|
curD > supD -> supD = curD
|
||||||
|
-curD > supD -> supD = -curD
|
||||||
|
}
|
||||||
|
} while (rankX < n && rankY < m);
|
||||||
|
return supD;
|
||||||
|
}
|
@ -6,6 +6,8 @@
|
|||||||
package space.kscience.kmath.stat
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import space.kscience.kmath.samplers.Sampler
|
||||||
|
import space.kscience.kmath.samplers.sampleBuffer
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
class SamplerTest {
|
class SamplerTest {
|
||||||
|
@ -15,6 +15,7 @@ import space.kscience.kmath.nd.as1D
|
|||||||
import space.kscience.kmath.nd.as2D
|
import space.kscience.kmath.nd.as2D
|
||||||
import space.kscience.kmath.operations.DoubleField
|
import space.kscience.kmath.operations.DoubleField
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
|
import space.kscience.kmath.structures.indices
|
||||||
import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra
|
import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra
|
||||||
import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra
|
import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra
|
||||||
import space.kscience.kmath.tensors.api.Tensor
|
import space.kscience.kmath.tensors.api.Tensor
|
||||||
|
@ -12,9 +12,9 @@ import space.kscience.kmath.nd.MutableStructure1D
|
|||||||
import space.kscience.kmath.nd.MutableStructure2D
|
import space.kscience.kmath.nd.MutableStructure2D
|
||||||
import space.kscience.kmath.nd.as1D
|
import space.kscience.kmath.nd.as1D
|
||||||
import space.kscience.kmath.nd.as2D
|
import space.kscience.kmath.nd.as2D
|
||||||
import space.kscience.kmath.operations.asSequence
|
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.structures.VirtualBuffer
|
import space.kscience.kmath.structures.VirtualBuffer
|
||||||
|
import space.kscience.kmath.structures.asSequence
|
||||||
import space.kscience.kmath.tensors.core.BufferedTensor
|
import space.kscience.kmath.tensors.core.BufferedTensor
|
||||||
import space.kscience.kmath.tensors.core.DoubleTensor
|
import space.kscience.kmath.tensors.core.DoubleTensor
|
||||||
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
package space.kscience.kmath.tensors.core.internal
|
package space.kscience.kmath.tensors.core.internal
|
||||||
|
|
||||||
import space.kscience.kmath.nd.as1D
|
import space.kscience.kmath.nd.as1D
|
||||||
import space.kscience.kmath.operations.toMutableList
|
|
||||||
import space.kscience.kmath.samplers.GaussianSampler
|
import space.kscience.kmath.samplers.GaussianSampler
|
||||||
import space.kscience.kmath.stat.RandomGenerator
|
import space.kscience.kmath.stat.RandomGenerator
|
||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.structures.*
|
||||||
|
Loading…
Reference in New Issue
Block a user