Safe shapes

This commit is contained in:
Alexander Nozik 2022-10-14 13:05:39 +03:00
parent b0abcf2d0c
commit ee569b85f8
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
66 changed files with 416 additions and 408 deletions

View File

@ -85,7 +85,7 @@ internal class NDFieldBenchmark {
private companion object {
private const val dim = 1000
private const val n = 100
private val shape = Shape(dim, dim)
private val shape = ShapeND(dim, dim)
private val specializedField = DoubleField.ndAlgebra
private val genericField = BufferedFieldOpsND(DoubleField)
private val nd4jField = DoubleField.nd4j

View File

@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one
@ -49,7 +49,7 @@ internal class ViktorBenchmark {
private companion object {
private const val dim = 1000
private const val n = 100
private val shape = Shape(dim, dim)
private val shape = ShapeND(dim, dim)
// automatically build context most suited for given type.
private val doubleField = DoubleField.ndAlgebra

View File

@ -10,7 +10,7 @@ import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.State
import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.ndAlgebra
import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.DoubleField
@ -49,7 +49,7 @@ internal class ViktorLogBenchmark {
private companion object {
private const val dim = 1000
private const val n = 100
private val shape = Shape(dim, dim)
private val shape = ShapeND(dim, dim)
// automatically build context most suited for given type.
private val doubleField = DoubleField.ndAlgebra

View File

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

View File

@ -29,7 +29,7 @@ fun main() {
Nd4j.zeros(0)
val dim = 1000
val n = 1000
val shape = Shape(dim, dim)
val shape = ShapeND(dim, dim)
// specialized nd-field for Double. It works as generic Double field as well.

View File

@ -17,7 +17,7 @@ import java.util.stream.IntStream
* A demonstration implementation of NDField over Real using Java [java.util.stream.DoubleStream] for parallel
* execution.
*/
class StreamDoubleFieldND(override val shape: Shape) : FieldND<Double, DoubleField>,
class StreamDoubleFieldND(override val shape: ShapeND) : FieldND<Double, DoubleField>,
NumbersAddOps<StructureND<Double>>,
ExtendedField<StructureND<Double>> {
@ -43,7 +43,7 @@ class StreamDoubleFieldND(override val shape: Shape) : FieldND<Double, DoubleFie
else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
}
override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): BufferND<Double> {
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): BufferND<Double> {
val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
val index = strides.index(offset)
DoubleField.initializer(index)
@ -111,4 +111,4 @@ class StreamDoubleFieldND(override val shape: Shape) : FieldND<Double, DoubleFie
override fun atanh(arg: StructureND<Double>): BufferND<Double> = arg.map { atanh(it) }
}
fun DoubleField.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(Shape(shape))
fun DoubleField.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(ShapeND(shape))

View File

@ -8,7 +8,7 @@ package space.kscience.kmath.structures
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import kotlin.system.measureTimeMillis
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
@ -17,7 +17,7 @@ fun main() {
val n = 6000
val array = DoubleArray(n * n) { 1.0 }
val buffer = DoubleBuffer(array)
val strides = ColumnStrides(Shape(n, n))
val strides = ColumnStrides(ShapeND(n, n))
val structure = BufferND(strides, buffer)
measureTimeMillis {

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.structures
import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.map
import kotlin.system.measureTimeMillis
@ -16,7 +16,7 @@ private inline fun <T, reified R: Any> BufferND<T>.map(block: (T) -> R): BufferN
@Suppress("UNUSED_VARIABLE")
fun main() {
val n = 6000
val structure = StructureND.buffered(Shape(n, n), Buffer.Companion::auto) { 1.0 }
val structure = StructureND.buffered(ShapeND(n, n), Buffer.Companion::auto) { 1.0 }
structure.map { it + 1 } // warm-up
val time1 = measureTimeMillis { val res = structure.map { it + 1 } }
println("Structure mapping finished in $time1 millis")

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.contentEquals
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.DoubleTensor
@ -25,10 +25,10 @@ fun main() {
DoubleTensorAlgebra {
// take coefficient vector from normal distribution
val alpha = randomNormal(
Shape(5),
ShapeND(5),
randSeed
) + fromArray(
Shape(5),
ShapeND(5),
doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1)
)
@ -36,7 +36,7 @@ fun main() {
// also take sample of size 20 from normal distribution for x
val x = randomNormal(
Shape(20, 5),
ShapeND(20, 5),
randSeed
)

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.tensors.core.tensorAlgebra
import space.kscience.kmath.tensors.core.withBroadcast
@ -17,7 +17,7 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with
// assume x is range from 0 until 10
val x = fromArray(
Shape(10),
ShapeND(10),
DoubleArray(10) { it.toDouble() }
)
@ -42,13 +42,13 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with
// save means ans standard deviations for further recovery
val mean = fromArray(
Shape(2),
ShapeND(2),
doubleArrayOf(xMean, yMean)
)
println("Means:\n$mean")
val std = fromArray(
Shape(2),
ShapeND(2),
doubleArrayOf(xStd, yStd)
)
println("Standard deviations:\n$std")
@ -69,7 +69,7 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with
// we can restore original data from reduced data;
// for example, find 7th element of dataset.
val n = 7
val restored = (datasetReduced.getTensor(n) dot v.view(Shape(1, 2))) * std + mean
val restored = (datasetReduced.getTensor(n) dot v.view(ShapeND(1, 2))) * std + mean
println("Original value:\n${dataset.getTensor(n)}")
println("Restored value:\n$restored")
}

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.tensors.core.tensorAlgebra
import space.kscience.kmath.tensors.core.withBroadcast
@ -14,10 +14,10 @@ import space.kscience.kmath.tensors.core.withBroadcast
fun main() = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods
// take dataset of 5-element vectors from normal distribution
val dataset = randomNormal(Shape(100, 5)) * 1.5 // all elements from N(0, 1.5)
val dataset = randomNormal(ShapeND(100, 5)) * 1.5 // all elements from N(0, 1.5)
dataset += fromArray(
Shape(5),
ShapeND(5),
doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means
)

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.tensors.core.DoubleTensor
import space.kscience.kmath.tensors.core.tensorAlgebra
import space.kscience.kmath.tensors.core.withBroadcast
@ -16,13 +16,13 @@ fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear
// set true value of x
val trueX = fromArray(
Shape(4),
ShapeND(4),
doubleArrayOf(-2.0, 1.5, 6.8, -2.4)
)
// and A matrix
val a = fromArray(
Shape(4, 4),
ShapeND(4, 4),
doubleArrayOf(
0.5, 10.5, 4.5, 1.0,
8.5, 0.9, 12.8, 0.1,
@ -65,7 +65,7 @@ fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear
// this function returns solution x of a system lx = b, l should be lower triangular
fun solveLT(l: DoubleTensor, b: DoubleTensor): DoubleTensor {
val n = l.shape[0]
val x = zeros(Shape(n))
val x = zeros(ShapeND(n))
for (i in 0 until n) {
x[intArrayOf(i)] = (b[intArrayOf(i)] - l.getTensor(i).dot(x).value()) / l[intArrayOf(i, i)]
}

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.contentEquals
import space.kscience.kmath.operations.asIterable
import space.kscience.kmath.operations.invoke
@ -70,12 +70,12 @@ class Dense(
private val weights: DoubleTensor = DoubleTensorAlgebra {
randomNormal(
Shape(inputUnits, outputUnits),
ShapeND(inputUnits, outputUnits),
seed
) * sqrt(2.0 / (inputUnits + outputUnits))
}
private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(Shape(outputUnits)) }
private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(ShapeND(outputUnits)) }
override fun forward(input: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra {
(input dot weights) + bias
@ -184,17 +184,17 @@ fun main() = BroadcastDoubleTensorAlgebra {
//val testSize = sampleSize - trainSize
// take sample of features from normal distribution
val x = randomNormal(Shape(sampleSize, features), seed) * 2.5
val x = randomNormal(ShapeND(sampleSize, features), seed) * 2.5
x += fromArray(
Shape(5),
ShapeND(5),
doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means
)
// define class like '1' if the sum of features > 0 and '0' otherwise
val y = fromArray(
Shape(sampleSize, 1),
ShapeND(sampleSize, 1),
DoubleArray(sampleSize) { i ->
if (x.getTensor(i).sum() > 0.0) {
1.0

View File

@ -59,7 +59,7 @@ public sealed class ComplexFieldOpsND : BufferedFieldOpsND<Complex, ComplexField
}
@OptIn(UnstableKMathAPI::class)
public class ComplexFieldND(override val shape: Shape) :
public class ComplexFieldND(override val shape: ShapeND) :
ComplexFieldOpsND(), FieldND<Complex, ComplexField>,
NumbersAddOps<StructureND<Complex>> {
@ -71,12 +71,12 @@ public class ComplexFieldND(override val shape: Shape) :
public val ComplexField.ndAlgebra: ComplexFieldOpsND get() = ComplexFieldOpsND
public fun ComplexField.ndAlgebra(vararg shape: Int): ComplexFieldND = ComplexFieldND(Shape(shape))
public fun ComplexField.ndAlgebra(vararg shape: Int): ComplexFieldND = ComplexFieldND(ShapeND(shape))
/**
* Produce a context for n-dimensional operations inside this real field
*/
public inline fun <R> ComplexField.withNdAlgebra(vararg shape: Int, action: ComplexFieldND.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return ComplexFieldND(Shape(shape)).action()
return ComplexFieldND(ShapeND(shape)).action()
}

View File

@ -21,7 +21,7 @@ public class BufferedLinearSpace<T, out A : Ring<T>>(
private val ndAlgebra = BufferedRingOpsND(bufferAlgebra)
override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix<T> =
ndAlgebra.structureND(Shape(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D()
ndAlgebra.structureND(ShapeND(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D()
override fun buildVector(size: Int, initializer: A.(Int) -> T): Point<T> =
bufferAlgebra.buffer(size) { elementAlgebra.initializer(it) }

View File

@ -21,7 +21,7 @@ public object DoubleLinearSpace : LinearSpace<Double, DoubleField> {
rows: Int,
columns: Int,
initializer: DoubleField.(i: Int, j: Int) -> Double
): Matrix<Double> = DoubleFieldOpsND.structureND(Shape(rows, columns)) { (i, j) ->
): Matrix<Double> = DoubleFieldOpsND.structureND(ShapeND(rows, columns)) { (i, j) ->
DoubleField.initializer(i, j)
}.as2D()

View File

@ -5,7 +5,8 @@
package space.kscience.kmath.linear
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
/**
* The matrix where each element is evaluated each time when is being accessed.
@ -18,7 +19,7 @@ public class VirtualMatrix<out T : Any>(
public val generator: (i: Int, j: Int) -> T,
) : Matrix<T> {
override val shape: Shape get() = Shape(rowNum, colNum)
override val shape: ShapeND get() = ShapeND(rowNum, colNum)
override operator fun get(i: Int, j: Int): T = generator(i, j)
}

View File

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

View File

@ -12,11 +12,11 @@ import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.*
public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
public val indexerBuilder: (Shape) -> ShapeIndexer
public val indexerBuilder: (ShapeND) -> ShapeIndexer
public val bufferAlgebra: BufferAlgebra<T, A>
override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra
override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): BufferND<T> {
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): BufferND<T> {
val indexer = indexerBuilder(shape)
return BufferND(
indexer,
@ -47,7 +47,7 @@ public interface BufferAlgebraND<T, out A : Algebra<T>> : AlgebraND<T, A> {
zipInline(left.toBufferND(), right.toBufferND(), transform)
public companion object {
public val defaultIndexerBuilder: (Shape) -> ShapeIndexer = ::Strides
public val defaultIndexerBuilder: (ShapeND) -> ShapeIndexer = ::Strides
}
}
@ -99,24 +99,24 @@ internal inline fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.zipInline(
@OptIn(PerformancePitfall::class)
public open class BufferedGroupNDOps<T, out A : Group<T>>(
override val bufferAlgebra: BufferAlgebra<T, A>,
override val indexerBuilder: (Shape) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
override val indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
) : GroupOpsND<T, A>, BufferAlgebraND<T, A> {
override fun StructureND<T>.unaryMinus(): StructureND<T> = map { -it }
}
public open class BufferedRingOpsND<T, out A : Ring<T>>(
bufferAlgebra: BufferAlgebra<T, A>,
indexerBuilder: (Shape) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
) : BufferedGroupNDOps<T, A>(bufferAlgebra, indexerBuilder), RingOpsND<T, A>
public open class BufferedFieldOpsND<T, out A : Field<T>>(
bufferAlgebra: BufferAlgebra<T, A>,
indexerBuilder: (Shape) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
) : BufferedRingOpsND<T, A>(bufferAlgebra, indexerBuilder), FieldOpsND<T, A> {
public constructor(
elementAlgebra: A,
indexerBuilder: (Shape) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
indexerBuilder: (ShapeND) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder,
) : this(BufferFieldOps(elementAlgebra), indexerBuilder)
@OptIn(PerformancePitfall::class)
@ -131,7 +131,7 @@ public val <T, A : Field<T>> BufferAlgebra<T, A>.nd: BufferedFieldOpsND<T, A> ge
public fun <T, A : Algebra<T>> BufferAlgebraND<T, A>.structureND(
vararg shape: Int,
initializer: A.(IntArray) -> T,
): BufferND<T> = structureND(Shape(shape), initializer)
): BufferND<T> = structureND(ShapeND(shape), initializer)
public fun <T, EA : Algebra<T>, A> A.structureND(
initializer: EA.(IntArray) -> T,

View File

@ -24,7 +24,7 @@ public open class BufferND<out T>(
@PerformancePitfall
override operator fun get(index: IntArray): T = buffer[indices.offset(index)]
override val shape: Shape get() = indices.shape
override val shape: ShapeND get() = indices.shape
override fun toString(): String = StructureND.toString(this)
}

View File

@ -74,7 +74,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
transform: DoubleField.(Double, Double) -> Double,
): BufferND<Double> = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) }
override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND {
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND {
val indexer = indexerBuilder(shape)
return DoubleBufferND(
indexer,
@ -189,7 +189,7 @@ public sealed class DoubleFieldOpsND : BufferedFieldOpsND<Double, DoubleField>(D
}
@OptIn(UnstableKMathAPI::class)
public class DoubleFieldND(override val shape: Shape) :
public class DoubleFieldND(override val shape: ShapeND) :
DoubleFieldOpsND(), FieldND<Double, DoubleField>, NumbersAddOps<StructureND<Double>>,
ExtendedField<StructureND<Double>> {
@ -231,8 +231,8 @@ public class DoubleFieldND(override val shape: Shape) :
public val DoubleField.ndAlgebra: DoubleFieldOpsND get() = DoubleFieldOpsND
public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(Shape(shape))
public fun DoubleField.ndAlgebra(shape: Shape): DoubleFieldND = DoubleFieldND(shape)
public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(ShapeND(shape))
public fun DoubleField.ndAlgebra(shape: ShapeND): DoubleFieldND = DoubleFieldND(shape)
/**
* Produce a context for n-dimensional operations inside this real field
@ -240,5 +240,5 @@ public fun DoubleField.ndAlgebra(shape: Shape): DoubleFieldND = DoubleFieldND(sh
@UnstableKMathAPI
public inline fun <R> DoubleField.withNdAlgebra(vararg shape: Int, action: DoubleFieldND.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return DoubleFieldND(Shape(shape)).run(action)
return DoubleFieldND(ShapeND(shape)).run(action)
}

View File

@ -20,7 +20,7 @@ public class IntBufferND(
public sealed class IntRingOpsND : BufferedRingOpsND<Int, IntRing>(IntRing.bufferAlgebra) {
override fun structureND(shape: Shape, initializer: IntRing.(IntArray) -> Int): IntBufferND {
override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntBufferND {
val indexer = indexerBuilder(shape)
return IntBufferND(
indexer,
@ -35,7 +35,7 @@ public sealed class IntRingOpsND : BufferedRingOpsND<Int, IntRing>(IntRing.buffe
@OptIn(UnstableKMathAPI::class)
public class IntRingND(
override val shape: Shape
override val shape: ShapeND
) : IntRingOpsND(), RingND<Int, IntRing>, NumbersAddOps<StructureND<Int>> {
override fun number(value: Number): BufferND<Int> {
@ -46,5 +46,5 @@ public class IntRingND(
public inline fun <R> IntRing.withNdAlgebra(vararg shape: Int, action: IntRingND.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return IntRingND(Shape(shape)).run(action)
return IntRingND(ShapeND(shape)).run(action)
}

View File

@ -13,7 +13,7 @@ public class PermutedStructureND<T>(
public val permutation: (IntArray) -> IntArray,
) : StructureND<T> {
override val shape: Shape
override val shape: ShapeND
get() = origin.shape
@OptIn(PerformancePitfall::class)
@ -28,7 +28,7 @@ public fun <T> StructureND<T>.permute(
public class PermutedMutableStructureND<T>(
public val origin: MutableStructureND<T>,
override val shape: Shape = origin.shape,
override val shape: ShapeND = origin.shape,
public val permutation: (IntArray) -> IntArray,
) : MutableStructureND<T> {
@ -45,6 +45,6 @@ public class PermutedMutableStructureND<T>(
}
public fun <T> MutableStructureND<T>.permute(
newShape: Shape = shape,
newShape: ShapeND = shape,
permutation: (IntArray) -> IntArray,
): PermutedMutableStructureND<T> = PermutedMutableStructureND(this, newShape, permutation)

View File

@ -1,102 +0,0 @@
/*
* Copyright 2018-2022 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.nd
import space.kscience.kmath.misc.UnsafeKMathAPI
import kotlin.jvm.JvmInline
/**
* A read-only ND shape
*/
@JvmInline
public value class Shape(@PublishedApi internal val array: IntArray) {
public val size: Int get() = array.size
public operator fun get(index: Int): Int = array[index]
override fun toString(): String = array.contentToString()
}
public inline fun Shape.forEach(block: (value: Int) -> Unit): Unit = array.forEach(block)
public inline fun Shape.forEachIndexed(block: (index: Int, value: Int) -> Unit): Unit = array.forEachIndexed(block)
public infix fun Shape.contentEquals(other: Shape): Boolean = array.contentEquals(other.array)
public fun Shape.contentHashCode(): Int = array.contentHashCode()
public val Shape.indices: IntRange get() = array.indices
public val Shape.linearSize: Int get() = array.reduce(Int::times)
public fun Shape.slice(range: IntRange): Shape = Shape(array.sliceArray(range))
public fun Shape.last(): Int = array.last()
/**
* A shape including last [n] dimensions of this shape
*/
public fun Shape.last(n: Int): Shape = Shape(array.copyOfRange(size - n, size))
public fun Shape.first(): Int = array.first()
/**
* A shape including first [n] dimensions of this shape
*/
public fun Shape.first(n: Int): Shape = Shape(array.copyOfRange(0, n))
public operator fun Shape.plus(add: IntArray): Shape = Shape(array + add)
public operator fun Shape.plus(add: Shape): Shape = Shape(array + add.array)
public fun Shape.isEmpty(): Boolean = size == 0
public fun Shape.isNotEmpty(): Boolean = size > 0
public fun Shape.transposed(i: Int, j: Int): Shape = Shape(array.copyOf().apply {
val ith = get(i)
val jth = get(j)
set(i, jth)
set(j, ith)
})
public operator fun Shape.component1(): Int = get(0)
public operator fun Shape.component2(): Int = get(1)
public operator fun Shape.component3(): Int = get(2)
/**
* Convert to array with protective copy
*/
public fun Shape.toArray(): IntArray = array.copyOf()
@UnsafeKMathAPI
public fun Shape.asArray(): IntArray = array
public fun Shape.asList(): List<Int> = array.asList()
/**
* An exception is thrown when the expected and actual shape of NDArray differ.
*
* @property expected the expected shape.
* @property actual the actual shape.
*/
public class ShapeMismatchException(public val expected: Shape, public val actual: Shape) :
RuntimeException("Shape $actual doesn't fit in expected shape ${expected}.")
public class IndexOutOfShapeException(public val shape: Shape, public val index: IntArray) :
RuntimeException("Index ${index.contentToString()} is out of shape ${shape}")
public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = Shape(intArrayOf(shapeFirst, *shapeRest))
public interface WithShape {
public val shape: Shape
public val indices: ShapeIndexer get() = ColumnStrides(shape)
}
internal fun requireIndexInShape(index: IntArray, shape: Shape) {
if (index.size != shape.size) throw IndexOutOfShapeException(shape, index)
shape.forEachIndexed { axis, axisShape ->
if (index[axis] !in 0 until axisShape) throw IndexOutOfShapeException(shape, index)
}
}

View File

@ -12,7 +12,7 @@ import kotlin.native.concurrent.ThreadLocal
* A converter from linear index to multivariate index
*/
public interface ShapeIndexer : Iterable<IntArray> {
public val shape: Shape
public val shape: ShapeND
/**
* Get linear index from multidimensional index
@ -68,7 +68,7 @@ public abstract class Strides : ShapeIndexer {
/**
* Column-first [Strides]. Columns are represented as continuous arrays
*/
public class ColumnStrides(override val shape: Shape) : Strides() {
public class ColumnStrides(override val shape: ShapeND) : Strides() {
override val linearSize: Int get() = strides[shape.size]
/**
@ -118,7 +118,7 @@ public class ColumnStrides(override val shape: Shape) : Strides() {
*
* @param shape the shape of the tensor.
*/
public class RowStrides(override val shape: Shape) : Strides() {
public class RowStrides(override val shape: ShapeND) : Strides() {
override val strides: IntArray by lazy {
val nDim = shape.size
@ -163,9 +163,9 @@ public class RowStrides(override val shape: Shape) : Strides() {
}
@ThreadLocal
private val defaultStridesCache = HashMap<Shape, Strides>()
private val defaultStridesCache = HashMap<ShapeND, Strides>()
/**
* Cached builder for default strides
*/
public fun Strides(shape: Shape): Strides = defaultStridesCache.getOrPut(shape) { RowStrides(shape) }
public fun Strides(shape: ShapeND): Strides = defaultStridesCache.getOrPut(shape) { RowStrides(shape) }

View File

@ -0,0 +1,102 @@
/*
* Copyright 2018-2022 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.nd
import space.kscience.kmath.misc.UnsafeKMathAPI
import kotlin.jvm.JvmInline
/**
* A read-only ND shape
*/
@JvmInline
public value class ShapeND(@PublishedApi internal val array: IntArray) {
public val size: Int get() = array.size
public operator fun get(index: Int): Int = array[index]
override fun toString(): String = array.contentToString()
}
public inline fun ShapeND.forEach(block: (value: Int) -> Unit): Unit = array.forEach(block)
public inline fun ShapeND.forEachIndexed(block: (index: Int, value: Int) -> Unit): Unit = array.forEachIndexed(block)
public infix fun ShapeND.contentEquals(other: ShapeND): Boolean = array.contentEquals(other.array)
public fun ShapeND.contentHashCode(): Int = array.contentHashCode()
public val ShapeND.indices: IntRange get() = array.indices
public val ShapeND.linearSize: Int get() = array.reduce(Int::times)
public fun ShapeND.slice(range: IntRange): ShapeND = ShapeND(array.sliceArray(range))
public fun ShapeND.last(): Int = array.last()
/**
* A shape including last [n] dimensions of this shape
*/
public fun ShapeND.last(n: Int): ShapeND = ShapeND(array.copyOfRange(size - n, size))
public fun ShapeND.first(): Int = array.first()
/**
* A shape including first [n] dimensions of this shape
*/
public fun ShapeND.first(n: Int): ShapeND = ShapeND(array.copyOfRange(0, n))
public operator fun ShapeND.plus(add: IntArray): ShapeND = ShapeND(array + add)
public operator fun ShapeND.plus(add: ShapeND): ShapeND = ShapeND(array + add.array)
public fun ShapeND.isEmpty(): Boolean = size == 0
public fun ShapeND.isNotEmpty(): Boolean = size > 0
public fun ShapeND.transposed(i: Int, j: Int): ShapeND = ShapeND(array.copyOf().apply {
val ith = get(i)
val jth = get(j)
set(i, jth)
set(j, ith)
})
public operator fun ShapeND.component1(): Int = get(0)
public operator fun ShapeND.component2(): Int = get(1)
public operator fun ShapeND.component3(): Int = get(2)
/**
* Convert to array with protective copy
*/
public fun ShapeND.toArray(): IntArray = array.copyOf()
@UnsafeKMathAPI
public fun ShapeND.asArray(): IntArray = array
public fun ShapeND.asList(): List<Int> = array.asList()
/**
* An exception is thrown when the expected and actual shape of NDArray differ.
*
* @property expected the expected shape.
* @property actual the actual shape.
*/
public class ShapeMismatchException(public val expected: ShapeND, public val actual: ShapeND) :
RuntimeException("Shape $actual doesn't fit in expected shape ${expected}.")
public class IndexOutOfShapeException(public val shape: ShapeND, public val index: IntArray) :
RuntimeException("Index ${index.contentToString()} is out of shape ${shape}")
public fun ShapeND(shapeFirst: Int, vararg shapeRest: Int): ShapeND = ShapeND(intArrayOf(shapeFirst, *shapeRest))
public interface WithShape {
public val shape: ShapeND
public val indices: ShapeIndexer get() = ColumnStrides(shape)
}
internal fun requireIndexInShape(index: IntArray, shape: ShapeND) {
if (index.size != shape.size) throw IndexOutOfShapeException(shape, index)
shape.forEachIndexed { axis, axisShape ->
if (index[axis] !in 0 until axisShape) throw IndexOutOfShapeException(shape, index)
}
}

View File

@ -18,7 +18,7 @@ public sealed class ShortRingOpsND : BufferedRingOpsND<Short, ShortRing>(ShortRi
@OptIn(UnstableKMathAPI::class)
public class ShortRingND(
override val shape: Shape
override val shape: ShapeND
) : ShortRingOpsND(), RingND<Short, ShortRing>, NumbersAddOps<StructureND<Short>> {
override fun number(value: Number): BufferND<Short> {
@ -30,5 +30,5 @@ public class ShortRingND(
public inline fun <R> ShortRing.withNdAlgebra(vararg shape: Int, action: ShortRingND.() -> R): R {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
return ShortRingND(Shape(shape)).run(action)
return ShortRingND(ShapeND(shape)).run(action)
}

View File

@ -46,7 +46,7 @@ public interface MutableStructure1D<T> : Structure1D<T>, MutableStructureND<T>,
*/
@JvmInline
private value class Structure1DWrapper<out T>(val structure: StructureND<T>) : Structure1D<T> {
override val shape: Shape get() = structure.shape
override val shape: ShapeND get() = structure.shape
override val size: Int get() = structure.shape[0]
@PerformancePitfall
@ -60,7 +60,7 @@ private value class Structure1DWrapper<out T>(val structure: StructureND<T>) : S
* A 1D wrapper for a mutable nd-structure
*/
private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure1D<T> {
override val shape: Shape get() = structure.shape
override val shape: ShapeND get() = structure.shape
override val size: Int get() = structure.shape[0]
@PerformancePitfall
@ -90,7 +90,7 @@ private class MutableStructure1DWrapper<T>(val structure: MutableStructureND<T>)
*/
@JvmInline
private value class Buffer1DWrapper<out T>(val buffer: Buffer<T>) : Structure1D<T> {
override val shape: Shape get() = Shape(buffer.size)
override val shape: ShapeND get() = ShapeND(buffer.size)
override val size: Int get() = buffer.size
@PerformancePitfall
@ -102,7 +102,7 @@ private value class Buffer1DWrapper<out T>(val buffer: Buffer<T>) : Structure1D<
}
internal class MutableBuffer1DWrapper<T>(val buffer: MutableBuffer<T>) : MutableStructure1D<T> {
override val shape: Shape get() = Shape(buffer.size)
override val shape: ShapeND get() = ShapeND(buffer.size)
override val size: Int get() = buffer.size
@PerformancePitfall

View File

@ -29,7 +29,7 @@ public interface Structure2D<out T> : StructureND<T> {
*/
public val colNum: Int
override val shape: Shape get() = Shape(rowNum, colNum)
override val shape: ShapeND get() = ShapeND(rowNum, colNum)
/**
* The buffer of rows of this structure. It gets elements from the structure dynamically.
@ -102,7 +102,7 @@ public interface MutableStructure2D<T> : Structure2D<T>, MutableStructureND<T> {
*/
@JvmInline
private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : Structure2D<T> {
override val shape: Shape get() = structure.shape
override val shape: ShapeND get() = structure.shape
override val rowNum: Int get() = shape[0]
override val colNum: Int get() = shape[1]
@ -120,7 +120,7 @@ private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : S
* A 2D wrapper for a mutable nd-structure
*/
private class MutableStructure2DWrapper<T>(val structure: MutableStructureND<T>) : MutableStructure2D<T> {
override val shape: Shape get() = structure.shape
override val shape: ShapeND get() = structure.shape
override val rowNum: Int get() = shape[0]
override val colNum: Int get() = shape[1]

View File

@ -33,7 +33,7 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
* The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of
* this structure.
*/
override val shape: Shape
override val shape: ShapeND
/**
* The count of dimensions in this structure. It should be equal to size of [shape].
@ -147,13 +147,13 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
): BufferND<T> = BufferND(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) })
public fun <T> buffered(
shape: Shape,
shape: ShapeND,
bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
initializer: (IntArray) -> T,
): BufferND<T> = buffered(ColumnStrides(shape), bufferFactory, initializer)
public inline fun <reified T : Any> auto(
shape: Shape,
shape: ShapeND,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = auto(ColumnStrides(shape), initializer)
@ -162,13 +162,13 @@ public interface StructureND<out T> : Featured<StructureFeature>, WithShape {
vararg shape: Int,
crossinline initializer: (IntArray) -> T,
): BufferND<T> =
auto(ColumnStrides(Shape(shape)), initializer)
auto(ColumnStrides(ShapeND(shape)), initializer)
public inline fun <T : Any> auto(
type: KClass<T>,
vararg shape: Int,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = auto(type, ColumnStrides(Shape(shape)), initializer)
): BufferND<T> = auto(type, ColumnStrides(ShapeND(shape)), initializer)
}
}

View File

@ -9,7 +9,7 @@ import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.misc.UnstableKMathAPI
public open class VirtualStructureND<T>(
override val shape: Shape,
override val shape: ShapeND,
public val producer: (IntArray) -> T,
) : StructureND<T> {
@ -22,12 +22,12 @@ public open class VirtualStructureND<T>(
@UnstableKMathAPI
public class VirtualDoubleStructureND(
shape: Shape,
shape: ShapeND,
producer: (IntArray) -> Double,
) : VirtualStructureND<Double>(shape, producer)
@UnstableKMathAPI
public class VirtualIntStructureND(
shape: Shape,
shape: ShapeND,
producer: (IntArray) -> Int,
) : VirtualStructureND<Int>(shape, producer)

View File

@ -15,9 +15,9 @@ public fun <T, A : Algebra<T>> AlgebraND<T, A>.structureND(
shapeFirst: Int,
vararg shapeRest: Int,
initializer: A.(IntArray) -> T
): StructureND<T> = structureND(Shape(shapeFirst, *shapeRest), initializer)
): StructureND<T> = structureND(ShapeND(shapeFirst, *shapeRest), initializer)
public fun <T, A : Group<T>> AlgebraND<T, A>.zero(shape: Shape): StructureND<T> = structureND(shape) { zero }
public fun <T, A : Group<T>> AlgebraND<T, A>.zero(shape: ShapeND): StructureND<T> = structureND(shape) { zero }
@JvmName("zeroVarArg")
public fun <T, A : Group<T>> AlgebraND<T, A>.zero(
@ -25,7 +25,7 @@ public fun <T, A : Group<T>> AlgebraND<T, A>.zero(
vararg shapeRest: Int,
): StructureND<T> = structureND(shapeFirst, *shapeRest) { zero }
public fun <T, A : Ring<T>> AlgebraND<T, A>.one(shape: Shape): StructureND<T> = structureND(shape) { one }
public fun <T, A : Ring<T>> AlgebraND<T, A>.one(shape: ShapeND): StructureND<T> = structureND(shape) { one }
@JvmName("oneVarArg")
public fun <T, A : Ring<T>> AlgebraND<T, A>.one(

View File

@ -28,7 +28,7 @@ internal class BufferAccessor2D<T>(
//TODO optimize wrapper
fun MutableBuffer<T>.collect(): Structure2D<T> = StructureND.buffered(
ColumnStrides(Shape(rowNum, colNum)),
ColumnStrides(ShapeND(rowNum, colNum)),
factory
) { (i, j) ->
get(i, j)

View File

@ -10,7 +10,7 @@ import kotlin.test.Test
class StridesTest {
@Test
fun checkRowBasedStrides() {
val strides = RowStrides(Shape(3, 3))
val strides = RowStrides(ShapeND(3, 3))
var counter = 0
for(i in 0..2){
for(j in 0..2){
@ -24,7 +24,7 @@ class StridesTest {
@Test
fun checkColumnBasedStrides() {
val strides = ColumnStrides(Shape(3, 3))
val strides = ColumnStrides(ShapeND(3, 3))
var counter = 0
for(i in 0..2){
for(j in 0..2){

View File

@ -9,12 +9,12 @@ import kotlinx.coroutines.*
import space.kscience.kmath.coroutines.Math
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
public class LazyStructureND<out T>(
public val scope: CoroutineScope,
override val shape: Shape,
override val shape: ShapeND,
public val function: suspend (IntArray) -> T,
) : StructureND<T> {
private val cache: MutableMap<IntArray, Deferred<T>> = HashMap()
@ -35,20 +35,24 @@ public class LazyStructureND<out T>(
}
}
@OptIn(PerformancePitfall::class)
public fun <T> StructureND<T>.async(index: IntArray): Deferred<T> =
if (this is LazyStructureND<T>) this@async.async(index) else CompletableDeferred(get(index))
@OptIn(PerformancePitfall::class)
public suspend fun <T> StructureND<T>.await(index: IntArray): T =
if (this is LazyStructureND<T>) await(index) else get(index)
/**
* PENDING would benefit from KEEP-176
*/
@OptIn(PerformancePitfall::class)
public inline fun <T, R> StructureND<T>.mapAsyncIndexed(
scope: CoroutineScope,
crossinline function: suspend (T, index: IntArray) -> R,
): LazyStructureND<R> = LazyStructureND(scope, shape) { index -> function(get(index), index) }
@OptIn(PerformancePitfall::class)
public inline fun <T, R> StructureND<T>.mapAsync(
scope: CoroutineScope,
crossinline function: suspend (T) -> R,

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.dimensions
import space.kscience.kmath.linear.*
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.Ring
@ -48,7 +48,7 @@ public interface DMatrix<out T, R : Dimension, C : Dimension> : Structure2D<T> {
public value class DMatrixWrapper<out T, R : Dimension, C : Dimension>(
private val structure: Structure2D<T>,
) : DMatrix<T, R, C> {
override val shape: Shape get() = structure.shape
override val shape: ShapeND get() = structure.shape
override val rowNum: Int get() = shape[0]
override val colNum: Int get() = shape[1]
override operator fun get(i: Int, j: Int): T = structure[i, j]

View File

@ -10,7 +10,7 @@ import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.FieldOpsND
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.Group
import space.kscience.kmath.operations.ScaleOperations
@ -45,7 +45,7 @@ public class HistogramND<T : Comparable<T>, D : Domain<T>, V : Any>(
*/
public interface HistogramGroupND<T : Comparable<T>, D : Domain<T>, V : Any> :
Group<HistogramND<T, D, V>>, ScaleOperations<HistogramND<T, D, V>> {
public val shape: Shape
public val shape: ShapeND
public val valueAlgebraND: FieldOpsND<V, *> //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape),
/**

View File

@ -39,7 +39,7 @@ public class UniformHistogramGroupND<V : Any, A : Field<V>>(
public val dimension: Int get() = lower.size
override val shape: Shape = Shape(IntArray(binNums.size) { binNums[it] + 2 })
override val shape: ShapeND = ShapeND(IntArray(binNums.size) { binNums[it] + 2 })
private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] }

View File

@ -7,13 +7,13 @@ package space.kscience.kmath.multik
import org.jetbrains.kotlinx.multik.ndarray.data.*
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.tensors.api.Tensor
import kotlin.jvm.JvmInline
@JvmInline
public value class MultikTensor<T>(public val array: MutableMultiArray<T, DN>) : Tensor<T> {
override val shape: Shape get() = Shape(array.shape)
override val shape: ShapeND get() = ShapeND(array.shape)
@PerformancePitfall
override fun get(index: IntArray): T = array[index]

View File

@ -32,7 +32,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
protected val multikStat: Statistics = multikEngine.getStatistics()
@OptIn(UnsafeKMathAPI::class)
override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor<T> {
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): MultikTensor<T> {
val strides = ColumnStrides(shape)
val memoryView = initMemoryView<T>(strides.linearSize, type)
strides.asSequence().forEachIndexed { linearIndex, tensorIndex ->
@ -123,7 +123,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
public fun MutableMultiArray<T, *>.wrap(): MultikTensor<T> = MultikTensor(this.asDNArray())
@OptIn(PerformancePitfall::class)
override fun StructureND<T>.valueOrNull(): T? = if (shape contentEquals Shape(1)) {
override fun StructureND<T>.valueOrNull(): T? = if (shape contentEquals ShapeND(1)) {
get(intArrayOf(0))
} else null
@ -211,7 +211,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
override fun StructureND<T>.transposed(i: Int, j: Int): MultikTensor<T> = asMultik().array.transpose(i, j).wrap()
override fun Tensor<T>.view(shape: Shape): MultikTensor<T> {
override fun Tensor<T>.view(shape: ShapeND): MultikTensor<T> {
require(shape.asList().all { it > 0 })
require(shape.linearSize == this.shape.size) {
"Cannot reshape array of size ${this.shape.size} into a new shape ${
@ -223,7 +223,7 @@ public abstract class MultikTensorAlgebra<T, A : Ring<T>>(
}
val mt = asMultik().array
return if (Shape(mt.shape).contentEquals(shape)) {
return if (ShapeND(mt.shape).contentEquals(shape)) {
mt
} else {
@OptIn(UnsafeKMathAPI::class)

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.multik
import org.jetbrains.kotlinx.multik.default.DefaultEngine
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.one
import space.kscience.kmath.operations.DoubleField
@ -29,8 +29,8 @@ internal class MultikNDTest {
fun dotResult() {
val dim = 100
val tensor1 = DoubleTensorAlgebra.randomNormal(shape = Shape(dim, dim), 12224)
val tensor2 = DoubleTensorAlgebra.randomNormal(shape = Shape(dim, dim), 12225)
val tensor1 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12224)
val tensor2 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12225)
val multikResult = with(multikAlgebra) {
tensor1 dot tensor2

View File

@ -33,7 +33,8 @@ public sealed interface Nd4jArrayAlgebra<T, out C : Algebra<T>> : AlgebraND<T, C
*/
public val StructureND<T>.ndArray: INDArray
override fun structureND(shape: Shape, initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> {
@OptIn(PerformancePitfall::class)
override fun structureND(shape: ShapeND, initializer: C.(IntArray) -> T): Nd4jArrayStructure<T> {
@OptIn(UnsafeKMathAPI::class)
val struct: Nd4jArrayStructure<T> = Nd4j.create(*shape.asArray())!!.wrap()
struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) }
@ -224,10 +225,10 @@ public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Double, Do
public val DoubleField.nd4j: DoubleNd4jArrayFieldOps get() = DoubleNd4jArrayFieldOps
public class DoubleNd4jArrayField(override val shape: Shape) : DoubleNd4jArrayFieldOps(), FieldND<Double, DoubleField>
public class DoubleNd4jArrayField(override val shape: ShapeND) : DoubleNd4jArrayFieldOps(), FieldND<Double, DoubleField>
public fun DoubleField.nd4j(shapeFirst: Int, vararg shapeRest: Int): DoubleNd4jArrayField =
DoubleNd4jArrayField(Shape(shapeFirst, * shapeRest))
DoubleNd4jArrayField(ShapeND(shapeFirst, * shapeRest))
/**
@ -271,12 +272,12 @@ public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps<Float, Floa
public companion object : FloatNd4jArrayFieldOps()
}
public class FloatNd4jArrayField(override val shape: Shape) : FloatNd4jArrayFieldOps(), RingND<Float, FloatField>
public class FloatNd4jArrayField(override val shape: ShapeND) : FloatNd4jArrayFieldOps(), RingND<Float, FloatField>
public val FloatField.nd4j: FloatNd4jArrayFieldOps get() = FloatNd4jArrayFieldOps
public fun FloatField.nd4j(shapeFirst: Int, vararg shapeRest: Int): FloatNd4jArrayField =
FloatNd4jArrayField(Shape(shapeFirst, * shapeRest))
FloatNd4jArrayField(ShapeND(shapeFirst, * shapeRest))
/**
* Represents [RingND] over [Nd4jArrayIntStructure].
@ -312,7 +313,7 @@ public open class IntNd4jArrayRingOps : Nd4jArrayRingOps<Int, IntRing> {
public val IntRing.nd4j: IntNd4jArrayRingOps get() = IntNd4jArrayRingOps
public class IntNd4jArrayRing(override val shape: Shape) : IntNd4jArrayRingOps(), RingND<Int, IntRing>
public class IntNd4jArrayRing(override val shape: ShapeND) : IntNd4jArrayRingOps(), RingND<Int, IntRing>
public fun IntRing.nd4j(shapeFirst: Int, vararg shapeRest: Int): IntNd4jArrayRing =
IntNd4jArrayRing(Shape(shapeFirst, * shapeRest))
IntNd4jArrayRing(ShapeND(shapeFirst, * shapeRest))

View File

@ -21,7 +21,7 @@ public sealed class Nd4jArrayStructure<T> : MutableStructureND<T> {
*/
public abstract val ndArray: INDArray
override val shape: Shape get() = Shape(ndArray.shape().toIntArray())
override val shape: ShapeND get() = ShapeND(ndArray.shape().toIntArray())
internal abstract fun elementsIterator(): Iterator<Pair<IntArray, T>>
internal fun indicesIterator(): Iterator<IntArray> = ndArray.indicesIterator()

View File

@ -37,7 +37,7 @@ public sealed interface Nd4jTensorAlgebra<T : Number, A : Field<T>> : AnalyticTe
*/
public val StructureND<T>.ndArray: INDArray
override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): Nd4jArrayStructure<T>
override fun structureND(shape: ShapeND, initializer: A.(IntArray) -> T): Nd4jArrayStructure<T>
@OptIn(PerformancePitfall::class)
override fun StructureND<T>.map(transform: A.(T) -> T): Nd4jArrayStructure<T> =
@ -108,7 +108,7 @@ public sealed interface Nd4jTensorAlgebra<T : Number, A : Field<T>> : AnalyticTe
ndArray.max(keepDim, dim).wrap()
@OptIn(UnsafeKMathAPI::class)
override fun Tensor<T>.view(shape: Shape): Nd4jArrayStructure<T> = ndArray.reshape(shape.asArray()).wrap()
override fun Tensor<T>.view(shape: ShapeND): Nd4jArrayStructure<T> = ndArray.reshape(shape.asArray()).wrap()
override fun Tensor<T>.viewAs(other: StructureND<T>): Nd4jArrayStructure<T> = view(other.shape)
@ -178,7 +178,7 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra<Double, DoubleField> {
override fun INDArray.wrap(): Nd4jArrayStructure<Double> = asDoubleStructure()
@OptIn(UnsafeKMathAPI::class)
override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure<Double> {
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure<Double> {
val array: INDArray = Nd4j.zeros(*shape.asArray())
val indices = ColumnStrides(shape)
indices.asSequence().forEach { index ->
@ -198,7 +198,7 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra<Double, DoubleField> {
}
override fun StructureND<Double>.valueOrNull(): Double? =
if (shape contentEquals Shape(1)) ndArray.getDouble(0) else null
if (shape contentEquals ShapeND(1)) ndArray.getDouble(0) else null
// TODO rewrite
override fun diagonalEmbedding(

View File

@ -14,7 +14,7 @@ import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.PowerOperations
@ -28,7 +28,7 @@ public class DoubleTensorFlowOutput(
}
internal fun Shape.toLongArray(): LongArray = LongArray(size) { get(it).toLong() }
internal fun ShapeND.toLongArray(): LongArray = LongArray(size) { get(it).toLong() }
public class DoubleTensorFlowAlgebra internal constructor(
graph: Graph,
@ -37,7 +37,7 @@ public class DoubleTensorFlowAlgebra internal constructor(
override val elementAlgebra: DoubleField get() = DoubleField
override fun structureND(
shape: Shape,
shape: ShapeND,
initializer: DoubleField.(IntArray) -> Double,
): StructureND<Double> {
val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array ->

View File

@ -20,7 +20,7 @@ import org.tensorflow.types.family.TType
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.misc.UnsafeKMathAPI
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.asArray
import space.kscience.kmath.nd.contentEquals
@ -41,12 +41,14 @@ public sealed interface TensorFlowTensor<T> : Tensor<T>
*/
@JvmInline
public value class TensorFlowArray<T>(public val tensor: NdArray<T>) : Tensor<T> {
override val shape: Shape get() = Shape(tensor.shape().asArray().toIntArray())
override val shape: ShapeND get() = ShapeND(tensor.shape().asArray().toIntArray())
@PerformancePitfall
override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray())
//TODO implement native element sequence
@PerformancePitfall
override fun set(index: IntArray, value: T) {
tensor.setObject(value, *index.toLongArray())
}
@ -65,7 +67,7 @@ public abstract class TensorFlowOutput<T, TT : TType>(
public var output: Output<TT> = output
internal set
override val shape: Shape get() = Shape(output.shape().asArray().toIntArray())
override val shape: ShapeND get() = ShapeND(output.shape().asArray().toIntArray())
protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray<T>
@ -99,7 +101,7 @@ public abstract class TensorFlowAlgebra<T, TT : TNumber, A : Ring<T>> internal c
protected abstract fun const(value: T): Constant<TT>
override fun StructureND<T>.valueOrNull(): T? = if (shape contentEquals Shape(1))
override fun StructureND<T>.valueOrNull(): T? = if (shape contentEquals ShapeND(1))
get(intArrayOf(0)) else null
/**
@ -195,7 +197,7 @@ public abstract class TensorFlowAlgebra<T, TT : TNumber, A : Ring<T>> internal c
ops.linalg.transpose(it, ops.constant(intArrayOf(i, j)))
}
override fun Tensor<T>.view(shape: Shape): Tensor<T> = operate {
override fun Tensor<T>.view(shape: ShapeND): Tensor<T> = operate {
@OptIn(UnsafeKMathAPI::class)
ops.reshape(it, ops.constant(shape.asArray()))
}

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.tensorflow
import org.junit.jupiter.api.Test
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.get
import space.kscience.kmath.nd.structureND
import space.kscience.kmath.operations.DoubleField
@ -32,8 +32,8 @@ class DoubleTensorFlowOps {
fun dot(){
val dim = 1000
val tensor1 = DoubleTensorAlgebra.randomNormal(shape = Shape(dim, dim), 12224)
val tensor2 = DoubleTensorAlgebra.randomNormal(shape = Shape(dim, dim), 12225)
val tensor1 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12224)
val tensor2 = DoubleTensorAlgebra.randomNormal(shape = ShapeND(dim, dim), 12225)
DoubleField.produceWithTF {
tensor1 dot tensor2

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.tensors.api
import space.kscience.kmath.nd.RingOpsND
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.operations.Ring
@ -193,7 +193,7 @@ public interface TensorAlgebra<T, A : Ring<T>> : RingOpsND<T, A> {
* @param shape the desired size
* @return tensor with new shape
*/
public fun Tensor<T>.view(shape: Shape): Tensor<T>
public fun Tensor<T>.view(shape: ShapeND): Tensor<T>
/**
* View this tensor as the same size as [other].

View File

@ -7,7 +7,7 @@ package space.kscience.kmath.tensors.core
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.RowStrides
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.Strides
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.tensors.api.Tensor
@ -16,7 +16,7 @@ import space.kscience.kmath.tensors.api.Tensor
* Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor]
*/
public abstract class BufferedTensor<T>(
override val shape: Shape,
override val shape: ShapeND,
) : Tensor<T> {
public abstract val source: MutableBuffer<T>

View File

@ -84,7 +84,7 @@ public inline fun OffsetDoubleBuffer.mapInPlace(operation: (Double) -> Double) {
* [DoubleTensor] always uses row-based strides
*/
public class DoubleTensor(
shape: Shape,
shape: ShapeND,
override val source: OffsetDoubleBuffer,
) : BufferedTensor<Double>(shape), MutableStructureNDOfDouble {
@ -92,7 +92,7 @@ public class DoubleTensor(
require(linearSize == source.size) { "Source buffer size must be equal tensor size" }
}
public constructor(shape: Shape, buffer: DoubleBuffer) : this(shape, OffsetDoubleBuffer(buffer, 0, buffer.size))
public constructor(shape: ShapeND, buffer: DoubleBuffer) : this(shape, OffsetDoubleBuffer(buffer, 0, buffer.size))
@OptIn(PerformancePitfall::class)
@ -147,7 +147,7 @@ public value class DoubleTensor2D(public val tensor: DoubleTensor) : MutableStru
override fun elements(): Sequence<Pair<IntArray, Double>> = tensor.elements()
@OptIn(PerformancePitfall::class)
override fun get(index: IntArray): Double = tensor[index]
override val shape: Shape get() = tensor.shape
override val shape: ShapeND get() = tensor.shape
}
public fun DoubleTensor.asDoubleTensor2D(): DoubleTensor2D = DoubleTensor2D(this)
@ -162,7 +162,7 @@ public inline fun DoubleTensor.forEachMatrix(block: (index: IntArray, matrix: Do
val n = shape.size
check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" }
val matrixOffset = shape[n - 1] * shape[n - 2]
val matrixShape = Shape(shape[n - 2], shape[n - 1])
val matrixShape = ShapeND(shape[n - 2], shape[n - 1])
val size = matrixShape.linearSize
for (i in 0 until linearSize / matrixOffset) {

View File

@ -92,7 +92,7 @@ public open class DoubleTensorAlgebra :
override fun StructureND<Double>.valueOrNull(): Double? {
val dt = asDoubleTensor()
return if (dt.shape contentEquals Shape(1)) dt.source[0] else null
return if (dt.shape contentEquals ShapeND(1)) dt.source[0] else null
}
override fun StructureND<Double>.value(): Double = valueOrNull()
@ -105,7 +105,7 @@ public open class DoubleTensorAlgebra :
* @param array one-dimensional data array.
* @return tensor with the [shape] shape and [array] data.
*/
public fun fromArray(shape: Shape, array: DoubleArray): DoubleTensor {
public fun fromArray(shape: ShapeND, array: DoubleArray): DoubleTensor {
checkNotEmptyShape(shape)
checkEmptyDoubleBuffer(array)
checkBufferShapeConsistency(shape, array)
@ -119,7 +119,7 @@ public open class DoubleTensorAlgebra :
* @param initializer mapping tensor indices to values.
* @return tensor with the [shape] shape and data generated by the [initializer].
*/
override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray(
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray(
shape,
RowStrides(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray()
)
@ -127,7 +127,7 @@ public open class DoubleTensorAlgebra :
override fun Tensor<Double>.getTensor(i: Int): DoubleTensor {
val dt = asDoubleTensor()
val lastShape = shape.last(shape.size - 1)
val newShape: Shape = if (lastShape.isNotEmpty()) lastShape else Shape(1)
val newShape: ShapeND = if (lastShape.isNotEmpty()) lastShape else ShapeND(1)
return DoubleTensor(
newShape,
dt.source.view(newShape.linearSize * i, newShape.linearSize)
@ -141,7 +141,7 @@ public open class DoubleTensorAlgebra :
* @param shape array of integers defining the shape of the output tensor.
* @return tensor with the [shape] shape and filled with [value].
*/
public fun full(value: Double, shape: Shape): DoubleTensor {
public fun full(value: Double, shape: ShapeND): DoubleTensor {
checkNotEmptyShape(shape)
val buffer = DoubleBuffer(shape.linearSize) { value }
return DoubleTensor(shape, buffer)
@ -165,7 +165,7 @@ public open class DoubleTensorAlgebra :
* @param shape array of integers defining the shape of the output tensor.
* @return tensor filled with the scalar value `0.0`, with the [shape] shape.
*/
public fun zeros(shape: Shape): DoubleTensor = full(0.0, shape)
public fun zeros(shape: ShapeND): DoubleTensor = full(0.0, shape)
/**
* Returns a tensor filled with the scalar value `0.0`, with the same shape as a given array.
@ -180,7 +180,7 @@ public open class DoubleTensorAlgebra :
* @param shape array of integers defining the shape of the output tensor.
* @return tensor filled with the scalar value `1.0`, with the [shape] shape.
*/
public fun ones(shape: Shape): DoubleTensor = full(1.0, shape)
public fun ones(shape: ShapeND): DoubleTensor = full(1.0, shape)
/**
* Returns a tensor filled with the scalar value `1.0`, with the same shape as a given array.
@ -196,7 +196,7 @@ public open class DoubleTensorAlgebra :
* @return a 2-D tensor with ones on the diagonal and zeros elsewhere.
*/
public fun eye(n: Int): DoubleTensor {
val shape = Shape(n, n)
val shape = ShapeND(n, n)
val buffer = DoubleBuffer(n * n) { 0.0 }
val res = DoubleTensor(shape, buffer)
for (i in 0 until n) {
@ -306,7 +306,7 @@ public open class DoubleTensorAlgebra :
// return resTensor
}
override fun Tensor<Double>.view(shape: Shape): DoubleTensor {
override fun Tensor<Double>.view(shape: ShapeND): DoubleTensor {
checkView(asDoubleTensor(), shape)
return DoubleTensor(shape, asDoubleTensor().source)
}
@ -346,7 +346,7 @@ public open class DoubleTensorAlgebra :
@UnstableKMathAPI
public infix fun StructureND<Double>.matmul(other: StructureND<Double>): DoubleTensor {
if (shape.size == 1 && other.shape.size == 1) {
return DoubleTensor(Shape(1), DoubleBuffer(times(other).sum()))
return DoubleTensor(ShapeND(1), DoubleBuffer(times(other).sum()))
}
var penultimateDim = false
@ -358,7 +358,7 @@ public open class DoubleTensorAlgebra :
if (shape.size == 1) {
penultimateDim = true
newThis = newThis.view(Shape(1) + shape)
newThis = newThis.view(ShapeND(1) + shape)
}
if (other.shape.size == 1) {
@ -396,7 +396,7 @@ public open class DoubleTensorAlgebra :
// }
return if (penultimateDim) {
resTensor.view(resTensor.shape.first(resTensor.shape.size - 2) + Shape(resTensor.shape.last()))
resTensor.view(resTensor.shape.first(resTensor.shape.size - 2) + ShapeND(resTensor.shape.last()))
} else if (lastDim) {
resTensor.view(resTensor.shape.first(resTensor.shape.size - 1))
} else {
@ -506,7 +506,7 @@ public open class DoubleTensorAlgebra :
* @return tensor of a given shape filled with numbers from the normal distribution
* with `0.0` mean and `1.0` standard deviation.
*/
public fun randomNormal(shape: Shape, seed: Long = 0): DoubleTensor =
public fun randomNormal(shape: ShapeND, seed: Long = 0): DoubleTensor =
DoubleTensor(shape, DoubleBuffer.randomNormals(shape.linearSize, seed))
/**
@ -531,7 +531,7 @@ public open class DoubleTensorAlgebra :
check(tensors.isNotEmpty()) { "List must have at least 1 element" }
val shape = tensors[0].shape
check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" }
val resShape = Shape(tensors.size) + shape
val resShape = ShapeND(tensors.size) + shape
// val resBuffer: List<Double> = tensors.flatMap {
// it.asDoubleTensor().source.array.drop(it.asDoubleTensor().bufferStart)
// .take(it.asDoubleTensor().linearSize)
@ -685,9 +685,9 @@ public open class DoubleTensorAlgebra :
check(tensors.isNotEmpty()) { "List must have at least 1 element" }
val n = tensors.size
val m = tensors[0].shape[0]
check(tensors.all { it.shape contentEquals Shape(m) }) { "Tensors must have same shapes" }
check(tensors.all { it.shape contentEquals ShapeND(m) }) { "Tensors must have same shapes" }
val resTensor = DoubleTensor(
Shape(n, n),
ShapeND(n, n),
DoubleBuffer(n * n) { 0.0 }
)
for (i in 0 until n) {
@ -875,9 +875,9 @@ public open class DoubleTensorAlgebra :
val size = dimension
val commonShape = shape.slice(0 until size - 2)
val (n, m) = shape.slice(size - 2 until size)
val uTensor = zeros(commonShape + Shape(min(n, m), n))
val sTensor = zeros(commonShape + Shape(min(n, m)))
val vTensor = zeros(commonShape + Shape(min(n, m), m))
val uTensor = zeros(commonShape + ShapeND(min(n, m), n))
val sTensor = zeros(commonShape + ShapeND(min(n, m)))
val vTensor = zeros(commonShape + ShapeND(min(n, m), m))
val matrices = asDoubleTensor().matrices
val uTensors = uTensor.matrices
@ -988,7 +988,7 @@ public open class DoubleTensorAlgebra :
val n = shape.size
val detTensorShape = Shape(IntArray(n - 1) { i -> shape[i] }.apply {
val detTensorShape = ShapeND(IntArray(n - 1) { i -> shape[i] }.apply {
set(n - 2, 1)
})

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.tensors.core
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.structures.*
/**
@ -75,7 +75,7 @@ public inline fun OffsetIntBuffer.mapInPlace(operation: (Int) -> Int) {
* Default [BufferedTensor] implementation for [Int] values
*/
public class IntTensor(
shape: Shape,
shape: ShapeND,
override val source: OffsetIntBuffer,
) : BufferedTensor<Int>(shape) {
@ -83,7 +83,7 @@ public class IntTensor(
require(linearSize == source.size) { "Source buffer size must be equal tensor size" }
}
public constructor(shape: Shape, buffer: IntBuffer) : this(shape, OffsetIntBuffer(buffer, 0, buffer.size))
public constructor(shape: ShapeND, buffer: IntBuffer) : this(shape, OffsetIntBuffer(buffer, 0, buffer.size))
@OptIn(PerformancePitfall::class)
override fun get(index: IntArray): Int = this.source[indices.offset(index)]

View File

@ -89,7 +89,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
override fun StructureND<Int>.valueOrNull(): Int? {
val dt = asIntTensor()
return if (dt.shape contentEquals Shape(1)) dt.source[0] else null
return if (dt.shape contentEquals ShapeND(1)) dt.source[0] else null
}
override fun StructureND<Int>.value(): Int = valueOrNull()
@ -102,7 +102,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @param array one-dimensional data array.
* @return tensor with the [shape] shape and [array] data.
*/
public fun fromArray(shape: Shape, array: IntArray): IntTensor {
public fun fromArray(shape: ShapeND, array: IntArray): IntTensor {
checkNotEmptyShape(shape)
check(array.isNotEmpty()) { "Illegal empty buffer provided" }
check(array.size == shape.linearSize) {
@ -118,7 +118,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @param initializer mapping tensor indices to values.
* @return tensor with the [shape] shape and data generated by the [initializer].
*/
override fun structureND(shape: Shape, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray(
override fun structureND(shape: ShapeND, initializer: IntRing.(IntArray) -> Int): IntTensor = fromArray(
shape,
RowStrides(shape).asSequence().map { IntRing.initializer(it) }.toMutableList().toIntArray()
)
@ -126,7 +126,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
override fun Tensor<Int>.getTensor(i: Int): IntTensor {
val dt = asIntTensor()
val lastShape = shape.last(shape.size - 1)
val newShape = if (lastShape.isNotEmpty()) lastShape else Shape(1)
val newShape = if (lastShape.isNotEmpty()) lastShape else ShapeND(1)
return IntTensor(newShape, dt.source.view(newShape.linearSize * i))
}
@ -137,7 +137,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @param shape array of integers defining the shape of the output tensor.
* @return tensor with the [shape] shape and filled with [value].
*/
public fun full(value: Int, shape: Shape): IntTensor {
public fun full(value: Int, shape: ShapeND): IntTensor {
checkNotEmptyShape(shape)
val buffer = IntBuffer(shape.linearSize) { value }
return IntTensor(shape, buffer)
@ -161,7 +161,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @param shape array of integers defining the shape of the output tensor.
* @return tensor filled with the scalar value `0`, with the [shape] shape.
*/
public fun zeros(shape: Shape): IntTensor = full(0, shape)
public fun zeros(shape: ShapeND): IntTensor = full(0, shape)
/**
* Returns a tensor filled with the scalar value `0`, with the same shape as a given array.
@ -176,7 +176,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @param shape array of integers defining the shape of the output tensor.
* @return tensor filled with the scalar value `1`, with the [shape] shape.
*/
public fun ones(shape: Shape): IntTensor = full(1, shape)
public fun ones(shape: ShapeND): IntTensor = full(1, shape)
/**
* Returns a tensor filled with the scalar value `1`, with the same shape as a given array.
@ -192,7 +192,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
* @return a 2-D tensor with ones on the diagonal and zeros elsewhere.
*/
public fun eye(n: Int): IntTensor {
val shape = Shape(n, n)
val shape = ShapeND(n, n)
val buffer = IntBuffer(n * n) { 0 }
val res = IntTensor(shape, buffer)
for (i in 0 until n) {
@ -287,7 +287,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
// return resTensor
}
override fun Tensor<Int>.view(shape: Shape): IntTensor {
override fun Tensor<Int>.view(shape: ShapeND): IntTensor {
checkView(asIntTensor(), shape)
return IntTensor(shape, asIntTensor().source)
}
@ -388,7 +388,7 @@ public open class IntTensorAlgebra : TensorAlgebra<Int, IntRing> {
check(tensors.isNotEmpty()) { "List must have at least 1 element" }
val shape = tensors[0].shape
check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" }
val resShape = Shape(tensors.size) + shape
val resShape = ShapeND(tensors.size) + shape
// val resBuffer: List<Int> = tensors.flatMap {
// it.asIntTensor().source.array.drop(it.asIntTensor().bufferStart)
// .take(it.asIntTensor().linearSize)

View File

@ -32,7 +32,7 @@ internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTenso
}
}
internal fun broadcastShapes(shapes: List<Shape>): Shape {
internal fun broadcastShapes(shapes: List<ShapeND>): ShapeND {
var totalDim = 0
for (shape in shapes) {
totalDim = max(totalDim, shape.size)
@ -57,10 +57,10 @@ internal fun broadcastShapes(shapes: List<Shape>): Shape {
}
}
return Shape(totalShape)
return ShapeND(totalShape)
}
internal fun broadcastTo(tensor: DoubleTensor, newShape: Shape): DoubleTensor {
internal fun broadcastTo(tensor: DoubleTensor, newShape: ShapeND): DoubleTensor {
require(tensor.shape.size <= newShape.size) {
"Tensor is not compatible with the new shape"
}
@ -120,7 +120,7 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List<DoubleTen
var curMultiIndex = tensor.shape.slice(0..tensor.shape.size - 3).asArray()
curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex
val newTensor = DoubleTensor(Shape(curMultiIndex) + matrixShape, tensor.source)
val newTensor = DoubleTensor(ShapeND(curMultiIndex) + matrixShape, tensor.source)
for (i in curMultiIndex.indices) {
if (curMultiIndex[i] != 1) {

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors.core.internal
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.contentEquals
import space.kscience.kmath.nd.linearSize
@ -15,7 +15,7 @@ import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.asDoubleTensor
internal fun checkNotEmptyShape(shape: Shape) =
internal fun checkNotEmptyShape(shape: ShapeND) =
check(shape.size > 0) {
"Illegal empty shape provided"
}
@ -24,7 +24,7 @@ internal fun checkEmptyDoubleBuffer(buffer: DoubleArray) = check(buffer.isNotEmp
"Illegal empty buffer provided"
}
internal fun checkBufferShapeConsistency(shape: Shape, buffer: DoubleArray) =
internal fun checkBufferShapeConsistency(shape: ShapeND, buffer: DoubleArray) =
check(buffer.size == shape.linearSize) {
"Inconsistent shape ${shape} for buffer of size ${buffer.size} provided"
}
@ -40,10 +40,10 @@ internal fun checkTranspose(dim: Int, i: Int, j: Int) =
"Cannot transpose $i to $j for a tensor of dim $dim"
}
internal fun <T> checkView(a: Tensor<T>, shape: Shape) =
internal fun <T> checkView(a: Tensor<T>, shape: ShapeND) =
check(a.shape.linearSize == shape.linearSize)
internal fun checkSquareMatrix(shape: Shape) {
internal fun checkSquareMatrix(shape: ShapeND) {
val n = shape.size
check(n >= 2) {
"Expected tensor with 2 or more dimensions, got size $n instead"

View File

@ -156,7 +156,7 @@ internal val DoubleTensor.vectors: List<DoubleTensor>
get() {
val n = shape.size
val vectorOffset = shape[n - 1]
val vectorShape = Shape(shape.last())
val vectorShape = ShapeND(shape.last())
return List(linearSize / vectorOffset) { index ->
val offset = index * vectorOffset
@ -173,7 +173,7 @@ internal val DoubleTensor.matrices: List<DoubleTensor>
val n = shape.size
check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" }
val matrixOffset = shape[n - 1] * shape[n - 2]
val matrixShape = Shape(shape[n - 2], shape[n - 1])
val matrixShape = ShapeND(shape[n - 2], shape[n - 1])
val size = matrixShape.linearSize

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors.core.internal
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.first
import space.kscience.kmath.nd.last
import space.kscience.kmath.operations.asSequence
@ -55,7 +55,7 @@ internal val IntTensor.matrices: VirtualBuffer<IntTensor>
val n = shape.size
check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" }
val matrixOffset = shape[n - 1] * shape[n - 2]
val matrixShape = Shape(shape[n - 2], shape[n - 1])
val matrixShape = ShapeND(shape[n - 2], shape[n - 1])
return VirtualBuffer(linearSize / matrixOffset) { index ->
val offset = index * matrixOffset

View File

@ -95,7 +95,7 @@ internal fun <T> StructureND<T>.setUpPivots(): IntTensor {
pivotsShape[n - 2] = m + 1
return IntTensor(
Shape(pivotsShape),
ShapeND(pivotsShape),
IntBuffer(pivotsShape.reduce(Int::times)) { 0 }
)
}
@ -240,10 +240,10 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10)
val b: DoubleTensor
if (n > m) {
b = a.transposed(0, 1).dot(a)
v = DoubleTensor(Shape(m), DoubleBuffer.randomUnitVector(m, 0))
v = DoubleTensor(ShapeND(m), DoubleBuffer.randomUnitVector(m, 0))
} else {
b = a.dot(a.transposed(0, 1))
v = DoubleTensor(Shape(n), DoubleBuffer.randomUnitVector(n, 0))
v = DoubleTensor(ShapeND(n), DoubleBuffer.randomUnitVector(n, 0))
}
var lastV: DoubleTensor
@ -275,7 +275,7 @@ internal fun DoubleTensorAlgebra.svdHelper(
outerProduct[i * v.shape[0] + j] = u.getTensor(i).value() * v.getTensor(j).value()
}
}
a = a - singularValue.times(DoubleTensor(Shape(u.shape[0], v.shape[0]), outerProduct.asBuffer()))
a = a - singularValue.times(DoubleTensor(ShapeND(u.shape[0], v.shape[0]), outerProduct.asBuffer()))
}
var v: DoubleTensor
var u: DoubleTensor

View File

@ -8,15 +8,15 @@
package space.kscience.kmath.tensors.core
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import kotlin.jvm.JvmName
@JvmName("varArgOne")
public fun DoubleTensorAlgebra.one(vararg shape: Int): DoubleTensor = ones(Shape(shape))
public fun DoubleTensorAlgebra.one(vararg shape: Int): DoubleTensor = ones(ShapeND(shape))
public fun DoubleTensorAlgebra.one(shape: Shape): DoubleTensor = ones(shape)
public fun DoubleTensorAlgebra.one(shape: ShapeND): DoubleTensor = ones(shape)
@JvmName("varArgZero")
public fun DoubleTensorAlgebra.zero(vararg shape: Int): DoubleTensor = zeros(Shape(shape))
public fun DoubleTensorAlgebra.zero(vararg shape: Int): DoubleTensor = zeros(ShapeND(shape))
public fun DoubleTensorAlgebra.zero(shape: Shape): DoubleTensor = zeros(shape)
public fun DoubleTensorAlgebra.zero(shape: ShapeND): DoubleTensor = zeros(shape)

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors.core
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.contentEquals
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.internal.broadcastOuterTensors
@ -21,38 +21,38 @@ internal class TestBroadcasting {
fun testBroadcastShapes() = DoubleTensorAlgebra {
assertTrue(
broadcastShapes(
listOf(Shape(2, 3), Shape(1, 3), Shape(1, 1, 1))
) contentEquals Shape(1, 2, 3)
listOf(ShapeND(2, 3), ShapeND(1, 3), ShapeND(1, 1, 1))
) contentEquals ShapeND(1, 2, 3)
)
assertTrue(
broadcastShapes(
listOf(Shape(6, 7), Shape(5, 6, 1), Shape(7), Shape(5, 1, 7))
) contentEquals Shape(5, 6, 7)
listOf(ShapeND(6, 7), ShapeND(5, 6, 1), ShapeND(7), ShapeND(5, 1, 7))
) contentEquals ShapeND(5, 6, 7)
)
}
@Test
fun testBroadcastTo() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(Shape(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val res = broadcastTo(tensor2, tensor1.shape)
assertTrue(res.shape contentEquals Shape(2, 3))
assertTrue(res.shape contentEquals ShapeND(2, 3))
assertTrue(res.source contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0))
}
@Test
fun testBroadcastTensors() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(Shape(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(Shape(1, 1, 1), doubleArrayOf(500.0))
val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(ShapeND(1, 1, 1), doubleArrayOf(500.0))
val res = broadcastTensors(tensor1, tensor2, tensor3)
assertTrue(res[0].shape contentEquals Shape(1, 2, 3))
assertTrue(res[1].shape contentEquals Shape(1, 2, 3))
assertTrue(res[2].shape contentEquals Shape(1, 2, 3))
assertTrue(res[0].shape contentEquals ShapeND(1, 2, 3))
assertTrue(res[1].shape contentEquals ShapeND(1, 2, 3))
assertTrue(res[2].shape contentEquals ShapeND(1, 2, 3))
assertTrue(res[0].source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res[1].source contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0))
@ -61,15 +61,15 @@ internal class TestBroadcasting {
@Test
fun testBroadcastOuterTensors() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(Shape(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(Shape(1, 1, 1), doubleArrayOf(500.0))
val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(ShapeND(1, 1, 1), doubleArrayOf(500.0))
val res = broadcastOuterTensors(tensor1, tensor2, tensor3)
assertTrue(res[0].shape contentEquals Shape(1, 2, 3))
assertTrue(res[1].shape contentEquals Shape(1, 1, 3))
assertTrue(res[2].shape contentEquals Shape(1, 1, 1))
assertTrue(res[0].shape contentEquals ShapeND(1, 2, 3))
assertTrue(res[1].shape contentEquals ShapeND(1, 1, 3))
assertTrue(res[2].shape contentEquals ShapeND(1, 1, 1))
assertTrue(res[0].source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res[1].source contentEquals doubleArrayOf(10.0, 20.0, 30.0))
@ -78,37 +78,37 @@ internal class TestBroadcasting {
@Test
fun testBroadcastOuterTensorsShapes() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) { 0.0 })
val tensor2 = fromArray(Shape(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) { 0.0 })
val tensor3 = fromArray(Shape(1, 1), doubleArrayOf(500.0))
val tensor1 = fromArray(ShapeND(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) { 0.0 })
val tensor2 = fromArray(ShapeND(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) { 0.0 })
val tensor3 = fromArray(ShapeND(1, 1), doubleArrayOf(500.0))
val res = broadcastOuterTensors(tensor1, tensor2, tensor3)
assertTrue(res[0].shape contentEquals Shape(4, 2, 5, 3, 2, 3))
assertTrue(res[1].shape contentEquals Shape(4, 2, 5, 3, 3, 3))
assertTrue(res[2].shape contentEquals Shape(4, 2, 5, 3, 1, 1))
assertTrue(res[0].shape contentEquals ShapeND(4, 2, 5, 3, 2, 3))
assertTrue(res[1].shape contentEquals ShapeND(4, 2, 5, 3, 3, 3))
assertTrue(res[2].shape contentEquals ShapeND(4, 2, 5, 3, 1, 1))
}
@Test
fun testMinusTensor() = BroadcastDoubleTensorAlgebra.invoke {
val tensor1 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(Shape(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(Shape(1, 1, 1), doubleArrayOf(500.0))
val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(ShapeND(1, 1, 1), doubleArrayOf(500.0))
val tensor21 = tensor2 - tensor1
val tensor31 = tensor3 - tensor1
val tensor32 = tensor3 - tensor2
assertTrue(tensor21.shape contentEquals Shape(2, 3))
assertTrue(tensor21.shape contentEquals ShapeND(2, 3))
assertTrue(tensor21.source contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0))
assertTrue(tensor31.shape contentEquals Shape(1, 2, 3))
assertTrue(tensor31.shape contentEquals ShapeND(1, 2, 3))
assertTrue(
tensor31.source
contentEquals doubleArrayOf(499.0, 498.0, 497.0, 496.0, 495.0, 494.0)
)
assertTrue(tensor32.shape contentEquals Shape(1, 1, 3))
assertTrue(tensor32.shape contentEquals ShapeND(1, 1, 3))
assertTrue(tensor32.source contentEquals doubleArrayOf(490.0, 480.0, 470.0))
}

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors.core
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.asBuffer
import kotlin.math.*
@ -14,7 +14,7 @@ import kotlin.test.assertTrue
internal class TestDoubleAnalyticTensorAlgebra {
val shape = Shape(2, 1, 3, 2)
val shape = ShapeND(2, 1, 3, 2)
val buffer = doubleArrayOf(
27.1, 20.0, 19.84,
23.123, 3.0, 2.0,
@ -103,7 +103,7 @@ internal class TestDoubleAnalyticTensorAlgebra {
assertTrue { tensor.floor() eq expectedTensor(::floor) }
}
val shape2 = Shape(2, 2)
val shape2 = ShapeND(2, 2)
val buffer2 = doubleArrayOf(
1.0, 2.0,
-3.0, 4.0
@ -115,13 +115,13 @@ internal class TestDoubleAnalyticTensorAlgebra {
assertTrue { tensor2.min() == -3.0 }
assertTrue {
tensor2.min(0, true) eq fromArray(
Shape(1, 2),
ShapeND(1, 2),
doubleArrayOf(-3.0, 2.0)
)
}
assertTrue {
tensor2.min(1, false) eq fromArray(
Shape(2),
ShapeND(2),
doubleArrayOf(1.0, -3.0)
)
}
@ -132,13 +132,13 @@ internal class TestDoubleAnalyticTensorAlgebra {
assertTrue { tensor2.max() == 4.0 }
assertTrue {
tensor2.max(0, true) eq fromArray(
Shape(1, 2),
ShapeND(1, 2),
doubleArrayOf(1.0, 4.0)
)
}
assertTrue {
tensor2.max(1, false) eq fromArray(
Shape(2),
ShapeND(2),
doubleArrayOf(2.0, 4.0)
)
}
@ -149,13 +149,13 @@ internal class TestDoubleAnalyticTensorAlgebra {
assertTrue { tensor2.sum() == 4.0 }
assertTrue {
tensor2.sum(0, true) eq fromArray(
Shape(1, 2),
ShapeND(1, 2),
doubleArrayOf(-2.0, 6.0)
)
}
assertTrue {
tensor2.sum(1, false) eq fromArray(
Shape(2),
ShapeND(2),
doubleArrayOf(3.0, 1.0)
)
}
@ -166,13 +166,13 @@ internal class TestDoubleAnalyticTensorAlgebra {
assertTrue { tensor2.mean() == 1.0 }
assertTrue {
tensor2.mean(0, true) eq fromArray(
Shape(1, 2),
ShapeND(1, 2),
doubleArrayOf(-1.0, 3.0)
)
}
assertTrue {
tensor2.mean(1, false) eq fromArray(
Shape(2),
ShapeND(2),
doubleArrayOf(1.5, 0.5)
)
}

View File

@ -5,7 +5,7 @@
package space.kscience.kmath.tensors.core
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.contentEquals
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.internal.svd1d
@ -19,7 +19,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testDetLU() = DoubleTensorAlgebra {
val tensor = fromArray(
Shape(2, 2, 2),
ShapeND(2, 2, 2),
doubleArrayOf(
1.0, 3.0,
1.0, 2.0,
@ -29,7 +29,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
)
val expectedTensor = fromArray(
Shape(2, 1),
ShapeND(2, 1),
doubleArrayOf(
-1.0,
-7.0
@ -45,7 +45,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
fun testDet() = DoubleTensorAlgebra {
val expectedValue = 0.019827417
val m = fromArray(
Shape(3, 3), doubleArrayOf(
ShapeND(3, 3), doubleArrayOf(
2.1843, 1.4391, -0.4845,
1.4391, 1.7772, 0.4055,
-0.4845, 0.4055, 0.7519
@ -59,7 +59,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
fun testDetSingle() = DoubleTensorAlgebra {
val expectedValue = 48.151623
val m = fromArray(
Shape(1, 1), doubleArrayOf(
ShapeND(1, 1), doubleArrayOf(
expectedValue
)
)
@ -70,7 +70,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testInvLU() = DoubleTensorAlgebra {
val tensor = fromArray(
Shape(2, 2, 2),
ShapeND(2, 2, 2),
doubleArrayOf(
1.0, 0.0,
0.0, 2.0,
@ -80,7 +80,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
)
val expectedTensor = fromArray(
Shape(2, 2, 2), doubleArrayOf(
ShapeND(2, 2, 2), doubleArrayOf(
1.0, 0.0,
0.0, 0.5,
0.0, 1.0,
@ -94,14 +94,14 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testScalarProduct() = DoubleTensorAlgebra {
val a = fromArray(Shape(3), doubleArrayOf(1.8, 2.5, 6.8))
val b = fromArray(Shape(3), doubleArrayOf(5.5, 2.6, 6.4))
val a = fromArray(ShapeND(3), doubleArrayOf(1.8, 2.5, 6.8))
val b = fromArray(ShapeND(3), doubleArrayOf(5.5, 2.6, 6.4))
assertEquals(a.dot(b).value(), 59.92)
}
@Test
fun testQR() = DoubleTensorAlgebra {
val shape = Shape(2, 2, 2)
val shape = ShapeND(2, 2, 2)
val buffer = doubleArrayOf(
1.0, 3.0,
1.0, 2.0,
@ -122,7 +122,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testLU() = DoubleTensorAlgebra {
val shape = Shape(2, 2, 2)
val shape = ShapeND(2, 2, 2)
val buffer = doubleArrayOf(
1.0, 3.0,
1.0, 2.0,
@ -142,9 +142,9 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testCholesky() = DoubleTensorAlgebra {
val tensor = randomNormal(Shape(2, 5, 5), 0)
val tensor = randomNormal(ShapeND(2, 5, 5), 0)
val sigma = (tensor matmul tensor.transposed()) + diagonalEmbedding(
fromArray(Shape(2, 5), DoubleArray(10) { 0.1 })
fromArray(ShapeND(2, 5), DoubleArray(10) { 0.1 })
)
val low = sigma.cholesky()
val sigmChol = low matmul low.transposed()
@ -153,24 +153,24 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testSVD1D() = DoubleTensorAlgebra {
val tensor2 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res = svd1d(tensor2)
assertTrue(res.shape contentEquals Shape(2))
assertTrue(res.shape contentEquals ShapeND(2))
assertTrue { abs(abs(res.source[0]) - 0.386) < 0.01 }
assertTrue { abs(abs(res.source[1]) - 0.922) < 0.01 }
}
@Test
fun testSVD() = DoubleTensorAlgebra {
testSVDFor(fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
testSVDFor(fromArray(Shape(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
testSVDFor(fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
testSVDFor(fromArray(ShapeND(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
}
@Test
fun testBatchedSVD() = DoubleTensorAlgebra {
val tensor = randomNormal(Shape(2, 5, 3), 0)
val tensor = randomNormal(ShapeND(2, 5, 3), 0)
val (tensorU, tensorS, tensorV) = tensor.svd()
val tensorSVD = tensorU matmul (diagonalEmbedding(tensorS) matmul tensorV.transposed())
assertTrue(tensor.eq(tensorSVD))
@ -178,7 +178,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
@Test
fun testBatchedSymEig() = DoubleTensorAlgebra {
val tensor = randomNormal(shape = Shape(2, 3, 3), 0)
val tensor = randomNormal(shape = ShapeND(2, 3, 3), 0)
val tensorSigma = tensor + tensor.transposed()
val (tensorS, tensorV) = tensorSigma.symEig()
val tensorSigmaCalc = tensorV matmul (diagonalEmbedding(tensorS) matmul tensorV.transposed())

View File

@ -21,14 +21,14 @@ internal class TestDoubleTensor {
@Test
fun testValue() = DoubleTensorAlgebra {
val value = 12.5
val tensor = fromArray(Shape(1), doubleArrayOf(value))
val tensor = fromArray(ShapeND(1), doubleArrayOf(value))
assertEquals(tensor.value(), value)
}
@OptIn(PerformancePitfall::class)
@Test
fun testStrides() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4))
val tensor = fromArray(ShapeND(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4))
assertEquals(tensor[intArrayOf(0, 1)], 5.8)
assertTrue(
tensor.elements().map { it.second }.toList()
@ -38,7 +38,7 @@ internal class TestDoubleTensor {
@Test
fun testGet() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4))
val tensor = fromArray(ShapeND(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4))
val matrix = tensor.getTensor(0).asDoubleTensor2D()
assertEquals(matrix[0, 1], 5.8)
@ -67,7 +67,7 @@ internal class TestDoubleTensor {
val doubleArray = DoubleBuffer(1.0, 2.0, 3.0)
// create ND buffers, no data is copied
val ndArray: MutableBufferND<Double> = DoubleBufferND(ColumnStrides(Shape(3)), doubleArray)
val ndArray: MutableBufferND<Double> = DoubleBufferND(ColumnStrides(ShapeND(3)), doubleArray)
// map to tensors
val tensorArray = ndArray.asDoubleTensor() // Data is copied because of strides change.
@ -91,7 +91,7 @@ internal class TestDoubleTensor {
@Test
fun test2D() = with(DoubleTensorAlgebra) {
val tensor: DoubleTensor = structureND(Shape(3, 3)) { (i, j) -> (i - j).toDouble() }
val tensor: DoubleTensor = structureND(ShapeND(3, 3)) { (i, j) -> (i - j).toDouble() }
//println(tensor.toPrettyString())
val tensor2d = tensor.asDoubleTensor2D()
assertBufferEquals(DoubleBuffer(1.0, 0.0, -1.0), tensor2d.rows[1])
@ -100,7 +100,7 @@ internal class TestDoubleTensor {
@Test
fun testMatrixIteration() = with(DoubleTensorAlgebra) {
val tensor = structureND(Shape(3, 3, 3, 3)) { index -> index.sum().toDouble() }
val tensor = structureND(ShapeND(3, 3, 3, 3)) { index -> index.sum().toDouble() }
tensor.forEachMatrix { index, matrix ->
println(index.joinToString { it.toString() })
println(matrix)

View File

@ -6,7 +6,7 @@
package space.kscience.kmath.tensors.core
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.contentEquals
import space.kscience.kmath.nd.get
import space.kscience.kmath.operations.invoke
@ -20,53 +20,53 @@ internal class TestDoubleTensorAlgebra {
@Test
fun testDoublePlus() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(2), doubleArrayOf(1.0, 2.0))
val tensor = fromArray(ShapeND(2), doubleArrayOf(1.0, 2.0))
val res = 10.0 + tensor
assertTrue(res.source contentEquals doubleArrayOf(11.0, 12.0))
}
@Test
fun testDoubleDiv() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(2), doubleArrayOf(2.0, 4.0))
val tensor = fromArray(ShapeND(2), doubleArrayOf(2.0, 4.0))
val res = 2.0 / tensor
assertTrue(res.source contentEquals doubleArrayOf(1.0, 0.5))
}
@Test
fun testDivDouble() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(2), doubleArrayOf(10.0, 5.0))
val tensor = fromArray(ShapeND(2), doubleArrayOf(10.0, 5.0))
val res = tensor / 2.5
assertTrue(res.source contentEquals doubleArrayOf(4.0, 2.0))
}
@Test
fun testTranspose1x1() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(1), doubleArrayOf(0.0))
val tensor = fromArray(ShapeND(1), doubleArrayOf(0.0))
val res = tensor.transposed(0, 0)
assertTrue(res.asDoubleTensor().source contentEquals doubleArrayOf(0.0))
assertTrue(res.shape contentEquals Shape(1))
assertTrue(res.shape contentEquals ShapeND(1))
}
@Test
fun testTranspose3x2() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor = fromArray(ShapeND(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res = tensor.transposed(1, 0)
assertTrue(res.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0))
assertTrue(res.shape contentEquals Shape(2, 3))
assertTrue(res.shape contentEquals ShapeND(2, 3))
}
@Test
fun testTranspose1x2x3() = DoubleTensorAlgebra {
val tensor = fromArray(Shape(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor = fromArray(ShapeND(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res01 = tensor.transposed(0, 1)
val res02 = tensor.transposed(-3, 2)
val res12 = tensor.transposed()
assertTrue(res01.shape contentEquals Shape(2, 1, 3))
assertTrue(res02.shape contentEquals Shape(3, 2, 1))
assertTrue(res12.shape contentEquals Shape(1, 3, 2))
assertTrue(res01.shape contentEquals ShapeND(2, 1, 3))
assertTrue(res02.shape contentEquals ShapeND(3, 2, 1))
assertTrue(res12.shape contentEquals ShapeND(1, 3, 2))
assertTrue(res01.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res02.asDoubleTensor().source contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0))
@ -75,7 +75,7 @@ internal class TestDoubleTensorAlgebra {
@Test
fun testLinearStructure() = DoubleTensorAlgebra {
val shape = Shape(3)
val shape = ShapeND(3)
val tensorA = full(value = -4.5, shape = shape)
val tensorB = full(value = 10.9, shape = shape)
val tensorC = full(value = 789.3, shape = shape)
@ -107,28 +107,28 @@ internal class TestDoubleTensorAlgebra {
@Test
fun testDot() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor11 = fromArray(Shape(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(Shape(3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(Shape(1, 1, 3), doubleArrayOf(-1.0, -2.0, -3.0))
val tensor4 = fromArray(Shape(2, 3, 3), (1..18).map { it.toDouble() }.toDoubleArray())
val tensor5 = fromArray(Shape(2, 3, 3), (1..18).map { 1 + it.toDouble() }.toDoubleArray())
val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor11 = fromArray(ShapeND(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(ShapeND(1, 1, 3), doubleArrayOf(-1.0, -2.0, -3.0))
val tensor4 = fromArray(ShapeND(2, 3, 3), (1..18).map { it.toDouble() }.toDoubleArray())
val tensor5 = fromArray(ShapeND(2, 3, 3), (1..18).map { 1 + it.toDouble() }.toDoubleArray())
val res12 = tensor1.dot(tensor2)
assertTrue(res12.source contentEquals doubleArrayOf(140.0, 320.0))
assertTrue(res12.shape contentEquals Shape(2))
assertTrue(res12.shape contentEquals ShapeND(2))
val res32 = tensor3.matmul(tensor2)
assertTrue(res32.source contentEquals doubleArrayOf(-140.0))
assertTrue(res32.shape contentEquals Shape(1, 1))
assertTrue(res32.shape contentEquals ShapeND(1, 1))
val res22 = tensor2.dot(tensor2)
assertTrue(res22.source contentEquals doubleArrayOf(1400.0))
assertTrue(res22.shape contentEquals Shape(1))
assertTrue(res22.shape contentEquals ShapeND(1))
val res11 = tensor1.dot(tensor11)
assertTrue(res11.source contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0))
assertTrue(res11.shape contentEquals Shape(2, 2))
assertTrue(res11.shape contentEquals ShapeND(2, 2))
val res45 = tensor4.matmul(tensor5)
assertTrue(
@ -137,44 +137,44 @@ internal class TestDoubleTensorAlgebra {
468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0
)
)
assertTrue(res45.shape contentEquals Shape(2, 3, 3))
assertTrue(res45.shape contentEquals ShapeND(2, 3, 3))
}
@Test
fun testDiagonalEmbedding() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor2 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor3 = zeros(Shape(2, 3, 4, 5))
val tensor1 = fromArray(ShapeND(3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor2 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor3 = zeros(ShapeND(2, 3, 4, 5))
assertTrue(
diagonalEmbedding(tensor3, 0, 3, 4).shape contentEquals
Shape(2, 3, 4, 5, 5)
ShapeND(2, 3, 4, 5, 5)
)
assertTrue(
diagonalEmbedding(tensor3, 1, 3, 4).shape contentEquals
Shape(2, 3, 4, 6, 6)
ShapeND(2, 3, 4, 6, 6)
)
assertTrue(
diagonalEmbedding(tensor3, 2, 0, 3).shape contentEquals
Shape(7, 2, 3, 7, 4)
ShapeND(7, 2, 3, 7, 4)
)
val diagonal1 = diagonalEmbedding(tensor1, 0, 1, 0)
assertTrue(diagonal1.shape contentEquals Shape(3, 3))
assertTrue(diagonal1.shape contentEquals ShapeND(3, 3))
assertTrue(
diagonal1.source contentEquals
doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0)
)
val diagonal1Offset = diagonalEmbedding(tensor1, 1, 1, 0)
assertTrue(diagonal1Offset.shape contentEquals Shape(4, 4))
assertTrue(diagonal1Offset.shape contentEquals ShapeND(4, 4))
assertTrue(
diagonal1Offset.source contentEquals
doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0)
)
val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2)
assertTrue(diagonal2.shape contentEquals Shape(4, 2, 4))
assertTrue(diagonal2.shape contentEquals ShapeND(4, 2, 4))
assertTrue(
diagonal2.source contentEquals
doubleArrayOf(
@ -188,9 +188,9 @@ internal class TestDoubleTensorAlgebra {
@Test
fun testEq() = DoubleTensorAlgebra {
val tensor1 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor3 = fromArray(Shape(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0))
val tensor1 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor3 = fromArray(ShapeND(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0))
assertTrue(tensor1 eq tensor1)
assertTrue(tensor1 eq tensor2)
@ -204,7 +204,7 @@ internal class TestDoubleTensorAlgebra {
val l = tensor.getTensor(0).map { it + 1.0 }
val r = tensor.getTensor(1).map { it - 1.0 }
val res = l + r
assertTrue { Shape(5, 5) contentEquals res.shape }
assertTrue { ShapeND(5, 5) contentEquals res.shape }
assertEquals(2.0, res[4, 4])
}
}

View File

@ -33,7 +33,7 @@ public open class ViktorFieldOpsND :
override val elementAlgebra: DoubleField get() = DoubleField
@OptIn(UnsafeKMathAPI::class)
override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND =
override fun structureND(shape: ShapeND, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND =
F64Array(*shape.asArray()).apply {
ColumnStrides(shape).asSequence().forEach { index ->
set(value = DoubleField.initializer(index), indices = index)
@ -46,7 +46,7 @@ public open class ViktorFieldOpsND :
@PerformancePitfall
override fun StructureND<Double>.map(transform: DoubleField.(Double) -> Double): ViktorStructureND =
F64Array(*shape.asArray()).apply {
ColumnStrides(Shape(shape)).asSequence().forEach { index ->
ColumnStrides(ShapeND(shape)).asSequence().forEach { index ->
set(value = DoubleField.transform(this@map[index]), indices = index)
}
}.asStructure()
@ -56,7 +56,7 @@ public open class ViktorFieldOpsND :
override fun StructureND<Double>.mapIndexed(
transform: DoubleField.(index: IntArray, Double) -> Double,
): ViktorStructureND = F64Array(*shape.asArray()).apply {
ColumnStrides(Shape(shape)).asSequence().forEach { index ->
ColumnStrides(ShapeND(shape)).asSequence().forEach { index ->
set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index)
}
}.asStructure()
@ -127,7 +127,7 @@ public open class ViktorFieldND(
private val shapeAsArray: IntArray,
) : ViktorFieldOpsND(), FieldND<Double, DoubleField>, NumbersAddOps<StructureND<Double>> {
override val shape: Shape = Shape(shapeAsArray)
override val shape: ShapeND = ShapeND(shapeAsArray)
override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shapeAsArray).asStructure() }

View File

@ -9,11 +9,11 @@ import org.jetbrains.bio.viktor.F64Array
import space.kscience.kmath.misc.PerformancePitfall
import space.kscience.kmath.nd.ColumnStrides
import space.kscience.kmath.nd.MutableStructureND
import space.kscience.kmath.nd.Shape
import space.kscience.kmath.nd.ShapeND
@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE")
public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND<Double> {
override val shape: Shape get() = Shape(f64Buffer.shape)
override val shape: ShapeND get() = ShapeND(f64Buffer.shape)
@OptIn(PerformancePitfall::class)
override inline fun get(index: IntArray): Double = f64Buffer.get(*index)