This commit is contained in:
Alexander Nozik 2023-11-04 11:49:31 +03:00
parent 46eacbb750
commit 2386ecba41
45 changed files with 297 additions and 309 deletions

View File

@ -106,4 +106,11 @@ public fun <T : Any, A : Attribute<T>> Attributes(
attrValue: T,
): Attributes = Attributes(mapOf(attribute to attrValue))
/**
* Create Attributes with a single [Unit] valued attribute
*/
public fun <A : Attribute<Unit>> Attributes(
attribute: A
): Attributes = Attributes(mapOf(attribute to Unit))
public operator fun Attributes.plus(other: Attributes): Attributes = Attributes(content + other.content)

View File

@ -26,3 +26,10 @@ public inline fun <reified T> safeTypeOf(): SafeType<T> = SafeType(typeOf<T>())
@Suppress("UNCHECKED_CAST")
@UnstableAttributesAPI
public val <T> SafeType<T>.kClass: KClass<T & Any> get() = kType.classifier as KClass<T & Any>
/**
* An interface containing [type] for dynamic type checking.
*/
public interface WithType<out T> {
public val type: SafeType<T>
}

View File

@ -47,7 +47,7 @@ internal class MatrixInverseBenchmark {
@Benchmark
fun ejmlInverse(blackhole: Blackhole) {
EjmlLinearSpaceDDRM {
blackhole.consume(matrix.toEjml().inverse())
blackhole.consume(matrix.toEjml().inverted())
}
}
}

View File

