Explicit mutability for StructureND builders

This commit is contained in:
Alexander Nozik 2023-04-21 12:41:46 +03:00
parent 875e32679b
commit cdfddb7551
25 changed files with 159 additions and 43 deletions

View File

@ -3,6 +3,7 @@
## Unreleased ## Unreleased
### Added ### Added
- Explicit `mutableStructureND` builders for mutable stucures
### Changed ### Changed

View File

@ -3,8 +3,6 @@ plugins {
`version-catalog` `version-catalog`
} }
java.targetCompatibility = JavaVersion.VERSION_11
repositories { repositories {
mavenLocal() mavenLocal()
maven("https://repo.kotlin.link") maven("https://repo.kotlin.link")
@ -26,6 +24,11 @@ dependencies {
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.+")
} }
kotlin.sourceSets.all { kotlin{
jvmToolchain{
languageVersion.set(JavaLanguageVersion.of(11))
}
sourceSets.all {
languageSettings.optIn("kotlin.OptIn") languageSettings.optIn("kotlin.OptIn")
} }
}

View File

@ -52,7 +52,7 @@ dependencies {
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.3-dev-1")
} }
kotlin { kotlin {

View File

@ -8,14 +8,15 @@ package space.kscience.kmath.operations
import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.commons.linear.CMLinearSpace
import space.kscience.kmath.linear.matrix import space.kscience.kmath.linear.matrix
import space.kscience.kmath.nd.DoubleBufferND import space.kscience.kmath.nd.DoubleBufferND
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.nd.mutableStructureND
import space.kscience.kmath.nd.ndAlgebra import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.viktor.ViktorStructureND
import space.kscience.kmath.viktor.viktorAlgebra import space.kscience.kmath.viktor.viktorAlgebra
import kotlin.collections.component1
import kotlin.collections.component2
fun main() { fun main() {
val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.structureND(ShapeND(2, 2)) { (i, j) -> val viktorStructure = DoubleField.viktorAlgebra.mutableStructureND(2, 2) { (i, j) ->
if (i == j) 2.0 else 0.0 if (i == j) 2.0 else 0.0
} }

View File

@ -13,7 +13,10 @@ import space.kscience.kmath.structures.slice
import space.kscience.plotly.* import space.kscience.plotly.*
import kotlin.math.PI import kotlin.math.PI
fun main() = with(Double.algebra.bufferAlgebra.seriesAlgebra()) { fun Double.Companion.seriesAlgebra() = Double.algebra.bufferAlgebra.seriesAlgebra()
fun main() = with(Double.seriesAlgebra()) {
fun Plot.plotSeries(name: String, buffer: Buffer<Double>) { fun Plot.plotSeries(name: String, buffer: Buffer<Double>) {

View File

@ -0,0 +1,50 @@
/*
* 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.structures.Buffer
import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.structures.toDoubleArray
import space.kscience.plotly.*
import space.kscience.plotly.models.Scatter
import space.kscience.plotly.models.ScatterMode
import kotlin.random.Random
fun main(): Unit = with(Double.seriesAlgebra()) {
val random = Random(1234)
val arrayOfRandoms = DoubleArray(20) { random.nextDouble() }
val series1: DoubleBuffer = arrayOfRandoms.asBuffer()
val series2: Series<Double> = series1.moveBy(3)
val res = series2 - series1
println(res.size)
println(res)
fun Plot.series(name: String, buffer: Buffer<Double>, block: Scatter.() -> Unit = {}) {
scatter {
this.name = name
x.numbers = buffer.offsetIndices
y.doubles = buffer.toDoubleArray()
block()
}
}
Plotly.plot {
series("series1", series1)
series("series2", series2)
series("dif", res){
mode = ScatterMode.lines
line.color("magenta")
}
}.makeFile(resourceLocation = ResourceLocation.REMOTE)
}

View File

@ -52,6 +52,15 @@ class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, DoubleF
return BufferND(strides, array.asBuffer()) return BufferND(strides, array.asBuffer())
} }
override fun mutableStructureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): MutableBufferND<Double> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
val index = strides.index(offset)
DoubleField.initializer(index)
}.toArray()
return MutableBufferND(strides, array.asBuffer())
}
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
override fun StructureND<Double>.map( override fun StructureND<Double>.map(
transform: DoubleField.(Double) -> Double, transform: DoubleField.(Double) -> Double,

View File

@ -0,0 +1,26 @@
/*
* 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.structures
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.algebra
@OptIn(PerformancePitfall::class)
fun main(): Unit = with(Double.algebra.ndAlgebra) {
val structure: MutableStructure2D<Double> = mutableStructureND(ShapeND(2, 2)) { (i, j) ->
i.toDouble() + j.toDouble()
}.as2D()
structure[0, 1] = -2.0
val structure2 = mutableStructureND(2, 2) { (i, j) -> i.toDouble() + j.toDouble() }.as2D()
structure2[0, 1] = 2.0
println(structure + structure2)
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -37,8 +37,8 @@ kotlin.sourceSets {
filter { it.name.contains("test", true) } filter { it.name.contains("test", true) }
.map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings)
.forEach { .forEach {
it.optIn("space.kscience.kmath.misc.PerformancePitfall") it.optIn("space.kscience.kmath.PerformancePitfall")
it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") it.optIn("space.kscience.kmath.UnstableKMathAPI")
} }
} }

View File

@ -22,10 +22,16 @@ public interface AlgebraND<T, out C : Algebra<T>>: Algebra<StructureND<T>> {
*/ */
public val elementAlgebra: C public val elementAlgebra: C
/**
* Produces a new [MutableStructureND] using given initializer function.
*/
public fun mutableStructureND(shape: ShapeND, initializer: C.(IntArray) -> T): MutableStructureND<T>
/** /**
* Produces a new [StructureND] using given initializer function. * Produces a new [StructureND] using given initializer function.
*/ */
public fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): StructureND<T> public fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): StructureND<T> =
mutableStructureND(shape, initializer)
/** /**
* Maps elements from one structure to another one by applying [transform] to them. * Maps elements from one structure to another one by applying [transform] to them.

View File

@ -16,9 +16,10 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
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
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): BufferND<T> { //TODO change AlgebraND contract to include this
override fun mutableStructureND(shape: ShapeND, initializer: A.(IntArray) -> T): MutableBufferND<T> {
val indexer = indexerBuilder(shape) val indexer = indexerBuilder(shape)
return BufferND( return MutableBufferND(
indexer, indexer,
bufferAlgebra.buffer(indexer.linearSize) { offset -> bufferAlgebra.buffer(indexer.linearSize) { offset ->
elementAlgebra.initializer(indexer.index(offset)) elementAlgebra.initializer(indexer.index(offset))
@ -26,6 +27,9 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
) )
} }
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): BufferND<T> =
mutableStructureND(shape, initializer)
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
public fun StructureND<T>.toBufferND(): BufferND<T> = when (this) { public fun StructureND<T>.toBufferND(): BufferND<T> = when (this) {
is BufferND -> this is BufferND -> this
@ -133,6 +137,11 @@ public fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.structureND(
initializer: A.(IntArray) -> T, initializer: A.(IntArray) -> T,
): BufferND<T> = structureND(ShapeND(shape), initializer) ): BufferND<T> = structureND(ShapeND(shape), initializer)
public fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.mutableStructureND(
vararg shape: Int,
initializer: A.(IntArray) -> T,
): MutableBufferND<T> = mutableStructureND(ShapeND(shape), initializer)
public fun <T, EA : Algebra<T>, A> A.structureND( public fun <T, EA : Algebra<T>, A> A.structureND(
initializer: EA.(IntArray) -> T, initializer: EA.(IntArray) -> T,
): BufferND<T> where A : BufferAlgebraND<T, EA>, A : WithShape = structureND(shape, initializer) ): BufferND<T> where A : BufferAlgebraND<T, EA>, A : WithShape = structureND(shape, initializer)

View File

@ -74,7 +74,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
transform: DoubleField.(Double, Double) -> Double, transform: DoubleField.(Double, Double) -> Double,
): BufferND<Double> = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) } ): BufferND<Double> = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) }
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { override fun mutableStructureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND {
val indexer = indexerBuilder(shape) val indexer = indexerBuilder(shape)
return DoubleBufferND( return DoubleBufferND(
indexer, indexer,
@ -225,7 +225,7 @@ public class DoubleFieldND(override val shape: ShapeND) :
override fun number(value: Number): DoubleBufferND { override fun number(value: Number): DoubleBufferND {
val d = value.toDouble() // minimize conversions val d = value.toDouble() // minimize conversions
return structureND(shape) { d } return mutableStructureND(shape) { d }
} }
} }

View File

@ -244,6 +244,7 @@ public interface MutableStructureND<T> : StructureND<T> {
* Set value at specified indices * Set value at specified indices
*/ */
@PerformancePitfall @PerformancePitfall
@Deprecated("")
public operator fun <T> MutableStructureND<T>.set(vararg index: Int, value: T) { public operator fun <T> MutableStructureND<T>.set(vararg index: Int, value: T) {
set(index, value) set(index, value)
} }

View File

@ -17,6 +17,12 @@ public fun <T, A : Algebra<T>> AlgebraND<T, A>.structureND(
initializer: A.(IntArray) -> T initializer: A.(IntArray) -> T
): StructureND<T> = structureND(ShapeND(shapeFirst, *shapeRest), initializer) ): StructureND<T> = structureND(ShapeND(shapeFirst, *shapeRest), initializer)
public fun <T, A : Algebra<T>> AlgebraND<T, A>.mutableStructureND(
shapeFirst: Int,
vararg shapeRest: Int,
initializer: A.(IntArray) -> T
): MutableStructureND<T> = mutableStructureND(ShapeND(shapeFirst, *shapeRest), initializer)
public fun <T, A : Group<T>> AlgebraND<T, A>.zero(shape: ShapeND): StructureND<T> = structureND(shape) { zero } public fun <T, A : Group<T>> AlgebraND<T, A>.zero(shape: ShapeND): StructureND<T> = structureND(shape) { zero }
@JvmName("zeroVarArg") @JvmName("zeroVarArg")

View File

@ -6,7 +6,8 @@
package space.kscience.kmath.operations package 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.MutableBuffer
import space.kscience.kmath.structures.MutableBufferFactory
public interface WithSize { public interface WithSize {
public val size: Int public val size: Int
@ -17,7 +18,7 @@ public interface WithSize {
*/ */
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> { public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
public val elementAlgebra: A public val elementAlgebra: A
public val elementBufferFactory: BufferFactory<T> get() = elementAlgebra.bufferFactory public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
public fun buffer(size: Int, vararg elements: T): Buffer<T> { public fun buffer(size: Int, vararg elements: T): Buffer<T> {
require(elements.size == size) { "Expected $size elements but found ${elements.size}" } require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
@ -73,11 +74,11 @@ private inline fun <T, A : Algebra<T>> BufferAlgebra<T, A>.zipInline(
return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } return elementBufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) }
} }
public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): Buffer<T> { public fun <T> BufferAlgebra<T, *>.buffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> {
return elementBufferFactory(size, initializer) return elementBufferFactory(size, initializer)
} }
public fun <T, A> A.buffer(initializer: (Int) -> T): Buffer<T> where A : BufferAlgebra<T, *>, A : WithSize { public fun <T, A> A.buffer(initializer: (Int) -> T): MutableBuffer<T> where A : BufferAlgebra<T, *>, A : WithSize {
return elementBufferFactory(size, initializer) return elementBufferFactory(size, initializer)
} }

View File

@ -33,7 +33,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
protected val multikStat: Statistics = multikEngine.getStatistics() protected val multikStat: Statistics = multikEngine.getStatistics()
@OptIn(UnsafeKMathAPI::class) @OptIn(UnsafeKMathAPI::class)
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): MultikTensor<T> { override fun mutableStructureND(shape: ShapeND, initializer: A.(IntArray) -> T): MultikTensor<T> {
val strides = ColumnStrides(shape) val strides = ColumnStrides(shape)
val memoryView = initMemoryView<T>(strides.linearSize, type) val memoryView = initMemoryView<T>(strides.linearSize, type)
strides.asSequence().forEachIndexed { linearIndex, tensorIndex -> strides.asSequence().forEachIndexed { linearIndex, tensorIndex ->
@ -49,7 +49,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
for (el in array) data[count++] = elementAlgebra.transform(el) for (el in array) data[count++] = elementAlgebra.transform(el)
NDArray(data, shape = shape.asArray(), dim = array.dim).wrap() NDArray(data, shape = shape.asArray(), dim = array.dim).wrap()
} else { } else {
structureND(shape) { index -> mutableStructureND(shape) { index ->
transform(get(index)) transform(get(index))
} }
} }
@ -70,7 +70,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
} }
NDArray(data, shape = array.shape, dim = array.dim).wrap() NDArray(data, shape = array.shape, dim = array.dim).wrap()
} else { } else {
structureND(shape) { index -> mutableStructureND(shape) { index ->
transform(index, get(index)) transform(index, get(index))
} }
} }

View File

@ -34,7 +34,7 @@ public sealed interface Nd4jArrayAlgebra<T, out C : Algebra<T>> : AlgebraND<T, C
public val StructureND<T>.ndArray: INDArray public val StructureND<T>.ndArray: INDArray
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
override fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> { override fun mutableStructureND(shape: ShapeND, initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> {
@OptIn(UnsafeKMathAPI::class) @OptIn(UnsafeKMathAPI::class)
val struct: Nd4jArrayStructure<T> = Nd4j.create(*shape.asArray())!!.wrap() val struct: Nd4jArrayStructure<T> = Nd4j.create(*shape.asArray())!!.wrap()
struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) } struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) }

View File

@ -37,20 +37,20 @@ public sealed interface Nd4jTensorAlgebra<T : Number, A : Field<T>> : AnalyticTe
*/ */
public val StructureND<T>.ndArray: INDArray public val StructureND<T>.ndArray: INDArray
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): Nd4jArrayStructure<T> override fun mutableStructureND(shape: ShapeND, initializer: A.(IntArray) -> T): Nd4jArrayStructure<T>
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
override fun StructureND<T>.map(transform: A.(T) -> T): Nd4jArrayStructure<T> = override fun StructureND<T>.map(transform: A.(T) -> T): Nd4jArrayStructure<T> =
structureND(shape) { index -> elementAlgebra.transform(get(index)) } mutableStructureND(shape) { index -> elementAlgebra.transform(get(index)) }
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
override fun StructureND<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure<T> = override fun StructureND<T>.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure<T> =
structureND(shape) { index -> elementAlgebra.transform(index, get(index)) } mutableStructureND(shape) { index -> elementAlgebra.transform(index, get(index)) }
@OptIn(PerformancePitfall::class) @OptIn(PerformancePitfall::class)
override fun zip(left: StructureND<T>, right: StructureND<T>, transform: A.(T, T) -> T): Nd4jArrayStructure<T> { override fun zip(left: StructureND<T>, right: StructureND<T>, transform: A.(T, T) -> T): Nd4jArrayStructure<T> {
require(left.shape.contentEquals(right.shape)) require(left.shape.contentEquals(right.shape))
return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) } return mutableStructureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) }
} }
override fun T.plus(arg: StructureND<T>): Nd4jArrayStructure<T> = arg.ndArray.add(this).wrap() override fun T.plus(arg: StructureND<T>): Nd4jArrayStructure<T> = arg.ndArray.add(this).wrap()
@ -178,7 +178,7 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra<Double, DoubleField> {
override fun INDArray.wrap(): Nd4jArrayStructure<Double> = asDoubleStructure() override fun INDArray.wrap(): Nd4jArrayStructure<Double> = asDoubleStructure()
@OptIn(UnsafeKMathAPI::class) @OptIn(UnsafeKMathAPI::class)
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure<Double> { override fun mutableStructureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure<Double> {
val array: INDArray = Nd4j.zeros(*shape.asArray()) val array: INDArray = Nd4j.zeros(*shape.asArray())
val indices = ColumnStrides(shape) val indices = ColumnStrides(shape)
indices.asSequence().forEach { index -> indices.asSequence().forEach { index ->

View File

@ -14,6 +14,7 @@ import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.nd.ColumnStrides import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.MutableStructureND
import space.kscience.kmath.nd.ShapeND import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.DoubleField
@ -36,10 +37,10 @@ public class DoubleTensorFlowAlgebra internal constructor(
override val elementAlgebra: DoubleField get() = DoubleField override val elementAlgebra: DoubleField get() = DoubleField
override fun structureND( override fun mutableStructureND(
shape: ShapeND, shape: ShapeND,
initializer: DoubleField.(IntArray) -> Double, initializer: DoubleField.(IntArray) -> Double,
): StructureND<Double> { ): MutableStructureND<Double> {
val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array ->
ColumnStrides(shape).forEach { index -> ColumnStrides(shape).forEach { index ->
array.setDouble(elementAlgebra.initializer(index), *index.toLongArray()) array.setDouble(elementAlgebra.initializer(index), *index.toLongArray())

View File

@ -15,12 +15,12 @@ kscience{
kotlin.sourceSets { kotlin.sourceSets {
all { all {
languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") languageSettings.optIn("space.kscience.kmath.UnstableKMathAPI")
} }
filter { it.name.contains("test", true) } filter { it.name.contains("test", true) }
.map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings)
.forEach { it.optIn("space.kscience.kmath.misc.PerformancePitfall") } .forEach { it.optIn("space.kscience.kmath.PerformancePitfall") }
commonMain { commonMain {
dependencies { dependencies {

View File

@ -127,7 +127,7 @@ public open class DoubleTensorAlgebra :
* @param initializer mapping tensor indices to values. * @param initializer mapping tensor indices to values.
* @return tensor with the [shape] shape and data generated by the [initializer]. * @return tensor with the [shape] shape and data generated by the [initializer].
*/ */
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray( override fun mutableStructureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray(
shape, shape,
RowStrides(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() RowStrides(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray()
) )

View File

@ -118,7 +118,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @param initializer mapping tensor indices to values. * @param initializer mapping tensor indices to values.
* @return tensor with the [shape] shape and data generated by the [initializer]. * @return tensor with the [shape] shape and data generated by the [initializer].
*/ */
override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray( override fun mutableStructureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray(
shape, shape,
RowStrides(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray() RowStrides(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray()
) )

View File

@ -92,7 +92,7 @@ internal class TestDoubleTensor {
@Test @Test
fun test2D() = with(DoubleTensorAlgebra) { fun test2D() = with(DoubleTensorAlgebra) {
val tensor: DoubleTensor = structureND(ShapeND(3, 3)) { (i, j) -> (i - j).toDouble() } val tensor: DoubleTensor = mutableStructureND(ShapeND(3, 3)) { (i, j) -> (i - j).toDouble() }
//println(tensor.toPrettyString()) //println(tensor.toPrettyString())
val tensor2d = tensor.asDoubleTensor2D() val tensor2d = tensor.asDoubleTensor2D()
assertBufferEquals(DoubleBuffer(1.0, 0.0, -1.0), tensor2d.rows[1]) assertBufferEquals(DoubleBuffer(1.0, 0.0, -1.0), tensor2d.rows[1])
@ -101,7 +101,7 @@ internal class TestDoubleTensor {
@Test @Test
fun testMatrixIteration() = with(DoubleTensorAlgebra) { fun testMatrixIteration() = with(DoubleTensorAlgebra) {
val tensor = structureND(ShapeND(3, 3, 3, 3)) { index -> index.sum().toDouble() } val tensor = mutableStructureND(ShapeND(3, 3, 3, 3)) { index -> index.sum().toDouble() }
tensor.forEachMatrix { index, matrix -> tensor.forEachMatrix { index, matrix ->
println(index.joinToString { it.toString() }) println(index.joinToString { it.toString() })
println(matrix) println(matrix)

View File

@ -17,8 +17,7 @@ import space.kscience.kmath.operations.ExtendedFieldOps
import space.kscience.kmath.operations.NumbersAddOps import space.kscience.kmath.operations.NumbersAddOps
import space.kscience.kmath.operations.PowerOperations import space.kscience.kmath.operations.PowerOperations
@OptIn(UnstableKMathAPI::class, PerformancePitfall::class) @OptIn(PerformancePitfall::class)
@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public open class ViktorFieldOpsND : public open class ViktorFieldOpsND :
FieldOpsND<Double, DoubleField>, FieldOpsND<Double, DoubleField>,
ExtendedFieldOps<StructureND<Double>>, ExtendedFieldOps<StructureND<Double>>,
@ -27,13 +26,13 @@ public open class ViktorFieldOpsND :
public val StructureND<Double>.f64Buffer: F64Array public val StructureND<Double>.f64Buffer: F64Array
get() = when (this) { get() = when (this) {
is ViktorStructureND -> this.f64Buffer is ViktorStructureND -> this.f64Buffer
else -> structureND(shape) { this@f64Buffer[it] }.f64Buffer else -> mutableStructureND(shape) { this@f64Buffer[it] }.f64Buffer
} }
override val elementAlgebra: DoubleField get() = DoubleField override val elementAlgebra: DoubleField get() = DoubleField
@OptIn(UnsafeKMathAPI::class) @OptIn(UnsafeKMathAPI::class)
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = override fun mutableStructureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND =
F64Array(*shape.asArray()).apply { F64Array(*shape.asArray()).apply {
ColumnStrides(shape).asSequence().forEach { index -> ColumnStrides(shape).asSequence().forEach { index ->
set(value = DoubleField.initializer(index), indices = index) set(value = DoubleField.initializer(index), indices = index)