Refactor buffer factories

This commit is contained in:
Alexander Nozik 2021-03-15 14:26:17 +03:00
parent 8af2f5eb31
commit 0e0deaeb72
16 changed files with 198 additions and 125 deletions

View File

@ -9,7 +9,7 @@
- Exponential operations merged with hyperbolic functions - Exponential operations merged with hyperbolic functions
- Space is replaced by Group. Space is reserved for vector spaces. - Space is replaced by Group. Space is reserved for vector spaces.
- VectorSpace is now a vector space - VectorSpace is now a vector space
- - Buffer factories for primitives moved to MutableBuffer.Companion
### Deprecated ### Deprecated

View File

@ -432,7 +432,7 @@ public final class space/kscience/kmath/expressions/SymbolIndexerKt {
public static final fun withSymbols ([Lspace/kscience/kmath/expressions/Symbol;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; public static final fun withSymbols ([Lspace/kscience/kmath/expressions/Symbol;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
} }
public final class space/kscience/kmath/linear/BufferLinearSpace : space/kscience/kmath/linear/LinearSpace { public final class space/kscience/kmath/linear/BufferedLinearSpace : space/kscience/kmath/linear/LinearSpace {
public fun <init> (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V public fun <init> (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V
public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D; public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D;
public fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; public fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer;
@ -2115,7 +2115,6 @@ public abstract interface class space/kscience/kmath/structures/Buffer {
public final class space/kscience/kmath/structures/Buffer$Companion { public final class space/kscience/kmath/structures/Buffer$Companion {
public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer;
public final fun real-8hrHhI4 (ILkotlin/jvm/functions/Function1;)[D
} }
public final class space/kscience/kmath/structures/Buffer$DefaultImpls { public final class space/kscience/kmath/structures/Buffer$DefaultImpls {
@ -2123,15 +2122,17 @@ public final class space/kscience/kmath/structures/Buffer$DefaultImpls {
} }
public final class space/kscience/kmath/structures/BufferKt { public final class space/kscience/kmath/structures/BufferKt {
public static final fun ListBuffer (ILkotlin/jvm/functions/Function1;)Ljava/util/List;
public static final fun asBuffer (Ljava/util/List;)Ljava/util/List; public static final fun asBuffer (Ljava/util/List;)Ljava/util/List;
public static final fun asBuffer ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer; public static final fun asBuffer ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer;
public static final fun asIterable (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Iterable; public static final fun asMutableBuffer (Ljava/util/List;)Ljava/util/List;
public static final fun asReadOnly (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; public static final fun asReadOnly (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer;
public static final fun asSequence (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/sequences/Sequence;
public static final fun getIndices (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/ranges/IntRange; public static final fun getIndices (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/ranges/IntRange;
}
public final class space/kscience/kmath/structures/BufferOperationKt {
public static final fun asIterable (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Iterable;
public static final fun asSequence (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/sequences/Sequence;
public static final fun toList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List; public static final fun toList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List;
public static final fun toMutableList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List;
} }
public abstract interface class space/kscience/kmath/structures/FlaggedBuffer : space/kscience/kmath/structures/Buffer { public abstract interface class space/kscience/kmath/structures/FlaggedBuffer : space/kscience/kmath/structures/Buffer {
@ -2316,7 +2317,11 @@ public abstract interface class space/kscience/kmath/structures/MutableBuffer :
public final class space/kscience/kmath/structures/MutableBuffer$Companion { public final class space/kscience/kmath/structures/MutableBuffer$Companion {
public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer;
public final fun float-YxruXGw (ILkotlin/jvm/functions/Function1;)[F
public final fun int-Ye6GY2U (ILkotlin/jvm/functions/Function1;)[I
public final fun long-BuQOeTY (ILkotlin/jvm/functions/Function1;)[J
public final fun real-8hrHhI4 (ILkotlin/jvm/functions/Function1;)[D public final fun real-8hrHhI4 (ILkotlin/jvm/functions/Function1;)[D
public final fun short-1yRgbGw (ILkotlin/jvm/functions/Function1;)[S
} }
public final class space/kscience/kmath/structures/MutableBuffer$DefaultImpls { public final class space/kscience/kmath/structures/MutableBuffer$DefaultImpls {

View File

@ -9,7 +9,7 @@ import space.kscience.kmath.structures.VirtualBuffer
import space.kscience.kmath.structures.indices import space.kscience.kmath.structures.indices
public class BufferLinearSpace<T : Any, A : Ring<T>>( public class BufferedLinearSpace<T : Any, A : Ring<T>>(
override val elementAlgebra: A, override val elementAlgebra: A,
private val bufferFactory: BufferFactory<T>, private val bufferFactory: BufferFactory<T>,
) : LinearSpace<T, A> { ) : LinearSpace<T, A> {

View File

@ -6,9 +6,20 @@ import space.kscience.kmath.nd.as1D
* A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors * A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors
*/ */
public interface LinearSolver<T : Any> { public interface LinearSolver<T : Any> {
/**
* Solve a dot x = b matrix equation and return x
*/
public fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> public fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T>
/**
* Solve a dot x = b vector equation and return b
*/
public fun solve(a: Matrix<T>, b: Point<T>): Point<T> = solve(a, b.asMatrix()).asVector() public fun solve(a: Matrix<T>, b: Point<T>): Point<T> = solve(a, b.asMatrix()).asVector()
public fun inverse(a: Matrix<T>): Matrix<T>
/**
* Get inverse of a matrix
*/
public fun inverse(matrix: Matrix<T>): Matrix<T>
} }
/** /**

View File

@ -5,6 +5,7 @@ import space.kscience.kmath.nd.*
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.RealBuffer
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -174,9 +175,9 @@ public interface LinearSpace<T : Any, out A : Ring<T>> {
public fun <T : Any, A : Ring<T>> buffered( public fun <T : Any, A : Ring<T>> buffered(
algebra: A, algebra: A,
bufferFactory: BufferFactory<T> = Buffer.Companion::boxing, bufferFactory: BufferFactory<T> = Buffer.Companion::boxing,
): LinearSpace<T, A> = BufferLinearSpace(algebra,bufferFactory) ): LinearSpace<T, A> = BufferedLinearSpace(algebra,bufferFactory)
public val real: LinearSpace<Double, RealField> = buffered(RealField, Buffer.Companion::real) public val real: LinearSpace<Double, RealField> = buffered(RealField, ::RealBuffer)
/** /**
* Automatic buffered matrix, unboxed if it is possible * Automatic buffered matrix, unboxed if it is possible

View File

@ -3,10 +3,10 @@ package space.kscience.kmath.linear
import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.nd.getFeature import space.kscience.kmath.nd.getFeature
import space.kscience.kmath.operations.* import space.kscience.kmath.operations.*
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.BufferAccessor2D
import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.MutableBuffer
import space.kscience.kmath.structures.MutableBufferFactory import space.kscience.kmath.structures.MutableBufferFactory
import space.kscience.kmath.structures.RealBuffer
/** /**
* Common implementation of [LupDecompositionFeature]. * Common implementation of [LupDecompositionFeature].
@ -152,7 +152,7 @@ public inline fun <reified T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
): LupDecomposition<T> = lup(MutableBuffer.Companion::auto, matrix, checkSingular) ): LupDecomposition<T> = lup(MutableBuffer.Companion::auto, matrix, checkSingular)
public fun LinearSpace<Double, RealField>.lup(matrix: Matrix<Double>): LupDecomposition<Double> = public fun LinearSpace<Double, RealField>.lup(matrix: Matrix<Double>): LupDecomposition<Double> =
lup(Buffer.Companion::real, matrix) { it < 1e-11 } lup(::RealBuffer, matrix) { it < 1e-11 }
public fun <T : Any> LupDecomposition<T>.solveWithLup( public fun <T : Any> LupDecomposition<T>.solveWithLup(
factory: MutableBufferFactory<T>, factory: MutableBufferFactory<T>,
@ -230,7 +230,7 @@ public inline fun <reified T : Comparable<T>> LinearSpace<T, Field<T>>.inverseWi
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
public fun LinearSpace<Double, RealField>.solveWithLup(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> { public fun LinearSpace<Double, RealField>.solveWithLup(a: Matrix<Double>, b: Matrix<Double>): Matrix<Double> {
// Use existing decomposition if it is provided by matrix // Use existing decomposition if it is provided by matrix
val bufferFactory: MutableBufferFactory<Double> = MutableBuffer.Companion::real val bufferFactory: MutableBufferFactory<Double> = ::RealBuffer
val decomposition: LupDecomposition<Double> = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 } val decomposition: LupDecomposition<Double> = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 }
return decomposition.solveWithLup(bufferFactory, b) return decomposition.solveWithLup(bufferFactory, b)
} }

View File

@ -48,8 +48,8 @@ public interface NDStructure<T> {
public override fun hashCode(): Int public override fun hashCode(): Int
/** /**
* Feature is additional property or hint that does not directly affect the structure, but could in some cases help * Feature is some additional strucure information which allows to access it special properties or hints.
* optimize operations and performance. If the feature is not present, null is defined. * If the feature is not present, null is returned.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <F : Any> getFeature(type: KClass<F>): F? = null public fun <F : Any> getFeature(type: KClass<F>): F? = null

View File

@ -5,7 +5,6 @@ import space.kscience.kmath.operations.ExtendedField
import space.kscience.kmath.operations.NumbersAddOperations import space.kscience.kmath.operations.NumbersAddOperations
import space.kscience.kmath.operations.RealField import space.kscience.kmath.operations.RealField
import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.ScaleOperations
import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.RealBuffer
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
@ -13,7 +12,7 @@ import kotlin.contracts.contract
@OptIn(UnstableKMathAPI::class) @OptIn(UnstableKMathAPI::class)
public class RealNDField( public class RealNDField(
shape: IntArray, shape: IntArray,
) : BufferedNDField<Double, RealField>(shape, RealField, Buffer.Companion::real), ) : BufferedNDField<Double, RealField>(shape, RealField, ::RealBuffer),
NumbersAddOperations<NDStructure<Double>>, NumbersAddOperations<NDStructure<Double>>,
ScaleOperations<NDStructure<Double>>, ScaleOperations<NDStructure<Double>>,
ExtendedField<NDStructure<Double>> { ExtendedField<NDStructure<Double>> {

View File

@ -56,3 +56,12 @@ public fun <T> NDStructure<T>.as1D(): Structure1D<T> = this as? Structure1D<T> ?
* Represent this buffer as 1D structure * Represent this buffer as 1D structure
*/ */
public fun <T> Buffer<T>.asND(): Structure1D<T> = Buffer1DWrapper(this) public fun <T> Buffer<T>.asND(): Structure1D<T> = Buffer1DWrapper(this)
/**
* Expose inner buffer of this [Structure1D] if possible
*/
internal fun <T : Any> Structure1D<T>.unwrap(): Buffer<T> = when {
this is Buffer1DWrapper<T> -> buffer
this is Structure1DWrapper && structure is NDBuffer<T> -> structure.buffer
else -> this
}

View File

@ -86,4 +86,9 @@ public fun <T> NDStructure<T>.as2D(): Structure2D<T> = this as? Structure2D<T> ?
else -> error("Can't create 2d-structure from ${shape.size}d-structure") else -> error("Can't create 2d-structure from ${shape.size}d-structure")
} }
internal fun <T> Structure2D<T>.unwrap(): NDStructure<T> = if (this is Structure2DWrapper) structure else this /**
* Expose inner [NDStructure] if possible
*/
internal fun <T> Structure2D<T>.unwrap(): NDStructure<T> =
if (this is Structure2DWrapper) structure
else this

View File

@ -44,21 +44,12 @@ public interface Buffer<out T> {
asSequence().mapIndexed { index, value -> value == other[index] }.all { it } asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
public companion object { public companion object {
/**
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
RealBuffer(size) { initializer(it) }
/** /**
* Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the * Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
* specified [initializer] function. * specified [initializer] function.
*/ */
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> = public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
ListBuffer(List(size, initializer)) List(size, initializer).asBuffer()
// TODO add resolution based on Annotation or companion resolution
/** /**
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer], * Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
@ -69,11 +60,11 @@ public interface Buffer<out T> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> = public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
when (type) { when (type) {
Double::class -> RealBuffer(size) { initializer(it) as Double } as Buffer<T> Double::class -> MutableBuffer.real(size) { initializer(it) as Double } as Buffer<T>
Short::class -> ShortBuffer(size) { initializer(it) as Short } as Buffer<T> Short::class -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer<T>
Int::class -> IntBuffer(size) { initializer(it) as Int } as Buffer<T> Int::class -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer<T>
Long::class -> LongBuffer(size) { initializer(it) as Long } as Buffer<T> Long::class -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer<T>
Float::class -> FloatBuffer(size) { initializer(it) as Float } as Buffer<T> Float::class -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer<T>
else -> boxing(size, initializer) else -> boxing(size, initializer)
} }
@ -89,41 +80,6 @@ public interface Buffer<out T> {
} }
} }
/**
* Creates a sequence that returns all elements from this [Buffer].
*/
public fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator)
/**
* Creates an iterable that returns all elements from this [Buffer].
*/
public fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator)
/**
* Returns a new [List] containing all elements of this buffer.
*/
public fun <T> Buffer<T>.toList(): List<T> = when (this) {
is ArrayBuffer<T> -> array.toList()
is ListBuffer<T> -> list.toList()
is MutableListBuffer<T> -> list.toList()
else -> asSequence().toList()
}
/**
* Returns a new [MutableList] filled with all elements of this buffer.
*/
public fun <T> Buffer<T>.toMutableList(): MutableList<T> = when (this) {
is ArrayBuffer<T> -> array.toMutableList()
is ListBuffer<T> -> list.toMutableList()
is MutableListBuffer<T> -> list.toMutableList()
else -> asSequence().toMutableList()
}
/**
* Returns a new [Array] containing all elements of this buffer.
*/
public inline fun <reified T> Buffer<T>.toTypedArray(): Array<T> = asSequence().toList().toTypedArray()
/** /**
* Returns an [IntRange] of the valid indices for this [Buffer]. * Returns an [IntRange] of the valid indices for this [Buffer].
*/ */
@ -146,6 +102,44 @@ public interface MutableBuffer<T> : Buffer<T> {
public fun copy(): MutableBuffer<T> public fun copy(): MutableBuffer<T>
public companion object { public companion object {
/**
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
RealBuffer(size, initializer)
/**
* Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer =
ShortBuffer(size, initializer)
/**
* Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer =
IntBuffer(size, initializer)
/**
* Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer =
LongBuffer(size, initializer)
/**
* Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer =
FloatBuffer(size, initializer)
/** /**
* Create a boxing mutable buffer of given type * Create a boxing mutable buffer of given type
*/ */
@ -161,11 +155,11 @@ public interface MutableBuffer<T> : Buffer<T> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> = public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
when (type) { when (type) {
Double::class -> RealBuffer(size) { initializer(it) as Double } as MutableBuffer<T> Double::class -> real(size) { initializer(it) as Double } as MutableBuffer<T>
Short::class -> ShortBuffer(size) { initializer(it) as Short } as MutableBuffer<T> Short::class -> short(size) { initializer(it) as Short } as MutableBuffer<T>
Int::class -> IntBuffer(size) { initializer(it) as Int } as MutableBuffer<T> Int::class -> int(size) { initializer(it) as Int } as MutableBuffer<T>
Float::class -> FloatBuffer(size) { initializer(it) as Float } as MutableBuffer<T> Float::class -> float(size) { initializer(it) as Float } as MutableBuffer<T>
Long::class -> LongBuffer(size) { initializer(it) as Long } as MutableBuffer<T> Long::class -> long(size) { initializer(it) as Long } as MutableBuffer<T>
else -> boxing(size, initializer) else -> boxing(size, initializer)
} }
@ -178,13 +172,6 @@ public interface MutableBuffer<T> : Buffer<T> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> = public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
auto(T::class, size, initializer) auto(T::class, size, initializer)
/**
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
* [initializer] function.
*/
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
RealBuffer(size) { initializer(it) }
} }
} }
@ -207,15 +194,6 @@ public inline class ListBuffer<T>(public val list: List<T>) : Buffer<T> {
*/ */
public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this) public fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this)
/**
* Creates a new [ListBuffer] with the specified [size], where each element is calculated by calling the specified
* [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an array element given its index.
*/
public inline fun <T> ListBuffer(size: Int, init: (Int) -> T): ListBuffer<T> = List(size, init).asBuffer()
/** /**
* [MutableBuffer] implementation over [MutableList]. * [MutableBuffer] implementation over [MutableList].
* *
@ -236,6 +214,11 @@ public inline class MutableListBuffer<T>(public val list: MutableList<T>) : Muta
override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list)) override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list))
} }
/**
* Returns an [ListBuffer] that wraps the original list.
*/
public fun <T> MutableList<T>.asMutableBuffer(): MutableListBuffer<T> = MutableListBuffer(this)
/** /**
* [MutableBuffer] implementation over [Array]. * [MutableBuffer] implementation over [Array].
* *
@ -244,8 +227,7 @@ public inline class MutableListBuffer<T>(public val list: MutableList<T>) : Muta
*/ */
public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> { public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
// Can't inline because array is invariant // Can't inline because array is invariant
override val size: Int override val size: Int get() = array.size
get() = array.size
override operator fun get(index: Int): T = array[index] override operator fun get(index: Int): T = array[index]
@ -263,16 +245,6 @@ public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
*/ */
public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this) public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
/**
* Creates a new [ArrayBuffer] with the specified [size], where each element is calculated by calling the specified
* [init] function.
*
* The function [init] is called for each array element sequentially starting from the first one.
* It should return the value for an array element given its index.
*/
public inline fun <reified T> ArrayBuffer(size: Int, init: (Int) -> T): ArrayBuffer<T> =
Array(size) { i -> init(i) }.asBuffer()
/** /**
* Immutable wrapper for [MutableBuffer]. * Immutable wrapper for [MutableBuffer].
* *
@ -313,14 +285,4 @@ public class VirtualBuffer<T>(override val size: Int, private val generator: (In
/** /**
* Convert this buffer to read-only buffer. * Convert this buffer to read-only buffer.
*/ */
public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this public fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
/**
* Typealias for buffer transformations.
*/
public typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
/**
* Typealias for buffer transformations with suspend function.
*/
public typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>

View File

@ -1,7 +1,84 @@
package space.kscience.kmath.structures package space.kscience.kmath.structures
import space.kscience.kmath.misc.UnstableKMathAPI
/**
* Typealias for buffer transformations.
*/
public typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
/**
* Typealias for buffer transformations with suspend function.
*/
public typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>
/**
* Creates a sequence that returns all elements from this [Buffer].
*/
public fun <T> Buffer<T>.asSequence(): Sequence<T> = Sequence(::iterator)
/**
* Creates an iterable that returns all elements from this [Buffer].
*/
public fun <T> Buffer<T>.asIterable(): Iterable<T> = Iterable(::iterator)
/**
* Returns a new [List] containing all elements of this buffer.
*/
public fun <T> Buffer<T>.toList(): List<T> = when (this) {
is ArrayBuffer<T> -> array.toList()
is ListBuffer<T> -> list.toList()
is MutableListBuffer<T> -> list.toList()
else -> asSequence().toList()
}
/**
* Returns a new [MutableList] filled with all elements of this buffer.
* **NOTE:** this method uses a protective copy, so it should not be used in performance-critical code.
*/
@UnstableKMathAPI
public fun <T> Buffer<T>.toMutableList(): MutableList<T> = when (this) {
is ArrayBuffer<T> -> array.toMutableList()
is ListBuffer<T> -> list.toMutableList()
is MutableListBuffer<T> -> list.toMutableList()
else -> MutableList(size, ::get)
}
/**
* Returns a new [Array] containing all elements of this buffer.
* **NOTE:** this method uses a protective copy, so it should not be used in performance-critical code.
*/
@UnstableKMathAPI
public inline fun <reified T> Buffer<T>.toTypedArray(): Array<T> = Array(size, ::get)
/**
* Create a new buffer from this one with the given mapping function.
* Provided [BufferFactory] is used to construct the new buffer.
*/
public inline fun <T : Any, reified R : Any> Buffer<T>.map( public inline fun <T : Any, reified R : Any> Buffer<T>.map(
bufferFactory: BufferFactory<R> = Buffer.Companion::auto, bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
crossinline block: (T) -> R, crossinline block: (T) -> R,
): Buffer<R> = bufferFactory(size) { block(get(it)) } ): Buffer<R> = bufferFactory(size) { block(get(it)) }
/**
* Create a new buffer from this one with the given indexed mapping function.
* Provided [BufferFactory] is used to construct the new buffer.
*/
public inline fun <T : Any, reified R : Any> Buffer<T>.mapIndexed(
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
crossinline block: (index: Int, value: T) -> R,
): Buffer<R> = bufferFactory(size) { block(it, get(it)) }
/**
* Zip two buffers using given [transform].
*/
@UnstableKMathAPI
public inline fun <T1 : Any, T2 : Any, reified R : Any> Buffer<T1>.zip(
other: Buffer<T2>,
bufferFactory: BufferFactory<R> = Buffer.Companion::auto,
crossinline transform: (T1, T2) -> R,
): Buffer<R> {
require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" }
return bufferFactory(size) { transform(get(it), other[it]) }
}

View File

@ -1,8 +1,10 @@
package space.kscience.kmath.real package space.kscience.kmath.real
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
import space.kscience.kmath.misc.UnstableKMathAPI
import space.kscience.kmath.operations.Norm import space.kscience.kmath.operations.Norm
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.MutableBuffer.Companion.real
import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.asBuffer
import space.kscience.kmath.structures.asIterable import space.kscience.kmath.structures.asIterable
import space.kscience.kmath.structures.indices import space.kscience.kmath.structures.indices
@ -20,15 +22,16 @@ public operator fun Buffer.Companion.invoke(vararg doubles: Double): RealVector
/** /**
* Fill the vector of given [size] with given [value] * Fill the vector of given [size] with given [value]
*/ */
@UnstableKMathAPI
public fun Buffer.Companion.same(size: Int, value: Number): RealVector = real(size) { value.toDouble() } public fun Buffer.Companion.same(size: Int, value: Number): RealVector = real(size) { value.toDouble() }
// Transformation methods // Transformation methods
public inline fun RealVector.map(transform: (Double) -> Double): RealVector = public inline fun RealVector.map(transform: (Double) -> Double): RealVector =
Buffer.real(size) { transform(get(it)) } real(size) { transform(get(it)) }
public inline fun RealVector.mapIndexed(transform: (index: Int, value: Double) -> Double): RealVector = public inline fun RealVector.mapIndexed(transform: (index: Int, value: Double) -> Double): RealVector =
Buffer.real(size) { transform(it, get(it)) } real(size) { transform(it, get(it)) }
public operator fun RealVector.plus(other: RealVector): RealVector { public operator fun RealVector.plus(other: RealVector): RealVector {
require(size == other.size) { "Vector size $size expected but ${other.size} found" } require(size == other.size) { "Vector size $size expected but ${other.size} found" }

View File

@ -4,30 +4,30 @@ import space.kscience.kmath.linear.LinearSpace
import space.kscience.kmath.linear.asMatrix import space.kscience.kmath.linear.asMatrix
import space.kscience.kmath.linear.transpose import space.kscience.kmath.linear.transpose
import space.kscience.kmath.real.plus import space.kscience.kmath.real.plus
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.RealBuffer
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
internal class RealVectorTest { internal class RealVectorTest {
@Test @Test
fun testSum() { fun testSum() {
val vector1 = Buffer.real(5) { it.toDouble() } val vector1 = RealBuffer(5) { it.toDouble() }
val vector2 = Buffer.real(5) { 5 - it.toDouble() } val vector2 = RealBuffer(5) { 5 - it.toDouble() }
val sum = vector1 + vector2 val sum = vector1 + vector2
assertEquals(5.0, sum[2]) assertEquals(5.0, sum[2])
} }
@Test @Test
fun testVectorToMatrix() { fun testVectorToMatrix() {
val vector = Buffer.real(5) { it.toDouble() } val vector = RealBuffer(5) { it.toDouble() }
val matrix = vector.asMatrix() val matrix = vector.asMatrix()
assertEquals(4.0, matrix[4, 0]) assertEquals(4.0, matrix[4, 0])
} }
@Test @Test
fun testDot() { fun testDot() {
val vector1 = Buffer.real(5) { it.toDouble() } val vector1 = RealBuffer(5) { it.toDouble() }
val vector2 = Buffer.real(5) { 5 - it.toDouble() } val vector2 = RealBuffer(5) { 5 - it.toDouble() }
val matrix1 = vector1.asMatrix() val matrix1 = vector1.asMatrix()
val matrix2 = vector2.asMatrix().transpose() val matrix2 = vector2.asMatrix().transpose()
val product = LinearSpace.real.run { matrix1 dot matrix2 } val product = LinearSpace.real.run { matrix1 dot matrix2 }

View File

@ -2,8 +2,8 @@ package space.kscience.kmath.histogram
import space.kscience.kmath.domains.Domain import space.kscience.kmath.domains.Domain
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
import space.kscience.kmath.structures.ArrayBuffer
import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.RealBuffer
import space.kscience.kmath.structures.asBuffer
/** /**
* The binned data element. Could be a histogram bin with a number of counts or an artificial construct * The binned data element. Could be a histogram bin with a number of counts or an artificial construct
@ -40,7 +40,7 @@ public fun interface HistogramBuilder<T : Any> {
public fun <T : Any, B : Bin<T>> HistogramBuilder<T>.put(point: Point<out T>): Unit = putValue(point, 1.0) public fun <T : Any, B : Bin<T>> HistogramBuilder<T>.put(point: Point<out T>): Unit = putValue(point, 1.0)
public fun <T : Any> HistogramBuilder<T>.put(vararg point: T): Unit = put(ArrayBuffer(point)) public fun <T : Any> HistogramBuilder<T>.put(vararg point: T): Unit = put(point.asBuffer())
public fun HistogramBuilder<Double>.put(vararg point: Number): Unit = public fun HistogramBuilder<Double>.put(vararg point: Number): Unit =
put(RealBuffer(point.map { it.toDouble() }.toDoubleArray())) put(RealBuffer(point.map { it.toDouble() }.toDoubleArray()))

View File

@ -4,6 +4,7 @@ import space.kscience.kmath.chains.Chain
import space.kscience.kmath.chains.collect import space.kscience.kmath.chains.collect
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.BufferFactory
import space.kscience.kmath.structures.RealBuffer
public interface Sampler<T : Any> { public interface Sampler<T : Any> {
public fun sample(generator: RandomGenerator): Chain<T> public fun sample(generator: RandomGenerator): Chain<T>
@ -74,4 +75,4 @@ public fun <T : Any> Sampler<T>.sampleBuffer(
* Generate a bunch of samples from real distributions * Generate a bunch of samples from real distributions
*/ */
public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> = public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> =
sampleBuffer(generator, size, Buffer.Companion::real) sampleBuffer(generator, size, ::RealBuffer)