forked from kscience/kmath
Basic series
This commit is contained in:
parent
0e1e97a3ff
commit
bf504ae6c5
@ -2,6 +2,7 @@ import java.net.URL
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.gradle.project")
|
id("ru.mipt.npm.gradle.project")
|
||||||
|
id("org.jetbrains.kotlinx.kover") version "0.4.1"
|
||||||
kotlin("jupyter.api") apply false
|
kotlin("jupyter.api") apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package space.kscience.kmath.series
|
||||||
|
|
||||||
|
|
||||||
|
import net.jafama.StrictFastMath.abs
|
||||||
|
import space.kscience.kmath.operations.algebra
|
||||||
|
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.plotly.Plotly
|
||||||
|
import space.kscience.plotly.makeFile
|
||||||
|
import space.kscience.plotly.scatter
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
fun main() = Double.algebra.bufferAlgebra.seriesAlgebra(0..100).invoke {
|
||||||
|
fun Buffer<Double>.plot() {
|
||||||
|
val ls = labels
|
||||||
|
Plotly.plot {
|
||||||
|
scatter {
|
||||||
|
x.numbers = ls
|
||||||
|
y.numbers = toList()
|
||||||
|
}
|
||||||
|
}.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))}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -36,7 +36,7 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND<Double, Double
|
|||||||
this@StreamDoubleFieldND.shape,
|
this@StreamDoubleFieldND.shape,
|
||||||
shape
|
shape
|
||||||
)
|
)
|
||||||
this is BufferND && this.indices == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer
|
this is BufferND && this.shapeIndices == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer
|
||||||
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ plugins {
|
|||||||
kotlin("multiplatform")
|
kotlin("multiplatform")
|
||||||
id("ru.mipt.npm.gradle.common")
|
id("ru.mipt.npm.gradle.common")
|
||||||
id("ru.mipt.npm.gradle.native")
|
id("ru.mipt.npm.gradle.native")
|
||||||
// id("com.xcporter.metaview") version "0.0.5"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin.sourceSets {
|
kotlin.sourceSets {
|
||||||
@ -13,12 +12,6 @@ kotlin.sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//generateUml {
|
|
||||||
// classTree {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
description = "Core classes, algebra definitions, basic linear algebra"
|
description = "Core classes, algebra definitions, basic linear algebra"
|
||||||
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
|
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
|
||||||
|
@ -7,7 +7,6 @@ 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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,6 @@ 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.operations.asIterable
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.indices
|
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,11 +13,10 @@ 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>>(
|
||||||
private val bufferAlgebra: BufferAlgebra<T, A>
|
private val bufferAlgebra: BufferAlgebra<T, A>,
|
||||||
) : LinearSpace<T, A> {
|
) : LinearSpace<T, A> {
|
||||||
override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = intArrayOf(sha
|
|||||||
public interface WithShape {
|
public interface WithShape {
|
||||||
public val shape: Shape
|
public val shape: Shape
|
||||||
|
|
||||||
public val indices: ShapeIndexer get() = DefaultStrides(shape)
|
public val shapeIndices: ShapeIndices get() = DefaultStrides(shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,7 +13,7 @@ import space.kscience.kmath.operations.*
|
|||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
|
|
||||||
public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
|
public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
|
||||||
public val indexerBuilder: (IntArray) -> ShapeIndexer
|
public val indexerBuilder: (IntArray) -> ShapeIndices
|
||||||
public val bufferAlgebra: BufferAlgebra<T, A>
|
public val bufferAlgebra: BufferAlgebra<T, A>
|
||||||
override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
|
|||||||
zipInline(left.toBufferND(), right.toBufferND(), transform)
|
zipInline(left.toBufferND(), right.toBufferND(), transform)
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val defaultIndexerBuilder: (IntArray) -> ShapeIndexer = DefaultStrides.Companion::invoke
|
public val defaultIndexerBuilder: (IntArray) -> ShapeIndices = DefaultStrides.Companion::invoke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ public inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.mapInline(
|
|||||||
arg: BufferND<T>,
|
arg: BufferND<T>,
|
||||||
crossinline transform: A.(T) -> T,
|
crossinline transform: A.(T) -> T,
|
||||||
): BufferND<T> {
|
): BufferND<T> {
|
||||||
val indexes = arg.indices
|
val indexes = arg.shapeIndices
|
||||||
val buffer = arg.buffer
|
val buffer = arg.buffer
|
||||||
return BufferND(
|
return BufferND(
|
||||||
indexes,
|
indexes,
|
||||||
@ -69,7 +69,7 @@ internal inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.mapIndexedInline(
|
|||||||
arg: BufferND<T>,
|
arg: BufferND<T>,
|
||||||
crossinline transform: A.(index: IntArray, arg: T) -> T,
|
crossinline transform: A.(index: IntArray, arg: T) -> T,
|
||||||
): BufferND<T> {
|
): BufferND<T> {
|
||||||
val indexes = arg.indices
|
val indexes = arg.shapeIndices
|
||||||
val buffer = arg.buffer
|
val buffer = arg.buffer
|
||||||
return BufferND(
|
return BufferND(
|
||||||
indexes,
|
indexes,
|
||||||
@ -84,8 +84,8 @@ internal inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.zipInline(
|
|||||||
r: BufferND<T>,
|
r: BufferND<T>,
|
||||||
crossinline block: A.(l: T, r: T) -> T,
|
crossinline block: A.(l: T, r: T) -> T,
|
||||||
): BufferND<T> {
|
): BufferND<T> {
|
||||||
require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" }
|
require(l.shapeIndices == r.shapeIndices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" }
|
||||||
val indexes = l.indices
|
val indexes = l.shapeIndices
|
||||||
val lbuffer = l.buffer
|
val lbuffer = l.buffer
|
||||||
val rbuffer = r.buffer
|
val rbuffer = r.buffer
|
||||||
return BufferND(
|
return BufferND(
|
||||||
@ -99,25 +99,25 @@ internal inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.zipInline(
|
|||||||
@OptIn(PerformancePitfall::class)
|
@OptIn(PerformancePitfall::class)
|
||||||
public open class BufferedGroupNDOps<T, out A : Group<T>>(
|
public open class BufferedGroupNDOps<T, out A : Group<T>>(
|
||||||
override val bufferAlgebra: BufferAlgebra<T, A>,
|
override val bufferAlgebra: BufferAlgebra<T, A>,
|
||||||
override val indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
|
override val indexerBuilder: (IntArray) -> ShapeIndices = BufferAlgebraND.defaultIndexerBuilder,
|
||||||
) : GroupOpsND<T, A>, BufferAlgebraND<T, A> {
|
) : GroupOpsND<T, A>, BufferAlgebraND<T, A> {
|
||||||
override fun StructureND<T>.unaryMinus(): StructureND<T> = map { -it }
|
override fun StructureND<T>.unaryMinus(): StructureND<T> = map { -it }
|
||||||
}
|
}
|
||||||
|
|
||||||
public open class BufferedRingOpsND<T, out A : Ring<T>>(
|
public open class BufferedRingOpsND<T, out A : Ring<T>>(
|
||||||
bufferAlgebra: BufferAlgebra<T, A>,
|
bufferAlgebra: BufferAlgebra<T, A>,
|
||||||
indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
|
indexerBuilder: (IntArray) -> ShapeIndices = BufferAlgebraND.defaultIndexerBuilder,
|
||||||
) : BufferedGroupNDOps<T, A>(bufferAlgebra, indexerBuilder), RingOpsND<T, A>
|
) : BufferedGroupNDOps<T, A>(bufferAlgebra, indexerBuilder), RingOpsND<T, A>
|
||||||
|
|
||||||
public open class BufferedFieldOpsND<T, out A : Field<T>>(
|
public open class BufferedFieldOpsND<T, out A : Field<T>>(
|
||||||
bufferAlgebra: BufferAlgebra<T, A>,
|
bufferAlgebra: BufferAlgebra<T, A>,
|
||||||
indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
|
indexerBuilder: (IntArray) -> ShapeIndices = BufferAlgebraND.defaultIndexerBuilder,
|
||||||
) : BufferedRingOpsND<T, A>(bufferAlgebra, indexerBuilder), FieldOpsND<T, A> {
|
) : BufferedRingOpsND<T, A>(bufferAlgebra, indexerBuilder), FieldOpsND<T, A> {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
elementAlgebra: A,
|
elementAlgebra: A,
|
||||||
bufferFactory: BufferFactory<T>,
|
bufferFactory: BufferFactory<T>,
|
||||||
indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
|
indexerBuilder: (IntArray) -> ShapeIndices = BufferAlgebraND.defaultIndexerBuilder,
|
||||||
) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder)
|
) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder)
|
||||||
|
|
||||||
@OptIn(PerformancePitfall::class)
|
@OptIn(PerformancePitfall::class)
|
||||||
|
@ -14,17 +14,17 @@ import space.kscience.kmath.structures.MutableBufferFactory
|
|||||||
* Represents [StructureND] over [Buffer].
|
* Represents [StructureND] over [Buffer].
|
||||||
*
|
*
|
||||||
* @param T the type of items.
|
* @param T the type of items.
|
||||||
* @param indices The strides to access elements of [Buffer] by linear indices.
|
* @param shapeIndices The strides to access elements of [Buffer] by linear indices.
|
||||||
* @param buffer The underlying buffer.
|
* @param buffer The underlying buffer.
|
||||||
*/
|
*/
|
||||||
public open class BufferND<out T>(
|
public open class BufferND<out T>(
|
||||||
override val indices: ShapeIndexer,
|
override val shapeIndices: ShapeIndices,
|
||||||
public open val buffer: Buffer<T>,
|
public open val buffer: Buffer<T>,
|
||||||
) : StructureND<T> {
|
) : StructureND<T> {
|
||||||
|
|
||||||
override operator fun get(index: IntArray): T = buffer[indices.offset(index)]
|
override operator fun get(index: IntArray): T = buffer[shapeIndices.offset(index)]
|
||||||
|
|
||||||
override val shape: IntArray get() = indices.shape
|
override val shape: IntArray get() = shapeIndices.shape
|
||||||
|
|
||||||
override fun toString(): String = StructureND.toString(this)
|
override fun toString(): String = StructureND.toString(this)
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ public inline fun <T, reified R : Any> StructureND<T>.mapToBuffer(
|
|||||||
crossinline transform: (T) -> R,
|
crossinline transform: (T) -> R,
|
||||||
): BufferND<R> {
|
): BufferND<R> {
|
||||||
return if (this is BufferND<T>)
|
return if (this is BufferND<T>)
|
||||||
BufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) })
|
BufferND(this.shapeIndices, factory.invoke(shapeIndices.linearSize) { transform(buffer[it]) })
|
||||||
else {
|
else {
|
||||||
val strides = DefaultStrides(shape)
|
val strides = DefaultStrides(shape)
|
||||||
BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||||
@ -52,11 +52,11 @@ public inline fun <T, reified R : Any> StructureND<T>.mapToBuffer(
|
|||||||
* @param buffer The underlying buffer.
|
* @param buffer The underlying buffer.
|
||||||
*/
|
*/
|
||||||
public class MutableBufferND<T>(
|
public class MutableBufferND<T>(
|
||||||
strides: ShapeIndexer,
|
strides: ShapeIndices,
|
||||||
override val buffer: MutableBuffer<T>,
|
override val buffer: MutableBuffer<T>,
|
||||||
) : MutableStructureND<T>, BufferND<T>(strides, buffer) {
|
) : MutableStructureND<T>, BufferND<T>(strides, buffer) {
|
||||||
override fun set(index: IntArray, value: T) {
|
override fun set(index: IntArray, value: T) {
|
||||||
buffer[indices.offset(index)] = value
|
buffer[shapeIndices.offset(index)] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ public inline fun <T, reified R : Any> MutableStructureND<T>.mapToMutableBuffer(
|
|||||||
crossinline transform: (T) -> R,
|
crossinline transform: (T) -> R,
|
||||||
): MutableBufferND<R> {
|
): MutableBufferND<R> {
|
||||||
return if (this is MutableBufferND<T>)
|
return if (this is MutableBufferND<T>)
|
||||||
MutableBufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) })
|
MutableBufferND(this.shapeIndices, factory.invoke(shapeIndices.linearSize) { transform(buffer[it]) })
|
||||||
else {
|
else {
|
||||||
val strides = DefaultStrides(shape)
|
val strides = DefaultStrides(shape)
|
||||||
MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) })
|
||||||
|
@ -14,7 +14,7 @@ import kotlin.contracts.contract
|
|||||||
import kotlin.math.pow as kpow
|
import kotlin.math.pow as kpow
|
||||||
|
|
||||||
public class DoubleBufferND(
|
public class DoubleBufferND(
|
||||||
indexes: ShapeIndexer,
|
indexes: ShapeIndices,
|
||||||
override val buffer: DoubleBuffer,
|
override val buffer: DoubleBuffer,
|
||||||
) : BufferND<Double>(indexes, buffer)
|
) : BufferND<Double>(indexes, buffer)
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
|
|||||||
arg: DoubleBufferND,
|
arg: DoubleBufferND,
|
||||||
transform: (Double) -> Double,
|
transform: (Double) -> Double,
|
||||||
): DoubleBufferND {
|
): DoubleBufferND {
|
||||||
val indexes = arg.indices
|
val indexes = arg.shapeIndices
|
||||||
val array = arg.buffer.array
|
val array = arg.buffer.array
|
||||||
return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) })
|
return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) })
|
||||||
}
|
}
|
||||||
@ -44,8 +44,8 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
|
|||||||
r: DoubleBufferND,
|
r: DoubleBufferND,
|
||||||
block: (l: Double, r: Double) -> Double,
|
block: (l: Double, r: Double) -> Double,
|
||||||
): DoubleBufferND {
|
): DoubleBufferND {
|
||||||
require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" }
|
require(l.shapeIndices == r.shapeIndices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" }
|
||||||
val indexes = l.indices
|
val indexes = l.shapeIndices
|
||||||
val lArray = l.buffer.array
|
val lArray = l.buffer.array
|
||||||
val rArray = r.buffer.array
|
val rArray = r.buffer.array
|
||||||
return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) })
|
return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) })
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.native.concurrent.ThreadLocal
|
|||||||
/**
|
/**
|
||||||
* A converter from linear index to multivariate index
|
* A converter from linear index to multivariate index
|
||||||
*/
|
*/
|
||||||
public interface ShapeIndexer: Iterable<IntArray>{
|
public interface ShapeIndices: Iterable<IntArray>{
|
||||||
public val shape: Shape
|
public val shape: Shape
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +44,7 @@ public interface ShapeIndexer: Iterable<IntArray>{
|
|||||||
/**
|
/**
|
||||||
* Linear transformation of indexes
|
* Linear transformation of indexes
|
||||||
*/
|
*/
|
||||||
public abstract class Strides: ShapeIndexer {
|
public abstract class Strides: ShapeIndices {
|
||||||
/**
|
/**
|
||||||
* Array strides
|
* Array strides
|
||||||
*/
|
*/
|
@ -54,7 +54,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
|
|||||||
* @return the lazy sequence of pairs of indices to values.
|
* @return the lazy sequence of pairs of indices to values.
|
||||||
*/
|
*/
|
||||||
@PerformancePitfall
|
@PerformancePitfall
|
||||||
public fun elements(): Sequence<Pair<IntArray, T>> = indices.asSequence().map { it to get(it) }
|
public fun elements(): Sequence<Pair<IntArray, T>> = shapeIndices.asSequence().map { it to get(it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Feature is some additional structure information that allows to access it special properties or hints.
|
* Feature is some additional structure information that allows to access it special properties or hints.
|
||||||
@ -71,7 +71,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
|
|||||||
if (st1 === st2) return true
|
if (st1 === st2) return true
|
||||||
|
|
||||||
// fast comparison of buffers if possible
|
// fast comparison of buffers if possible
|
||||||
if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices)
|
if (st1 is BufferND && st2 is BufferND && st1.shapeIndices == st2.shapeIndices)
|
||||||
return Buffer.contentEquals(st1.buffer, st2.buffer)
|
return Buffer.contentEquals(st1.buffer, st2.buffer)
|
||||||
|
|
||||||
//element by element comparison if it could not be avoided
|
//element by element comparison if it could not be avoided
|
||||||
@ -87,7 +87,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
|
|||||||
if (st1 === st2) return true
|
if (st1 === st2) return true
|
||||||
|
|
||||||
// fast comparison of buffers if possible
|
// fast comparison of buffers if possible
|
||||||
if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices)
|
if (st1 is BufferND && st2 is BufferND && st1.shapeIndices == st2.shapeIndices)
|
||||||
return Buffer.contentEquals(st1.buffer, st2.buffer)
|
return Buffer.contentEquals(st1.buffer, st2.buffer)
|
||||||
|
|
||||||
//element by element comparison if it could not be avoided
|
//element by element comparison if it could not be avoided
|
||||||
|
@ -61,14 +61,14 @@ public inline fun <reified T> Buffer<T>.toTypedArray(): Array<T> = Array(size, :
|
|||||||
/**
|
/**
|
||||||
* Create a new buffer from this one with the given mapping function and using [Buffer.Companion.auto] buffer factory.
|
* Create a new buffer from this one with the given mapping function and using [Buffer.Companion.auto] buffer factory.
|
||||||
*/
|
*/
|
||||||
public inline fun <T : Any, reified R : Any> Buffer<T>.map(block: (T) -> R): Buffer<R> =
|
public inline fun <T, reified R : Any> Buffer<T>.map(block: (T) -> R): Buffer<R> =
|
||||||
Buffer.auto(size) { block(get(it)) }
|
Buffer.auto(size) { block(get(it)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new buffer from this one with the given mapping function.
|
* Create a new buffer from this one with the given mapping function.
|
||||||
* Provided [bufferFactory] is used to construct the new buffer.
|
* Provided [bufferFactory] is used to construct the new buffer.
|
||||||
*/
|
*/
|
||||||
public inline fun <T : Any, R : Any> Buffer<T>.map(
|
public inline fun <T, R> Buffer<T>.map(
|
||||||
bufferFactory: BufferFactory<R>,
|
bufferFactory: BufferFactory<R>,
|
||||||
crossinline block: (T) -> R,
|
crossinline block: (T) -> R,
|
||||||
): Buffer<R> = bufferFactory(size) { block(get(it)) }
|
): Buffer<R> = bufferFactory(size) { block(get(it)) }
|
||||||
@ -77,15 +77,16 @@ public inline fun <T : Any, R : Any> Buffer<T>.map(
|
|||||||
* Create a new buffer from this one with the given indexed mapping function.
|
* Create a new buffer from this one with the given indexed mapping function.
|
||||||
* Provided [BufferFactory] is used to construct the new buffer.
|
* Provided [BufferFactory] is used to construct the new buffer.
|
||||||
*/
|
*/
|
||||||
public inline fun <T : Any, reified R : Any> Buffer<T>.mapIndexed(
|
public inline fun <T, reified R : Any> Buffer<T>.mapIndexed(
|
||||||
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
||||||
crossinline block: (index: Int, value: T) -> R,
|
crossinline block: (index: Int, value: T) -> R,
|
||||||
): Buffer<R> = bufferFactory(size) { block(it, get(it)) }
|
): Buffer<R> = bufferFactory(size) { block(it, get(it)) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fold given buffer according to [operation]
|
* Fold given buffer according to [operation]
|
||||||
|
* TODO add element algebra as fold receiver
|
||||||
*/
|
*/
|
||||||
public inline fun <T : Any, R> Buffer<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
|
public inline fun <T, R> Buffer<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
|
||||||
var accumulator = initial
|
var accumulator = initial
|
||||||
for (index in this.indices) accumulator = operation(accumulator, get(index))
|
for (index in this.indices) accumulator = operation(accumulator, get(index))
|
||||||
return accumulator
|
return accumulator
|
||||||
@ -95,7 +96,7 @@ public inline fun <T : Any, R> Buffer<T>.fold(initial: R, operation: (acc: R, T)
|
|||||||
* Zip two buffers using given [transform].
|
* Zip two buffers using given [transform].
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public inline fun <T1 : Any, T2 : Any, reified R : Any> Buffer<T1>.zip(
|
public inline fun <T1, T2, reified R : Any> Buffer<T1>.zip(
|
||||||
other: Buffer<T2>,
|
other: Buffer<T2>,
|
||||||
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
|
||||||
crossinline transform: (T1, T2) -> R,
|
crossinline transform: (T1, T2) -> R,
|
||||||
|
@ -48,6 +48,11 @@ public interface Buffer<out T> {
|
|||||||
|
|
||||||
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 =
|
||||||
@ -100,10 +105,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].
|
* if index is in range of buffer, return the value. Otherwise, return null.
|
||||||
*/
|
*/
|
||||||
public val Buffer<*>.indices: IntRange get() = 0 until size
|
public fun <T> Buffer<T>.getOrNull(index: Int): T? = if (index in indices) get(index) else null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immutable wrapper for [MutableBuffer].
|
* Immutable wrapper for [MutableBuffer].
|
||||||
|
@ -11,7 +11,6 @@ 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>
|
||||||
|
@ -13,8 +13,8 @@ import space.kscience.kmath.structures.DoubleBuffer
|
|||||||
* Map one [BufferND] using function without indices.
|
* Map one [BufferND] using function without indices.
|
||||||
*/
|
*/
|
||||||
public inline fun BufferND<Double>.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND<Double> {
|
public inline fun BufferND<Double>.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND<Double> {
|
||||||
val array = DoubleArray(indices.linearSize) { offset -> DoubleField.transform(buffer[offset]) }
|
val array = DoubleArray(shapeIndices.linearSize) { offset -> DoubleField.transform(buffer[offset]) }
|
||||||
return BufferND(indices, DoubleBuffer(array))
|
return BufferND(shapeIndices, DoubleBuffer(array))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,6 @@ 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
|
||||||
|
@ -0,0 +1,170 @@
|
|||||||
|
package space.kscience.kmath.series
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.*
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
|
import space.kscience.kmath.structures.getOrNull
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
private fun IntRange.intersect(other: IntRange): IntRange =
|
||||||
|
max(first, other.first)..min(last, other.last)
|
||||||
|
|
||||||
|
private val IntRange.size get() = last - first + 1
|
||||||
|
|
||||||
|
private class BufferView<T>(val buffer: Buffer<T>, val offset: Int, override val size: Int) : Buffer<T> {
|
||||||
|
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 < buffer.size) { "Slice size is larger than the buffer" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(index: Int): T = buffer[index - offset]
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public class SeriesAlgebra<T, A : Ring<T>, L>(
|
||||||
|
public val bufferAlgebra: BufferRingOps<T, A>,
|
||||||
|
private val labelResolver: (Int) -> L,
|
||||||
|
) : RingOps<Buffer<T>> {
|
||||||
|
|
||||||
|
public val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
|
||||||
|
public val bufferFactory: BufferFactory<T> get() = bufferAlgebra.bufferFactory
|
||||||
|
|
||||||
|
public val Buffer<T>.offset: UInt get() = indices.first.toUInt()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a new series
|
||||||
|
*/
|
||||||
|
public fun series(size: Int, fromIndex: Int = 0, block: A.(label: L) -> T): Buffer<T> {
|
||||||
|
return bufferFactory(size) {
|
||||||
|
val index = it + fromIndex
|
||||||
|
elementAlgebra.block(labelResolver(index))
|
||||||
|
}.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.
|
||||||
|
*/
|
||||||
|
public val Buffer<T>.labels: List<L> get() = indices.map(labelResolver)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to resolve element by label and return null if element with a given label is not found
|
||||||
|
*/
|
||||||
|
public operator fun Buffer<T>.get(label: L): T? {
|
||||||
|
val index = labels.indexOf(label)
|
||||||
|
if (index == -1) return null
|
||||||
|
return get(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
|
||||||
|
*/
|
||||||
|
public inline fun Buffer<T>.map(crossinline transform: A.(T) -> T): Buffer<T> {
|
||||||
|
val buf = bufferFactory(size) {
|
||||||
|
elementAlgebra.transform(get(it))
|
||||||
|
}
|
||||||
|
return buf.moveTo(indices.first)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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> {
|
||||||
|
val labels = labels
|
||||||
|
val buf = bufferFactory(size) {
|
||||||
|
elementAlgebra.transform(get(it), labels[it])
|
||||||
|
}
|
||||||
|
return buf.moveTo(indices.first)
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun <R> Buffer<T>.fold(initial: R, operation: A.(acc: R, T) -> R): R {
|
||||||
|
var accumulator = initial
|
||||||
|
for (index in this.indices) accumulator = elementAlgebra.operation(accumulator, get(index))
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline fun <R> Buffer<T>.foldWithLabel(initial: R, operation: A.(acc: R, arg: T, label: L) -> R): R {
|
||||||
|
val labels = labels
|
||||||
|
var accumulator = initial
|
||||||
|
for (index in this.indices) accumulator = elementAlgebra.operation(accumulator, get(index), labels[index])
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zip two buffers replacing missing values with [defaultValue]
|
||||||
|
*/
|
||||||
|
public inline fun Buffer<T>.zip(
|
||||||
|
other: Buffer<T>,
|
||||||
|
defaultValue: T,
|
||||||
|
crossinline operation: A.(left: T?, right: T?) -> T?,
|
||||||
|
): Buffer<T> {
|
||||||
|
val start = min(indices.first, other.indices.first)
|
||||||
|
val size = max(indices.last, other.indices.last) - start
|
||||||
|
return bufferFactory(size) {
|
||||||
|
elementAlgebra.operation(
|
||||||
|
getOrNull(it) ?: defaultValue,
|
||||||
|
other.getOrNull(it) ?: defaultValue
|
||||||
|
) ?: defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T, A : Ring<T>, L> BufferRingOps<T, A>.seriesAlgebra(labels: Iterable<L>): SeriesAlgebra<T, A, L> {
|
||||||
|
val l = labels.toList()
|
||||||
|
return SeriesAlgebra(this) {
|
||||||
|
if (it in l.indices) l[it] else error("Index $it is outside of labels range ${l.indices}")
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ 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
|
||||||
@ -45,8 +44,10 @@ public class Mean<T>(
|
|||||||
public companion object {
|
public companion object {
|
||||||
@Deprecated("Use Double.mean instead")
|
@Deprecated("Use Double.mean instead")
|
||||||
public val double: Mean<Double> = Mean(DoubleField) { sum, count -> sum / count }
|
public val double: Mean<Double> = Mean(DoubleField) { sum, count -> sum / count }
|
||||||
|
|
||||||
@Deprecated("Use Int.mean instead")
|
@Deprecated("Use Int.mean instead")
|
||||||
public val int: Mean<Int> = Mean(IntRing) { sum, count -> sum / count }
|
public val int: Mean<Int> = Mean(IntRing) { sum, count -> sum / count }
|
||||||
|
|
||||||
@Deprecated("Use Long.mean instead")
|
@Deprecated("Use Long.mean instead")
|
||||||
public val long: Mean<Long> = Mean(LongRing) { sum, count -> sum / count }
|
public val long: Mean<Long> = Mean(LongRing) { sum, count -> sum / count }
|
||||||
|
|
||||||
@ -60,6 +61,6 @@ public class Mean<T>(
|
|||||||
//TODO replace with optimized version which respects overflow
|
//TODO replace with optimized version which respects overflow
|
||||||
public val Double.Companion.mean: Mean<Double> get() = Mean(DoubleField) { sum, count -> sum / count }
|
public val Double.Companion.mean: Mean<Double> get() = Mean(DoubleField) { sum, count -> sum / count }
|
||||||
public val Int.Companion.mean: Mean<Int> get() = Mean(IntRing) { sum, count -> sum / count }
|
public val Int.Companion.mean: Mean<Int> get() = Mean(IntRing) { sum, count -> sum / count }
|
||||||
public val Long.Companion.mean: Mean<Long> get() = Mean(LongRing) { sum, count -> sum / count }
|
public val Long.Companion.mean: Mean<Long> get() = Mean(LongRing) { sum, count -> sum / count }
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
val broadcast = broadcastTensors(tensor, arg.tensor)
|
val broadcast = broadcastTensors(tensor, arg.tensor)
|
||||||
val newThis = broadcast[0]
|
val newThis = broadcast[0]
|
||||||
val newOther = broadcast[1]
|
val newOther = broadcast[1]
|
||||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
val resBuffer = DoubleArray(newThis.shapeIndices.linearSize) { i ->
|
||||||
newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i]
|
newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i]
|
||||||
}
|
}
|
||||||
return DoubleTensor(newThis.shape, resBuffer)
|
return DoubleTensor(newThis.shape, resBuffer)
|
||||||
@ -34,7 +34,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
|
|
||||||
override fun Tensor<Double>.plusAssign(arg: StructureND<Double>) {
|
override fun Tensor<Double>.plusAssign(arg: StructureND<Double>) {
|
||||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||||
for (i in 0 until tensor.indices.linearSize) {
|
for (i in 0 until tensor.shapeIndices.linearSize) {
|
||||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] +=
|
tensor.mutableBuffer.array()[tensor.bufferStart + i] +=
|
||||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
val broadcast = broadcastTensors(tensor, arg.tensor)
|
val broadcast = broadcastTensors(tensor, arg.tensor)
|
||||||
val newThis = broadcast[0]
|
val newThis = broadcast[0]
|
||||||
val newOther = broadcast[1]
|
val newOther = broadcast[1]
|
||||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
val resBuffer = DoubleArray(newThis.shapeIndices.linearSize) { i ->
|
||||||
newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i]
|
newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i]
|
||||||
}
|
}
|
||||||
return DoubleTensor(newThis.shape, resBuffer)
|
return DoubleTensor(newThis.shape, resBuffer)
|
||||||
@ -52,7 +52,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
|
|
||||||
override fun Tensor<Double>.minusAssign(arg: StructureND<Double>) {
|
override fun Tensor<Double>.minusAssign(arg: StructureND<Double>) {
|
||||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||||
for (i in 0 until tensor.indices.linearSize) {
|
for (i in 0 until tensor.shapeIndices.linearSize) {
|
||||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] -=
|
tensor.mutableBuffer.array()[tensor.bufferStart + i] -=
|
||||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
val broadcast = broadcastTensors(tensor, arg.tensor)
|
val broadcast = broadcastTensors(tensor, arg.tensor)
|
||||||
val newThis = broadcast[0]
|
val newThis = broadcast[0]
|
||||||
val newOther = broadcast[1]
|
val newOther = broadcast[1]
|
||||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
val resBuffer = DoubleArray(newThis.shapeIndices.linearSize) { i ->
|
||||||
newThis.mutableBuffer.array()[newThis.bufferStart + i] *
|
newThis.mutableBuffer.array()[newThis.bufferStart + i] *
|
||||||
newOther.mutableBuffer.array()[newOther.bufferStart + i]
|
newOther.mutableBuffer.array()[newOther.bufferStart + i]
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
|
|
||||||
override fun Tensor<Double>.timesAssign(arg: StructureND<Double>) {
|
override fun Tensor<Double>.timesAssign(arg: StructureND<Double>) {
|
||||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||||
for (i in 0 until tensor.indices.linearSize) {
|
for (i in 0 until tensor.shapeIndices.linearSize) {
|
||||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] *=
|
tensor.mutableBuffer.array()[tensor.bufferStart + i] *=
|
||||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
val broadcast = broadcastTensors(tensor, arg.tensor)
|
val broadcast = broadcastTensors(tensor, arg.tensor)
|
||||||
val newThis = broadcast[0]
|
val newThis = broadcast[0]
|
||||||
val newOther = broadcast[1]
|
val newOther = broadcast[1]
|
||||||
val resBuffer = DoubleArray(newThis.indices.linearSize) { i ->
|
val resBuffer = DoubleArray(newThis.shapeIndices.linearSize) { i ->
|
||||||
newThis.mutableBuffer.array()[newOther.bufferStart + i] /
|
newThis.mutableBuffer.array()[newOther.bufferStart + i] /
|
||||||
newOther.mutableBuffer.array()[newOther.bufferStart + i]
|
newOther.mutableBuffer.array()[newOther.bufferStart + i]
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() {
|
|||||||
|
|
||||||
override fun Tensor<Double>.divAssign(arg: StructureND<Double>) {
|
override fun Tensor<Double>.divAssign(arg: StructureND<Double>) {
|
||||||
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
val newOther = broadcastTo(arg.tensor, tensor.shape)
|
||||||
for (i in 0 until tensor.indices.linearSize) {
|
for (i in 0 until tensor.shapeIndices.linearSize) {
|
||||||
tensor.mutableBuffer.array()[tensor.bufferStart + i] /=
|
tensor.mutableBuffer.array()[tensor.bufferStart + i] /=
|
||||||
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
newOther.mutableBuffer.array()[tensor.bufferStart + i]
|
||||||
}
|
}
|
||||||
|
@ -22,22 +22,22 @@ public open class BufferedTensor<T> internal constructor(
|
|||||||
/**
|
/**
|
||||||
* Buffer strides based on [TensorLinearStructure] implementation
|
* Buffer strides based on [TensorLinearStructure] implementation
|
||||||
*/
|
*/
|
||||||
override val indices: Strides get() = TensorLinearStructure(shape)
|
override val shapeIndices: Strides get() = TensorLinearStructure(shape)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of elements in tensor
|
* Number of elements in tensor
|
||||||
*/
|
*/
|
||||||
public val numElements: Int
|
public val numElements: Int
|
||||||
get() = indices.linearSize
|
get() = shapeIndices.linearSize
|
||||||
|
|
||||||
override fun get(index: IntArray): T = mutableBuffer[bufferStart + indices.offset(index)]
|
override fun get(index: IntArray): T = mutableBuffer[bufferStart + shapeIndices.offset(index)]
|
||||||
|
|
||||||
override fun set(index: IntArray, value: T) {
|
override fun set(index: IntArray, value: T) {
|
||||||
mutableBuffer[bufferStart + indices.offset(index)] = value
|
mutableBuffer[bufferStart + shapeIndices.offset(index)] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@PerformancePitfall
|
@PerformancePitfall
|
||||||
override fun elements(): Sequence<Pair<IntArray, T>> = indices.asSequence().map {
|
override fun elements(): Sequence<Pair<IntArray, T>> = shapeIndices.asSequence().map {
|
||||||
it to get(it)
|
it to get(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ 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
|
||||||
@ -63,7 +62,7 @@ public open class DoubleTensorAlgebra :
|
|||||||
val tensor = this.tensor
|
val tensor = this.tensor
|
||||||
//TODO remove additional copy
|
//TODO remove additional copy
|
||||||
val sourceArray = tensor.copyArray()
|
val sourceArray = tensor.copyArray()
|
||||||
val array = DoubleArray(tensor.numElements) { DoubleField.transform(tensor.indices.index(it), sourceArray[it]) }
|
val array = DoubleArray(tensor.numElements) { DoubleField.transform(tensor.shapeIndices.index(it), sourceArray[it]) }
|
||||||
return DoubleTensor(
|
return DoubleTensor(
|
||||||
tensor.shape,
|
tensor.shape,
|
||||||
array,
|
array,
|
||||||
@ -365,11 +364,11 @@ public open class DoubleTensorAlgebra :
|
|||||||
val resTensor = DoubleTensor(resShape, resBuffer)
|
val resTensor = DoubleTensor(resShape, resBuffer)
|
||||||
|
|
||||||
for (offset in 0 until n) {
|
for (offset in 0 until n) {
|
||||||
val oldMultiIndex = tensor.indices.index(offset)
|
val oldMultiIndex = tensor.shapeIndices.index(offset)
|
||||||
val newMultiIndex = oldMultiIndex.copyOf()
|
val newMultiIndex = oldMultiIndex.copyOf()
|
||||||
newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] }
|
newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] }
|
||||||
|
|
||||||
val linearIndex = resTensor.indices.offset(newMultiIndex)
|
val linearIndex = resTensor.shapeIndices.offset(newMultiIndex)
|
||||||
resTensor.mutableBuffer.array()[linearIndex] =
|
resTensor.mutableBuffer.array()[linearIndex] =
|
||||||
tensor.mutableBuffer.array()[tensor.bufferStart + offset]
|
tensor.mutableBuffer.array()[tensor.bufferStart + offset]
|
||||||
}
|
}
|
||||||
@ -467,7 +466,7 @@ public open class DoubleTensorAlgebra :
|
|||||||
val resTensor = zeros(resShape)
|
val resTensor = zeros(resShape)
|
||||||
|
|
||||||
for (i in 0 until diagonalEntries.tensor.numElements) {
|
for (i in 0 until diagonalEntries.tensor.numElements) {
|
||||||
val multiIndex = diagonalEntries.tensor.indices.index(i)
|
val multiIndex = diagonalEntries.tensor.shapeIndices.index(i)
|
||||||
|
|
||||||
var offset1 = 0
|
var offset1 = 0
|
||||||
var offset2 = abs(realOffset)
|
var offset2 = abs(realOffset)
|
||||||
@ -592,7 +591,7 @@ public open class DoubleTensorAlgebra :
|
|||||||
val init = foldFunction(DoubleArray(1) { 0.0 })
|
val init = foldFunction(DoubleArray(1) { 0.0 })
|
||||||
val resTensor = BufferedTensor(resShape,
|
val resTensor = BufferedTensor(resShape,
|
||||||
MutableBuffer.auto(resNumElements) { init }, 0)
|
MutableBuffer.auto(resNumElements) { init }, 0)
|
||||||
for (index in resTensor.indices) {
|
for (index in resTensor.shapeIndices) {
|
||||||
val prefix = index.take(dim).toIntArray()
|
val prefix = index.take(dim).toIntArray()
|
||||||
val suffix = index.takeLast(dimension - dim - 1).toIntArray()
|
val suffix = index.takeLast(dimension - dim - 1).toIntArray()
|
||||||
resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i ->
|
resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i ->
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.math.max
|
|||||||
|
|
||||||
internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) {
|
internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) {
|
||||||
for (linearIndex in 0 until linearSize) {
|
for (linearIndex in 0 until linearSize) {
|
||||||
val totalMultiIndex = resTensor.indices.index(linearIndex)
|
val totalMultiIndex = resTensor.shapeIndices.index(linearIndex)
|
||||||
val curMultiIndex = tensor.shape.copyOf()
|
val curMultiIndex = tensor.shape.copyOf()
|
||||||
|
|
||||||
val offset = totalMultiIndex.size - curMultiIndex.size
|
val offset = totalMultiIndex.size - curMultiIndex.size
|
||||||
@ -23,7 +23,7 @@ internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTenso
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val curLinearIndex = tensor.indices.offset(curMultiIndex)
|
val curLinearIndex = tensor.shapeIndices.offset(curMultiIndex)
|
||||||
resTensor.mutableBuffer.array()[linearIndex] =
|
resTensor.mutableBuffer.array()[linearIndex] =
|
||||||
tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex]
|
tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex]
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List<DoubleTen
|
|||||||
val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize))
|
val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize))
|
||||||
|
|
||||||
for (linearIndex in 0 until n) {
|
for (linearIndex in 0 until n) {
|
||||||
val totalMultiIndex = outerTensor.indices.index(linearIndex)
|
val totalMultiIndex = outerTensor.shapeIndices.index(linearIndex)
|
||||||
var curMultiIndex = tensor.shape.sliceArray(0..tensor.shape.size - 3).copyOf()
|
var curMultiIndex = tensor.shape.sliceArray(0..tensor.shape.size - 3).copyOf()
|
||||||
curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex
|
curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex
|
||||||
|
|
||||||
@ -127,13 +127,13 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List<DoubleTen
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0 until matrixSize) {
|
for (i in 0 until matrixSize) {
|
||||||
val curLinearIndex = newTensor.indices.offset(
|
val curLinearIndex = newTensor.shapeIndices.offset(
|
||||||
curMultiIndex +
|
curMultiIndex +
|
||||||
matrix.indices.index(i)
|
matrix.shapeIndices.index(i)
|
||||||
)
|
)
|
||||||
val newLinearIndex = resTensor.indices.offset(
|
val newLinearIndex = resTensor.shapeIndices.offset(
|
||||||
totalMultiIndex +
|
totalMultiIndex +
|
||||||
matrix.indices.index(i)
|
matrix.shapeIndices.index(i)
|
||||||
)
|
)
|
||||||
|
|
||||||
resTensor.mutableBuffer.array()[resTensor.bufferStart + newLinearIndex] =
|
resTensor.mutableBuffer.array()[resTensor.bufferStart + newLinearIndex] =
|
||||||
|
@ -3,8 +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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:OptIn(PerformancePitfall::class)
|
||||||
|
|
||||||
package space.kscience.kmath.tensors.core.internal
|
package space.kscience.kmath.tensors.core.internal
|
||||||
|
|
||||||
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
import space.kscience.kmath.nd.MutableStructure1D
|
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
|
||||||
|
@ -28,7 +28,7 @@ internal fun <T> StructureND<T>.copyToBufferedTensor(): BufferedTensor<T> =
|
|||||||
|
|
||||||
internal fun <T> StructureND<T>.toBufferedTensor(): BufferedTensor<T> = when (this) {
|
internal fun <T> StructureND<T>.toBufferedTensor(): BufferedTensor<T> = when (this) {
|
||||||
is BufferedTensor<T> -> this
|
is BufferedTensor<T> -> this
|
||||||
is MutableBufferND<T> -> if (this.indices == TensorLinearStructure(this.shape)) {
|
is MutableBufferND<T> -> if (this.shapeIndices == TensorLinearStructure(this.shape)) {
|
||||||
BufferedTensor(this.shape, this.buffer, 0)
|
BufferedTensor(this.shape, this.buffer, 0)
|
||||||
} else {
|
} else {
|
||||||
this.copyToBufferedTensor()
|
this.copyToBufferedTensor()
|
||||||
|
@ -85,7 +85,7 @@ internal fun format(value: Double, digits: Int = 4): String = buildString {
|
|||||||
internal fun DoubleTensor.toPrettyString(): String = buildString {
|
internal fun DoubleTensor.toPrettyString(): String = buildString {
|
||||||
var offset = 0
|
var offset = 0
|
||||||
val shape = this@toPrettyString.shape
|
val shape = this@toPrettyString.shape
|
||||||
val linearStructure = this@toPrettyString.indices
|
val linearStructure = this@toPrettyString.shapeIndices
|
||||||
val vectorSize = shape.last()
|
val vectorSize = shape.last()
|
||||||
append("DoubleTensor(\n")
|
append("DoubleTensor(\n")
|
||||||
var charOffset = 3
|
var charOffset = 3
|
||||||
|
@ -5,8 +5,8 @@ pluginManagement {
|
|||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
|
|
||||||
val kotlinVersion = "1.6.0-RC"
|
val kotlinVersion = "1.6.0-RC2"
|
||||||
val toolsVersion = "0.10.5"
|
val toolsVersion = "0.10.6"
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.jetbrains.kotlinx.benchmark") version "0.3.1"
|
id("org.jetbrains.kotlinx.benchmark") version "0.3.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user