@ -10,6 +10,7 @@ import space.kscience.kmath.complex.ComplexField
import space.kscience.kmath.expressions.interpret
import space.kscience.kmath.operations.Algebra
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.test.Test
import kotlin.test.assertEquals
@ -39,6 +40,8 @@ internal class TestParser {
@Test
fun evaluateMstBinary() {
val magicalAlgebra = object : Algebra<String> {
override val bufferFactory: MutableBufferFactory<String> get() = MutableBufferFactory()
override fun bindSymbolOrNull(value: String): String = value
override fun unaryOperationFunction(operation: String): (arg: String) -> String {

View File

@ -10,6 +10,7 @@ kscience {
dependencies {
api(projects.kmathCore)
api(projects.kmathMemory)
}
testDependencies {

View File

@ -5,12 +5,14 @@
package space.kscience.kmath.complex
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.memory.MemoryReader
import space.kscience.kmath.memory.MemorySpec
import space.kscience.kmath.memory.MemoryWriter
import space.kscience.kmath.memory.*
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.*
/**
@ -51,8 +53,11 @@ public object ComplexField :
Norm<Complex, Complex>,
NumbersAddOps<Complex>,
ScaleOperations<Complex> {
override val bufferFactory: MutableBufferFactory<Complex> = MutableBufferFactory { size, init ->
MutableMemoryBuffer.create(Complex, size, init)
override val bufferFactory: MutableBufferFactory<Complex> = object : MutableBufferFactory<Complex> {
override fun invoke(size: Int, builder: (Int) -> Complex): MutableBuffer<Complex> =
MutableMemoryBuffer.create(Complex, size, builder)
override val type: SafeType<Complex> = safeTypeOf()
}
override val zero: Complex = 0.0.toComplex()
@ -202,8 +207,10 @@ public data class Complex(val re: Double, val im: Double) {
override fun toString(): String = "($re + i * $im)"
public companion object : MemorySpec<Complex> {
override val objectSize: Int
get() = 16
override val type: SafeType<Complex> get() = safeTypeOf()
override val objectSize: Int get() = 16
override fun MemoryReader.read(offset: Int): Complex =
Complex(readDouble(offset), readDouble(offset + 8))

View File

@ -5,15 +5,14 @@
package space.kscience.kmath.complex
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.memory.MemoryReader
import space.kscience.kmath.memory.MemorySpec
import space.kscience.kmath.memory.MemoryWriter
import space.kscience.kmath.memory.*
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MemoryBuffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableMemoryBuffer
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.*
/**
@ -37,6 +36,8 @@ public class Quaternion(
require(!z.isNaN()) { "z-component of quaternion is not-a-number" }
}
override val type: SafeType<Double> get() = safeTypeOf()
/**
* Returns a string representation of this quaternion.
*/
@ -78,6 +79,7 @@ public class Quaternion(
public companion object : MemorySpec<Quaternion> {
override val objectSize: Int get() = 32
override val type: SafeType<Quaternion> get() = safeTypeOf()
override fun MemoryReader.read(offset: Int): Quaternion = Quaternion(
readDouble(offset),
@ -122,7 +124,7 @@ public val Quaternion.reciprocal: Quaternion
/**
* Produce a normalized version of this quaternion
*/
public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra){ this@normalized / norm(this@normalized) }
public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra) { this@normalized / norm(this@normalized) }
/**
* A field of [Quaternion].
@ -131,6 +133,8 @@ public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra){ this@n
public object QuaternionAlgebra : Group<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
ExponentialOperations<Quaternion>, NumbersAddOps<Quaternion>, ScaleOperations<Quaternion> {
override val bufferFactory: MutableBufferFactory<Quaternion> = MutableBufferFactory()
override val zero: Quaternion = Quaternion(0.0)
public val one: Quaternion = Quaternion(1.0)

View File

@ -9,7 +9,6 @@ kscience{
wasm()
dependencies {
api(projects.kmathMemory)
api(projects.attributesKt)
}

View File

@ -188,7 +188,7 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
vararg derivatives: T,
): DS<T, A> {
require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" }
val data = derivatives.asBuffer()
val data = derivatives.asList().asBuffer(algebra.type)
return DS(data)
}

View File

@ -6,6 +6,7 @@
package space.kscience.kmath.expressions
import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.linear.Point
import space.kscience.kmath.operations.*

View File

@ -5,15 +5,12 @@
package space.kscience.kmath.linear
import space.kscience.attributes.SafeType
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.VirtualBuffer
import space.kscience.kmath.structures.indices
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public class BufferedLinearSpace<T, out A : Ring<T>>(

View File

@ -6,11 +6,11 @@
package space.kscience.kmath.linear
import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.BufferRingOps
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
@ -173,15 +173,15 @@ public interface LinearSpace<T, out A : Ring<T>> : MatrixOperations<T> {
public operator fun T.times(v: Point<T>): Point<T> = v * this
/**
* Get an attribute value for the structure in this scope. Structure features take precedence other context features.
* Get an attribute value for the structure in this scope. Structure attributes are preferred to computed attributes.
*
* @param structure the structure.
* @param attribute to be computed.
* @return a feature object or `null` if it isn't present.
*/
@UnstableKMathAPI
public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T? =
structure.attributes[attribute]
public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T =
structure.attributes[attribute] ?: error("Can't compute attribute $attribute for $structure")
public companion object {

View File

@ -7,6 +7,7 @@
package space.kscience.kmath.linear
import space.kscience.attributes.Attributes
import space.kscience.attributes.PolymorphicAttribute
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
@ -19,32 +20,42 @@ import space.kscience.kmath.structures.*
* *a* is the owning matrix.
*
* @param T the type of matrices' items.
* @param l The lower triangular matrix in this decomposition. It may have [LowerTriangular].
* @param u The upper triangular matrix in this decomposition. It may have [UpperTriangular].
* @param lu combined L and U matrix
*/
public class LupDecomposition<T>(
public val linearSpace: LinearSpace<T, Ring<T>>,
public val l: Matrix<T>,
public val u: Matrix<T>,
private val lu: Matrix<T>,
public val pivot: IntBuffer,
private val even: Boolean,
) {
public val elementAlgebra: Ring<T> get() = linearSpace.elementAlgebra
public val pivotMatrix: VirtualMatrix<T>
public val l: Matrix<T>
get() = VirtualMatrix(lu.type, lu.rowNum, lu.colNum, attributes = Attributes(LowerTriangular)) { i, j ->
when {
j < i -> lu[i, j]
j == i -> elementAlgebra.one
else -> elementAlgebra.zero
}
}
public val u: Matrix<T>
get() = VirtualMatrix(lu.type, lu.rowNum, lu.colNum, attributes = Attributes(UpperTriangular)) { i, j ->
if (j >= i) lu[i, j] else elementAlgebra.zero
}
public val pivotMatrix: Matrix<T>
get() = VirtualMatrix(linearSpace.type, l.rowNum, l.colNum) { row, column ->
if (column == pivot[row]) elementAlgebra.one else elementAlgebra.zero
}
public val <T> LupDecomposition<T>.determinant by lazy {
public val determinant: T by lazy {
elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
}
}
public class LupDecompositionAttribute<T>(type: SafeType<LupDecomposition<T>>) :
PolymorphicAttribute<LupDecomposition<T>>(type),
MatrixAttribute<LupDecomposition<T>>
@ -52,59 +63,6 @@ public class LupDecompositionAttribute<T>(type: SafeType<LupDecomposition<T>>) :
public val <T> MatrixOperations<T>.LUP: LupDecompositionAttribute<T>
get() = LupDecompositionAttribute(safeTypeOf())
///**
// * Common implementation of [LupDecomposition].
// */
//private class LupDecompositionImpl<T : Any>(
// public val elementContext: Field<T>,
// public val lu: Matrix<T>,
// public val pivot: IntBuffer,
// private val even: Boolean,
//) : LupDecomposition<T> {
// /**
// * Returns the matrix L of the decomposition.
// *
// * L is a lower-triangular matrix with [Ring.one] in diagonal
// */
// override val l: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
// when {
// j < i -> lu[i, j]
// j == i -> elementContext.one
// else -> elementContext.zero
// }
// }.withFeature(LowerTriangular)
//
//
// /**
// * Returns the matrix U of the decomposition.
// *
// * U is an upper-triangular matrix including the diagonal
// */
// override val u: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
// if (j >= i) lu[i, j] else elementContext.zero
// }.withFeature(UpperTriangular)
//
// /**
// * Returns the P rows permutation matrix.
// *
// * P is a sparse matrix with exactly one element set to [Ring.one] in
// * each row and each column, all other elements being set to [Ring.zero].
// */
// override val p: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
// if (j == pivot[i]) elementContext.one else elementContext.zero
// }
//
// /**
// * Return the determinant of the matrix
// * @return determinant of the matrix
// */
// override val determinant: T by lazy {
// elementContext { (0 until lu.shape[0]).fold(if(even) one else -one) { value, i -> value * lu[i, i] } }
// }
//
//}
@PublishedApi
internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
if (value > elementAlgebra.zero) value else elementAlgebra { -value }
@ -115,14 +73,14 @@ internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
matrix: Matrix<T>,
checkSingular: (T) -> Boolean,
): LupDecomposition<T> {
): LupDecomposition<T> = elementAlgebra {
require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" }
val m = matrix.colNum
val pivot = IntArray(matrix.rowNum)
//TODO just waits for multi-receivers
BufferAccessor2D(matrix.rowNum, matrix.colNum, elementAlgebra.bufferFactory).run {
elementAlgebra {
with(BufferAccessor2D(matrix.rowNum, matrix.colNum, elementAlgebra.bufferFactory)){
val lu = create(matrix)
// Initialize the permutation array and parity
@ -184,28 +142,12 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
for (row in col + 1 until m) lu[row, col] /= luDiag
}
val l: MatrixWrapper<T> = VirtualMatrix(type, rowNum, colNum) { i, j ->
when {
j < i -> lu[i, j]
j == i -> one
else -> zero
}
}.withAttribute(LowerTriangular)
val u = VirtualMatrix(type, rowNum, colNum) { i, j ->
if (j >= i) lu[i, j] else zero
}.withAttribute(UpperTriangular)
//
// val p = VirtualMatrix(rowNum, colNum) { i, j ->
// if (j == pivot[i]) one else zero
// }.withAttribute(Determinant, if (even) one else -one)
return LupDecomposition(this@lup, l, u, pivot.asBuffer())
}
return LupDecomposition(this@lup, lu.toStructure2D(), pivot.asBuffer(), even)
}
}
public fun LinearSpace<Double, Float64Field>.lup(
matrix: Matrix<Double>,
singularityThreshold: Double = 1e-11,

View File

@ -7,9 +7,9 @@ package space.kscience.kmath.linear
import space.kscience.attributes.FlagAttribute
import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.structures.BufferAccessor2D
import space.kscience.kmath.structures.MutableBufferFactory

View File

@ -16,7 +16,7 @@ import space.kscience.kmath.operations.Ring
*
* @param T the type of items.
*/
public class MatrixWrapper<out T : Any> internal constructor(
public class MatrixWrapper<out T> internal constructor(
public val origin: Matrix<T>,
override val attributes: Attributes,
) : Matrix<T> by origin {

View File

@ -5,17 +5,12 @@
package space.kscience.kmath.nd
import space.kscience.attributes.Attribute
import space.kscience.attributes.AttributeContainer
import space.kscience.attributes.Attributes
import space.kscience.attributes.SafeType
import space.kscience.attributes.*
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Buffer
import kotlin.jvm.JvmName
import kotlin.math.abs
public interface StructureAttribute<T> : Attribute<T>
@ -148,28 +143,20 @@ public inline fun <reified T : Any> BufferND(
crossinline initializer: (IntArray) -> T,
): BufferND<T> = BufferND(strides, Buffer(strides.linearSize) { i -> initializer(strides.index(i)) })
public inline fun <T : Any> BufferND(
type: SafeType<T>,
strides: Strides,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = BufferND(strides, Buffer(type, strides.linearSize) { i -> initializer(strides.index(i)) })
public inline fun <reified T : Any> BufferND(
shape: ShapeND,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = BufferND(ColumnStrides(shape), initializer)
@JvmName("autoVarArg")
public inline fun <reified T : Any> BufferND(
vararg shape: Int,
crossinline initializer: (IntArray) -> T,
): BufferND<T> = BufferND(ColumnStrides(ShapeND(shape)), initializer)
public inline fun <T : Any> BufferND(
public fun <T : Any> BufferND(
type: SafeType<T>,
vararg shape: Int,
crossinline initializer: (IntArray) -> T,
initializer: (IntArray) -> T,
): BufferND<T> = BufferND(type, ColumnStrides(ShapeND(shape)), initializer)

View File

@ -6,19 +6,12 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.operations.Ring.Companion.optimizedPower
import space.kscience.kmath.structures.MutableBufferFactory
/**
* An interface containing [type] for dynamic type checking.
*/
public interface WithType<out T> {
public val type: SafeType<T>
}
/**
* Represents an algebraic structure.
*

View File

@ -5,20 +5,18 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.BufferedRingOpsND
import space.kscience.kmath.operations.BigInt.Companion.BASE
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.log2
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sign
private typealias Magnitude = UIntArray
private typealias TBase = ULong
/**
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
@ -29,7 +27,7 @@ private typealias TBase = ULong
@OptIn(UnstableKMathAPI::class)
public object BigIntField : Field<BigInt>, NumbersAddOps<BigInt>, ScaleOperations<BigInt> {
override val type: SafeType<BigInt> = safeTypeOf()
override val bufferFactory: MutableBufferFactory<BigInt> = MutableBufferFactory()
override val zero: BigInt = BigInt.ZERO
override val one: BigInt = BigInt.ONE

View File

@ -5,8 +5,6 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableBufferFactory
@ -21,10 +19,10 @@ public interface WithSize {
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
public val elementAlgebra: A
override val type: SafeType<Buffer<T>> get() = safeTypeOf<Buffer<T>>()
public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
override val bufferFactory: MutableBufferFactory<Buffer<T>> get() = MutableBufferFactory()
public fun buffer(size: Int, vararg elements: T): Buffer<T> {
require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
return elementBufferFactory(size) { elements[it] }

View File

@ -5,10 +5,9 @@
package space.kscience.kmath.operations
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.expressions.Symbol
import space.kscience.kmath.structures.MutableBufferFactory
/**
* An algebra for generic boolean logic
@ -74,7 +73,7 @@ public interface LogicAlgebra<T : Any> : Algebra<T> {
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object BooleanAlgebra : LogicAlgebra<Boolean> {
override val type: SafeType<Boolean> get() = safeTypeOf()
override val bufferFactory: MutableBufferFactory<Boolean> get() = MutableBufferFactory()
override fun const(boolean: Boolean): Boolean = boolean

View File

@ -4,7 +4,7 @@
*/
package space.kscience.kmath.operations
import space.kscience.kmath.structures.*
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.pow as kpow
@ -129,7 +129,7 @@ public val Double.Companion.algebra: Float64Field get() = Float64Field
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Float32Field : ExtendedField<Float>, Norm<Float, Float> {
override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory(::Float32Buffer)
override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory()
override val zero: Float get() = 0.0f
override val one: Float get() = 1.0f
@ -187,7 +187,7 @@ public val Float.Companion.algebra: Float32Field get() = Float32Field
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int32Ring : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory(::Int32Buffer)
override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory()
override val zero: Int get() = 0
override val one: Int get() = 1
@ -212,7 +212,7 @@ public val Int.Companion.algebra: Int32Ring get() = Int32Ring
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int16Ring : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> {
override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory(::Int16Buffer)
override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory()
override val zero: Short get() = 0
override val one: Short get() = 1
@ -237,7 +237,7 @@ public val Short.Companion.algebra: Int16Ring get() = Int16Ring
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int8Ring : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory(::Int8Buffer)
override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory()
override val zero: Byte get() = 0
override val one: Byte get() = 1
@ -262,7 +262,7 @@ public val Byte.Companion.algebra: Int8Ring get() = Int8Ring
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public object Int64Ring : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory(::Int64Buffer)
override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory()
override val zero: Long get() = 0L
override val one: Long get() = 1L

View File

@ -5,13 +5,16 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
/**
* [MutableBuffer] implementation over [Array].
*
* @param T the type of elements contained in the buffer.
* @property array The underlying array.
*/
public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
public class ArrayBuffer<T>(override val type: SafeType<T>, internal val array: Array<T>) : MutableBuffer<T> {
// Can't inline because array is invariant
override val size: Int get() = array.size
@ -22,13 +25,17 @@ public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
}
override operator fun iterator(): Iterator<T> = array.iterator()
override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf())
override fun copy(): MutableBuffer<T> = ArrayBuffer(type, array.copyOf())
override fun toString(): String = Buffer.toString(this)
}
/**
* Returns an [ArrayBuffer] that wraps the original array.
*/
public fun <T> Array<T>.asBuffer(type: SafeType<T>): ArrayBuffer<T> = ArrayBuffer(type, this)
/**
* Returns an [ArrayBuffer] that wraps the original array.
*/
public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
public inline fun <reified T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(safeTypeOf<T>(), this)

View File

@ -6,9 +6,9 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.operations.WithSize
import space.kscience.kmath.operations.WithType
import space.kscience.kmath.operations.asSequence
import kotlin.reflect.typeOf

View File

@ -1,5 +1,6 @@
package space.kscience.kmath.structures
import space.kscience.attributes.SafeType
import space.kscience.kmath.UnstableKMathAPI
/**
@ -8,6 +9,8 @@ import space.kscience.kmath.UnstableKMathAPI
public interface BufferView<T> : Buffer<T> {
public val origin: Buffer<T>
override val type: SafeType<T> get() = origin.type
/**
* Get the index in [origin] buffer from index in this buffer.
* Return -1 if element not present in the original buffer
@ -36,6 +39,7 @@ public class BufferSlice<T>(
}
}
override fun get(index: Int): T = if (index >= size) {
throw IndexOutOfBoundsException("$index is out of ${0 until size} rage")
} else {
@ -100,7 +104,8 @@ public fun <T> Buffer<T>.slice(range: IntRange): BufferView<T> = if (this is Buf
* Dynamically create a range from the initial range
*/
@UnstableKMathAPI
public inline fun <T> Buffer<T>.slice(rangeBuilder: IntRange.() -> IntRange): BufferView<T> = slice(rangeBuilder(indices))
public inline fun <T> Buffer<T>.slice(rangeBuilder: IntRange.() -> IntRange): BufferView<T> =
slice(rangeBuilder(indices))
/**
* Resize original buffer to a given range using given [range], filling additional segments with [defaultValue].

View File

@ -72,15 +72,21 @@ public interface MutableBuffer<T> : Buffer<T> {
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
*/
@Suppress("UNCHECKED_CAST")
public inline fun <T> MutableBuffer(type: SafeType<T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
when (type.kType) {
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer<T>
typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as MutableBuffer<T>
typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as MutableBuffer<T>
public inline fun <T> MutableBuffer(
type: SafeType<T>,
size: Int,
initializer: (Int) -> T,
): MutableBuffer<T> = when (type.kType) {
typeOf<Boolean>() -> TODO()
typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T>
typeOf<Int16>() -> MutableBuffer.short(size) { initializer(it) as Int16 } as MutableBuffer<T>
typeOf<Int32>() -> MutableBuffer.int(size) { initializer(it) as Int32 } as MutableBuffer<T>
typeOf<Int64>() -> MutableBuffer.long(size) { initializer(it) as Int64 } as MutableBuffer<T>
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as MutableBuffer<T>
typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as MutableBuffer<T>
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer<T>
//TODO add unsigned types
else -> MutableListBuffer(type, MutableList(size, initializer))
}
}
/**
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used

View File

@ -8,7 +8,6 @@ package space.kscience.kmath.linear
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.as2D
import space.kscience.kmath.operations.algebra
import kotlin.test.Test
import kotlin.test.assertEquals
@ -22,7 +21,7 @@ class MatrixTest {
@Test
fun testTranspose() = Double.algebra.linearSpace.run {
val matrix = one(3, 3)
val transposed = matrix.transpose()
val transposed = matrix.transposed
assertTrue { StructureND.contentEquals(matrix, transposed) }
}
@ -38,7 +37,7 @@ class MatrixTest {
@Test
fun testMatrixExtension() = Double.algebra.linearSpace.run {
val transitionMatrix: Matrix<Double> = VirtualMatrix(6, 6) { row, col ->
val transitionMatrix: Matrix<Double> = VirtualMatrix(type,6, 6) { row, col ->
when {
col == 0 -> .50
row + 1 == col -> .50
@ -60,8 +59,8 @@ class MatrixTest {
@Test
fun test2DDot() = Double.algebra.linearSpace.run {
val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D()
val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D()
val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() }
val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() }
// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
// val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() }

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.operations
import space.kscience.kmath.structures.MutableBufferFactory
import java.math.BigDecimal
import java.math.BigInteger
import java.math.MathContext
@ -13,6 +14,8 @@ import java.math.MathContext
* A field over [BigInteger].
*/
public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
override val bufferFactory: MutableBufferFactory<BigInteger> = MutableBufferFactory()
override val zero: BigInteger get() = BigInteger.ZERO
override val one: BigInteger get() = BigInteger.ONE
@ -33,6 +36,7 @@ public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
public abstract class JBigDecimalFieldBase internal constructor(
private val mathContext: MathContext = MathContext.DECIMAL64,
) : Field<BigDecimal>, PowerOperations<BigDecimal>, NumericAlgebra<BigDecimal>, ScaleOperations<BigDecimal> {
override val bufferFactory: MutableBufferFactory<BigDecimal> = MutableBufferFactory()
override val zero: BigDecimal
get() = BigDecimal.ZERO

View File

@ -43,7 +43,7 @@ public interface BlockingBufferChain<out T> : BlockingChain<T>, BufferChain<T> {
public suspend inline fun <reified T : Any> Chain<T>.nextBuffer(size: Int): Buffer<T> = if (this is BufferChain) {
nextBuffer(size)
} else {
Buffer.auto(size) { next() }
Buffer(size) { next() }
}
public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
@ -51,5 +51,5 @@ public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
): Buffer<T> = if (this is BlockingBufferChain) {
nextBufferBlocking(size)
} else {
Buffer.auto(size) { nextBlocking() }
Buffer(size) { nextBlocking() }
}

View File

@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flow
import space.kscience.kmath.chains.BlockingDoubleChain
import space.kscience.kmath.operations.Group
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.Float64Buffer
@ -84,9 +85,9 @@ public fun Flow<Double>.chunked(bufferSize: Int): Flow<Float64Buffer> = flow {
* Map a flow to a moving window buffer. The window step is one.
* To get different steps, one could use skip operation.
*/
public fun <T> Flow<T>.windowed(window: Int): Flow<Buffer<T>> = flow {
public fun <T> Flow<T>.windowed(window: Int, algebra: Group<T>): Flow<Buffer<T>> = flow {
require(window > 1) { "Window size must be more than one" }
val ringBuffer = RingBuffer.boxing<T>(window)
val ringBuffer = RingBuffer(window, algebra)
this@windowed.collect { element ->
ringBuffer.push(element)

View File

@ -7,6 +7,8 @@ package space.kscience.kmath.streaming
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import space.kscience.attributes.SafeType
import space.kscience.kmath.operations.Group
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.VirtualBuffer
@ -14,12 +16,14 @@ import space.kscience.kmath.structures.VirtualBuffer
/**
* Thread-safe ring buffer
*/
@Suppress("UNCHECKED_CAST")
public class RingBuffer<T>(
private val buffer: MutableBuffer<T?>,
private val buffer: MutableBuffer<T>,
private var startIndex: Int = 0,
size: Int = 0,
) : Buffer<T> {
override val type: SafeType<T> get() = buffer.type
private val mutex: Mutex = Mutex()
override var size: Int = size
@ -28,7 +32,7 @@ public class RingBuffer<T>(
override operator fun get(index: Int): T {
require(index >= 0) { "Index must be positive" }
require(index < size) { "Index $index is out of circular buffer size $size" }
return buffer[startIndex.forward(index)] as T
return buffer[startIndex.forward(index)]
}
public fun isFull(): Boolean = size == buffer.size
@ -43,7 +47,7 @@ public class RingBuffer<T>(
override fun computeNext() {
if (count == 0) done() else {
setNext(copy[index] as T)
setNext(copy[index])
index = index.forward(1)
count--
}
@ -55,7 +59,7 @@ public class RingBuffer<T>(
*/
public suspend fun snapshot(): Buffer<T> = mutex.withLock {
val copy = buffer.copy()
VirtualBuffer(size) { i -> copy[startIndex.forward(i)] as T }
VirtualBuffer(type, size) { i -> copy[startIndex.forward(i)] }
}
public suspend fun push(element: T) {
@ -68,19 +72,17 @@ public class RingBuffer<T>(
private fun Int.forward(n: Int): Int = (this + n) % (buffer.size)
override fun toString(): String = Buffer.toString(this)
}
public companion object {
public inline fun <reified T : Any> build(size: Int, empty: T): RingBuffer<T> {
val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer<T?>
public inline fun <reified T : Any> RingBuffer(size: Int, empty: T): RingBuffer<T> {
val buffer = MutableBuffer(size) { empty }
return RingBuffer(buffer)
}
}
/**
/**
* Slow yet universal buffer
*/
public fun <T> boxing(size: Int): RingBuffer<T> {
val buffer: MutableBuffer<T?> = MutableBuffer.boxing(size) { null }
public fun <T> RingBuffer(size: Int, algebra: Group<T>): RingBuffer<T> {
val buffer: MutableBuffer<T> = MutableBuffer(algebra.type, size) { algebra.zero }
return RingBuffer(buffer)
}
}
}

View File

@ -6,6 +6,8 @@
package space.kscience.kmath.structures
import kotlinx.coroutines.*
import space.kscience.attributes.SafeType
import space.kscience.attributes.safeTypeOf
import space.kscience.kmath.PerformancePitfall
import space.kscience.kmath.coroutines.Math
import space.kscience.kmath.nd.ColumnStrides
@ -14,9 +16,11 @@ import space.kscience.kmath.nd.StructureND
public class LazyStructureND<out T>(
public val scope: CoroutineScope,
override val type: SafeType<T>,
override val shape: ShapeND,
public val function: suspend (IntArray) -> T,
) : StructureND<T> {
private val cache: MutableMap<IntArray, Deferred<T>> = HashMap()
public fun async(index: IntArray): Deferred<T> = cache.getOrPut(index) {
@ -47,13 +51,13 @@ public suspend fun <T> StructureND<T>.await(index: IntArray): T =
* PENDING would benefit from KEEP-176
*/
@OptIn(PerformancePitfall::class)
public inline fun <T, R> StructureND<T>.mapAsyncIndexed(
public inline fun <T, reified R> StructureND<T>.mapAsyncIndexed(
scope: CoroutineScope,
crossinline function: suspend (T, index: IntArray) -> R,
): LazyStructureND<R> = LazyStructureND(scope, shape) { index -> function(get(index), index) }
): LazyStructureND<R> = LazyStructureND(scope, safeTypeOf(), shape) { index -> function(get(index), index) }
@OptIn(PerformancePitfall::class)
public inline fun <T, R> StructureND<T>.mapAsync(
public inline fun <T, reified R> StructureND<T>.mapAsync(
scope: CoroutineScope,
crossinline function: suspend (T) -> R,
): LazyStructureND<R> = LazyStructureND(scope, shape) { index -> function(get(index)) }
): LazyStructureND<R> = LazyStructureND(scope, safeTypeOf(), shape) { index -> function(get(index)) }

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.dimensions
import space.kscience.attributes.SafeType
import space.kscience.kmath.linear.*
import space.kscience.kmath.nd.ShapeND
import space.kscience.kmath.nd.Structure2D
@ -48,6 +49,9 @@ 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 type: SafeType<T> get() = structure.type
override val shape: ShapeND get() = structure.shape
override val rowNum: Int get() = shape[0]
override val colNum: Int get() = shape[1]
@ -75,8 +79,10 @@ public interface DPoint<out T, D : Dimension> : Point<T> {
* Dimension-safe point wrapper
*/
@JvmInline
public value class DPointWrapper<out T, D : Dimension>(public val point: Point<T>) :
DPoint<T, D> {
public value class DPointWrapper<out T, D : Dimension>(public val point: Point<T>) : DPoint<T, D> {
override val type: SafeType<T> get() = point.type
override val size: Int get() = point.size
override operator fun get(index: Int): T = point[index]

View File

@ -6,14 +6,9 @@
package space.kscience.kmath.ejml
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.linear.InverseMatrixFeature
import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.linear.Matrix
import space.kscience.kmath.linear.Point
import space.kscience.kmath.nd.Structure2D
import space.kscience.kmath.linear.*
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.Ring
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* [LinearSpace] implementation specialized for a certain EJML type.
@ -42,8 +37,7 @@ public abstract class EjmlLinearSpace<T : Any, out A : Ring<T>, out M : org.ejml
public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector<T, M>
@Suppress("UNCHECKED_CAST")
@UnstableKMathAPI
public fun EjmlMatrix<T, *>.inverse(): Structure2D<Double> =
attributeFor(this, InverseMatrixFeature::class)?.inverse as Structure2D<Double>
public fun EjmlMatrix<T, *>.inverted(): Matrix<Double> =
attributeFor(this, Float64Field.linearSpace.Inverted)
}

View File

@ -96,7 +96,7 @@ internal class EjmlMatrixTest {
val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
val matrix = space { l dot u }
val inverted = matrix.toEjml().inverse()
val inverted = matrix.toEjml().inverted()
val res = matrix dot inverted

View File

@ -48,7 +48,7 @@ public fun Sequence<DoubleArray>.toMatrix(): RealMatrix = toList().let {
}
public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix =
VirtualMatrix(rowNum * n, colNum) { row, col ->
VirtualMatrix(type, rowNum * n, colNum) { row, col ->
get(if (row == 0) 0 else row % rowNum, col)
}

View File

@ -7,14 +7,12 @@
package space.kscience.kmath.functions
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.operations.Ring
import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.MutableBufferFactory
import kotlin.math.max
import kotlin.math.min
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
@ -67,6 +65,7 @@ public data class Polynomial<out C>(
public open class PolynomialSpace<C, A>(
public val ring: A,
) : Ring<Polynomial<C>>, ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
override val bufferFactory: MutableBufferFactory<Polynomial<C>> get() = MutableBufferFactory()
/**
* Instance of zero constant (zero of the underlying ring).

View File

@ -5,6 +5,7 @@
package space.kscience.kmath.integration
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.mapToBuffer
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.Float64Buffer
@ -32,11 +33,11 @@ public fun GaussIntegratorRuleFactory.build(
val normalized: Pair<Buffer<Double>, Buffer<Double>> = build(numPoints)
val length = range.endInclusive - range.start
val points = normalized.first.mapToBuffer(::Float64Buffer) {
val points = normalized.first.mapToBuffer(Float64Field.bufferFactory) {
range.start + length / 2 + length / 2 * it
}
val weights = normalized.second.mapToBuffer(::Float64Buffer) {
val weights = normalized.second.mapToBuffer(Float64Field.bufferFactory) {
it * length / 2
}

View File

@ -88,7 +88,7 @@ public class SplineIntegrator<T : Comparable<T>>(
public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
val range = integrand[IntegrationRange] ?: 0.0..1.0
val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(Float64Field, ::Float64Buffer)
val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(Float64Field, Float64Field.bufferFactory)
val nodes: Buffer<Double> = integrand[UnivariateIntegrationNodes] ?: run {
val numPoints = integrand[IntegrandMaxCalls] ?: 100
@ -96,7 +96,7 @@ public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
Float64Buffer(numPoints) { i -> range.start + i * step }
}
val values = nodes.mapToBuffer(::Float64Buffer) { integrand.function(it) }
val values = nodes.mapToBuffer(Float64Field.bufferFactory) { integrand.function(it) }
val polynomials = interpolator.interpolatePolynomials(nodes, values)
val res = polynomials.integrate(Float64Field, range)
return integrand.withAttributes {

View File

@ -7,6 +7,8 @@
package space.kscience.kmath.interpolation
import space.kscience.attributes.SafeType
import space.kscience.attributes.WithType
import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.data.XYColumnarData
import space.kscience.kmath.functions.PiecewisePolynomial
@ -26,9 +28,11 @@ public fun interface Interpolator<T, in X : T, Y : T> {
/**
* And interpolator returning [PiecewisePolynomial] function
*/
public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T> {
public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T>, WithType<T> {
public val algebra: Ring<T>
override val type: SafeType<T> get() = algebra.type
public fun getDefaultValue(): T = error("Out of bounds")
public fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T>
@ -50,14 +54,14 @@ public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
data: Map<T, T>,
): PiecewisePolynomial<T> {
val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer())
val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(type), data.values.toList().asBuffer(type))
return interpolatePolynomials(pointSet)
}
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
data: List<Pair<T, T>>,
): PiecewisePolynomial<T> {
val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer())
val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(type), data.map { it.second }.asBuffer(type))
return interpolatePolynomials(pointSet)
}

View File

@ -12,7 +12,6 @@ import space.kscience.kmath.functions.Polynomial
import space.kscience.kmath.operations.Field
import space.kscience.kmath.operations.Float64Field
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.structures.Float64Buffer
import space.kscience.kmath.structures.MutableBufferFactory
/**
@ -80,4 +79,4 @@ public fun <T : Comparable<T>> Field<T>.splineInterpolator(
): SplineInterpolator<T> = SplineInterpolator(this, bufferFactory)
public val Float64Field.splineInterpolator: SplineInterpolator<Double>
get() = SplineInterpolator(this, ::Float64Buffer)
get() = SplineInterpolator(this, bufferFactory)

View File

@ -7,6 +7,10 @@ kscience {
js()
native()
wasm()
dependencies {
api(projects.kmathCore)
}
}
readme {

View File

@ -1,11 +1,13 @@
/*
* Copyright 2018-2022 KMath contributors.
* Copyright 2018-2023 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.structures
package space.kscience.kmath.memory
import space.kscience.kmath.memory.*
import space.kscience.attributes.SafeType
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer
/**
* A non-boxing buffer over [Memory] object.
@ -15,6 +17,9 @@ import space.kscience.kmath.memory.*
* @property spec the spec of [T] type.
*/
public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
override val type: SafeType<T> get() = spec.type
override val size: Int get() = memory.size / spec.objectSize
override operator fun get(index: Int): T = memory.read { read(spec, spec.objectSize * index) }
@ -43,8 +48,10 @@ public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected
* @property memory the underlying memory segment.
* @property spec the spec of [T] type.
*/
public class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : MemoryBuffer<T>(memory, spec),
MutableBuffer<T> {
public class MutableMemoryBuffer<T : Any>(
memory: Memory,
spec: MemorySpec<T>,
) : MemoryBuffer<T>(memory, spec), MutableBuffer<T> {
private val writer: MemoryWriter = memory.writer()

View File

@ -5,12 +5,15 @@
package space.kscience.kmath.memory
import space.kscience.attributes.WithType
/**
* A specification to read or write custom objects with fixed size in bytes.
*
* @param T the type of object this spec manages.
*/
public interface MemorySpec<T : Any> {
public interface MemorySpec<T : Any>: WithType<T> {
/**
* Size of [T] in bytes after serialization.
*/