Add time series example stub

This commit is contained in:
Alexander Nozik 2023-03-10 22:50:41 +03:00
parent a3963ac4f5
commit 72c7030297
4 changed files with 82 additions and 9 deletions

View File

@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
plugins { plugins {
kotlin("jvm") kotlin("jvm")
} }
@ -33,6 +35,8 @@ dependencies {
implementation(project(":kmath-multik")) implementation(project(":kmath-multik"))
implementation("org.jetbrains.kotlinx:multik-default:$multikVersion") implementation("org.jetbrains.kotlinx:multik-default:$multikVersion")
//datetime
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
implementation("org.nd4j:nd4j-native:1.0.0-beta7") implementation("org.nd4j:nd4j-native:1.0.0-beta7")
@ -46,9 +50,6 @@ dependencies {
// } else // } else
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
// multik implementation
implementation("org.jetbrains.kotlinx:multik-default:0.1.0")
implementation("org.slf4j:slf4j-simple:1.7.32") implementation("org.slf4j:slf4j-simple:1.7.32")
// plotting // plotting
implementation("space.kscience:plotlykt-server:0.5.0") implementation("space.kscience:plotlykt-server:0.5.0")
@ -62,7 +63,7 @@ kotlin.sourceSets.all {
} }
} }
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> { tasks.withType<KotlinJvmCompile> {
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy"

View File

@ -0,0 +1,19 @@
/*
* Copyright 2018-2023 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.stat
import kotlinx.datetime.Instant
import space.kscience.kmath.operations.algebra
import space.kscience.kmath.operations.bufferAlgebra
import space.kscience.kmath.series.MonotonicSeriesAlgebra
import space.kscience.kmath.series.SeriesAlgebra
import kotlin.time.Duration
fun SeriesAlgebra.Companion.time(zero: Instant, step: Duration) = MonotonicSeriesAlgebra(
bufferAlgebra = Double.algebra.bufferAlgebra,
offsetToLabel = { zero + step * it },
labelToOffset = { (it - zero) / step }
)

View File

@ -0,0 +1,47 @@
/*
* Copyright 2018-2023 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.series
import space.kscience.kmath.operations.BufferAlgebra
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.structures.Buffer
import kotlin.math.ceil
import kotlin.math.floor
/**
* A [SeriesAlgebra] with reverse label to index transformation.
*
* @param [labelToOffset] returns floating point number that is used for index resolution.
*/
public class MonotonicSeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>, L : Comparable<L>>(
bufferAlgebra: BA,
offsetToLabel: (Int) -> L,
private val labelToOffset: (L) -> Double,
) : SeriesAlgebra<T, A, BA, L>(bufferAlgebra, offsetToLabel) {
public val Buffer<T>.labelRange: ClosedRange<L> get() = offsetToLabel(startOffset)..offsetToLabel(startOffset + size)
/**
* An offset of the given [label] rounded down
*/
public fun floorOffset(label: L): Int = floor(labelToOffset(label)).toInt()
/**
* An offset of the given [label] rounded up
*/
public fun ceilOffset(label: L): Int = ceil(labelToOffset(label)).toInt()
/**
* Get value by label (rounded down) or return null if the value is outside series boundaries.
*/
public fun Buffer<T>.getByLabelOrNull(label: L): T? = getByOffsetOrNull(floorOffset(label))
/**
* Get value by label (rounded down) or throw [IndexOutOfBoundsException] if the value is outside series boundaries.
*/
public fun Buffer<T>.getByLabel(label: L): T = getByLabelOrNull(label)
?: throw IndexOutOfBoundsException("Label $label is not in $labelRange")
}

View File

@ -24,7 +24,9 @@ internal operator fun IntRange.contains(other: IntRange): Boolean = (other.first
//TODO add permutation sort //TODO add permutation sort
//TODO check rank statistics //TODO check rank statistics
/**
* A [Buffer] with an offset relative to the [SeriesAlgebra] zero.
*/
public interface Series<T> : Buffer<T> { public interface Series<T> : Buffer<T> {
public val origin: Buffer<T> public val origin: Buffer<T>
@ -54,9 +56,9 @@ private class SeriesImpl<T>(
/** /**
* A scope to operation on series * A scope to operation on series
*/ */
public class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>, L>( public open class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>, L>(
override val bufferAlgebra: BA, override val bufferAlgebra: BA,
private val labelResolver: (Int) -> L, public val offsetToLabel: (Int) -> L,
) : RingOps<Buffer<T>>, StatisticalAlgebra<T, A, BA> { ) : RingOps<Buffer<T>>, StatisticalAlgebra<T, A, BA> {
/** /**
@ -107,20 +109,22 @@ public class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>, L>(
*/ */
public val Buffer<T>.startOffset: Int get() = if (this is Series) position else 0 public val Buffer<T>.startOffset: Int get() = if (this is Series) position else 0
public val Buffer<T>.startLabel: L get() = offsetToLabel(startOffset)
/** /**
* Build a new series positioned at [startOffset]. * Build a new series positioned at [startOffset].
*/ */
public fun series(size: Int, startOffset: Int = 0, block: A.(label: L) -> T): Series<T> { public fun series(size: Int, startOffset: Int = 0, block: A.(label: L) -> T): Series<T> {
return elementAlgebra.bufferFactory(size) { return elementAlgebra.bufferFactory(size) {
val index = it + startOffset val index = it + startOffset
elementAlgebra.block(labelResolver(index)) elementAlgebra.block(offsetToLabel(index))
}.moveTo(startOffset) }.moveTo(startOffset)
} }
/** /**
* Get a label buffer for given buffer. * Get a label buffer for given buffer.
*/ */
public val Buffer<T>.labels: List<L> get() = offsetIndices.map(labelResolver) public val Buffer<T>.labels: List<L> get() = offsetIndices.map(offsetToLabel)
/** /**
* Try to resolve element by label and return null if element with a given label is not found * Try to resolve element by label and return null if element with a given label is not found
@ -187,6 +191,8 @@ public class SeriesAlgebra<T, out A : Ring<T>, out BA : BufferAlgebra<T, A>, L>(
override fun add(left: Buffer<T>, right: Buffer<T>): Series<T> = left.zip(right) { l, r -> l + r } 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 } override fun multiply(left: Buffer<T>, right: Buffer<T>): Buffer<T> = left.zip(right) { l, r -> l * r }
public companion object
} }
public fun <T, A : Ring<T>, BA : BufferAlgebra<T, A>, L> BA.seriesAlgebra(labels: Iterable<L>): SeriesAlgebra<T, A, BA, L> { public fun <T, A : Ring<T>, BA : BufferAlgebra<T, A>, L> BA.seriesAlgebra(labels: Iterable<L>): SeriesAlgebra<T, A, BA, L> {