Update buffers documentation, make API more consistent, minor changes

This commit is contained in:
Iaroslav 2020-08-07 15:20:26 +07:00
parent 9f6bd116f6
commit 0a8044ddb3
No known key found for this signature in database
GPG Key ID: 46E15E4A31B3BCD7
12 changed files with 227 additions and 27 deletions

View File

@ -5,19 +5,19 @@ import scientifik.kmath.operations.Ring
import scientifik.kmath.operations.Space import scientifik.kmath.operations.Space
/** /**
* Create a functional expression on this [Space] * Creates a functional expression with this [Space].
*/ */
fun <T> Space<T>.spaceExpression(block: FunctionalExpressionSpace<T, Space<T>>.() -> Expression<T>): Expression<T> = fun <T> Space<T>.spaceExpression(block: FunctionalExpressionSpace<T, Space<T>>.() -> Expression<T>): Expression<T> =
FunctionalExpressionSpace(this).run(block) FunctionalExpressionSpace(this).run(block)
/** /**
* Create a functional expression on this [Ring] * Creates a functional expression with this [Ring].
*/ */
fun <T> Ring<T>.ringExpression(block: FunctionalExpressionRing<T, Ring<T>>.() -> Expression<T>): Expression<T> = fun <T> Ring<T>.ringExpression(block: FunctionalExpressionRing<T, Ring<T>>.() -> Expression<T>): Expression<T> =
FunctionalExpressionRing(this).run(block) FunctionalExpressionRing(this).run(block)
/** /**
* Create a functional expression on this [Field] * Creates a functional expression with this [Field].
*/ */
fun <T> Field<T>.fieldExpression(block: FunctionalExpressionField<T, Field<T>>.() -> Expression<T>): Expression<T> = fun <T> Field<T>.fieldExpression(block: FunctionalExpressionField<T, Field<T>>.() -> Expression<T>): Expression<T> =
FunctionalExpressionField(this).run(block) FunctionalExpressionField(this).run(block)

View File

@ -12,8 +12,21 @@ interface MathElement<C> {
val context: C val context: C
} }
/**
* Represents element that can be wrapped to its "primitive" value.
*
* @param T the type wrapped by this wrapper.
* @param I the type of this wrapper.
*/
interface MathWrapper<T, I> { interface MathWrapper<T, I> {
/**
* Unwraps [I] to [T].
*/
fun unwrap(): T fun unwrap(): T
/**
* Wraps [T] to [I].
*/
fun T.wrap(): I fun T.wrap(): I
} }

View File

@ -19,10 +19,11 @@ typealias BufferFactory<T> = (Int, (Int) -> T) -> Buffer<T>
typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T> typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
/** /**
* A generic random-access structure for both primitives and objects. * A generic immutable random-access structure for both primitives and objects.
*
* @param T the type of elements contained in the buffer.
*/ */
interface Buffer<T> { interface Buffer<T> {
/** /**
* The size of this buffer. * The size of this buffer.
*/ */
@ -45,7 +46,6 @@ interface Buffer<T> {
asSequence().mapIndexed { index, value -> value == other[index] }.all { it } asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
companion object { companion object {
inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer { inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer {
val array = DoubleArray(size) { initializer(it) } val array = DoubleArray(size) { initializer(it) }
return RealBuffer(array) return RealBuffer(array)
@ -95,6 +95,8 @@ val Buffer<*>.indices: IntRange get() = 0 until size
/** /**
* A generic mutable random-access structure for both primitives and objects. * A generic mutable random-access structure for both primitives and objects.
*
* @param T the type of elements contained in the buffer.
*/ */
interface MutableBuffer<T> : Buffer<T> { interface MutableBuffer<T> : Buffer<T> {
/** /**
@ -138,8 +140,13 @@ interface MutableBuffer<T> : Buffer<T> {
} }
} }
/**
* [Buffer] implementation over [List].
*
* @param T the type of elements contained in the buffer.
* @property list The underlying list.
*/
inline class ListBuffer<T>(val list: List<T>) : Buffer<T> { inline class ListBuffer<T>(val list: List<T>) : Buffer<T> {
override val size: Int override val size: Int
get() = list.size get() = list.size
@ -148,10 +155,26 @@ inline class ListBuffer<T>(val list: List<T>) : Buffer<T> {
override fun iterator(): Iterator<T> = list.iterator() override fun iterator(): Iterator<T> = list.iterator()
} }
/**
* Returns an [ListBuffer] that wraps the original list.
*/
fun <T> List<T>.asBuffer(): ListBuffer<T> = ListBuffer(this) 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.
*/
inline fun <T> ListBuffer(size: Int, init: (Int) -> T): ListBuffer<T> = List(size, init).asBuffer() inline fun <T> ListBuffer(size: Int, init: (Int) -> T): ListBuffer<T> = List(size, init).asBuffer()
/**
* [MutableBuffer] implementation over [MutableList].
*
* @param T the type of elements contained in the buffer.
* @property list The underlying list.
*/
inline class MutableListBuffer<T>(val list: MutableList<T>) : MutableBuffer<T> { inline class MutableListBuffer<T>(val list: MutableList<T>) : MutableBuffer<T> {
override val size: Int override val size: Int
@ -167,6 +190,12 @@ inline class MutableListBuffer<T>(val list: MutableList<T>) : MutableBuffer<T> {
override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list)) override fun copy(): MutableBuffer<T> = MutableListBuffer(ArrayList(list))
} }
/**
* [MutableBuffer] implementation over [Array].
*
* @param T the type of elements contained in the buffer.
* @property array The underlying array.
*/
class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> { class ArrayBuffer<T>(private 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
@ -183,8 +212,17 @@ class ArrayBuffer<T>(private val array: Array<T>) : MutableBuffer<T> {
override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf()) override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf())
} }
/**
* Returns an [ArrayBuffer] that wraps the original array.
*/
fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this) fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
/**
* Immutable wrapper for [MutableBuffer].
*
* @param T the type of elements contained in the buffer.
* @property buffer The underlying buffer.
*/
inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> { inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> {
override val size: Int get() = buffer.size override val size: Int get() = buffer.size
@ -196,6 +234,8 @@ inline class ReadOnlyBuffer<T>(val buffer: MutableBuffer<T>) : Buffer<T> {
/** /**
* A buffer with content calculated on-demand. The calculated content is not stored, so it is recalculated on each call. * A buffer with content calculated on-demand. The calculated content is not stored, so it is recalculated on each call.
* Useful when one needs single element from the buffer. * Useful when one needs single element from the buffer.
*
* @param T the type of elements provided by the buffer.
*/ */
class VirtualBuffer<T>(override val size: Int, private val generator: (Int) -> T) : Buffer<T> { class VirtualBuffer<T>(override val size: Int, private val generator: (Int) -> T) : Buffer<T> {
override fun get(index: Int): T { override fun get(index: Int): T {
@ -215,17 +255,16 @@ class VirtualBuffer<T>(override val size: Int, private val generator: (Int) -> T
} }
/** /**
* Convert this buffer to read-only buffer * Convert this buffer to read-only buffer.
*/ */
fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) { fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) ReadOnlyBuffer(this) else this
ReadOnlyBuffer(this)
} else {
this
}
/** /**
* Typealias for buffer transformations * Typealias for buffer transformations.
*/ */
typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R> typealias BufferTransform<T, R> = (Buffer<T>) -> Buffer<R>
/**
* Typealias for buffer transformations with suspend function.
*/
typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R> typealias SuspendBufferTransform<T, R> = suspend (Buffer<T>) -> Buffer<R>

View File

@ -2,15 +2,35 @@ package scientifik.kmath.structures
import kotlin.experimental.and import kotlin.experimental.and
/**
* Represents flags to supply additional info about values of buffer.
*
* @property mask bit mask value of this flag.
*/
enum class ValueFlag(val mask: Byte) { enum class ValueFlag(val mask: Byte) {
/**
* Reports the value is NaN.
*/
NAN(0b0000_0001), NAN(0b0000_0001),
/**
* Reports the value doesn't present in the buffer (when the type of value doesn't support `null`).
*/
MISSING(0b0000_0010), MISSING(0b0000_0010),
/**
* Reports the value is negative infinity.
*/
NEGATIVE_INFINITY(0b0000_0100), NEGATIVE_INFINITY(0b0000_0100),
/**
* Reports the value is positive infinity
*/
POSITIVE_INFINITY(0b0000_1000) POSITIVE_INFINITY(0b0000_1000)
} }
/** /**
* A buffer with flagged values * A buffer with flagged values.
*/ */
interface FlaggedBuffer<T> : Buffer<T> { interface FlaggedBuffer<T> : Buffer<T> {
fun getFlag(index: Int): Byte fun getFlag(index: Int): Byte

View File

@ -0,0 +1,49 @@
package scientifik.kmath.structures
/**
* Specialized [MutableBuffer] implementation over [FloatArray].
*
* @property array the underlying array.
*/
inline class FloatBuffer(val array: FloatArray) : MutableBuffer<Float> {
override val size: Int get() = array.size
override fun get(index: Int): Float = array[index]
override fun set(index: Int, value: Float) {
array[index] = value
}
override fun iterator(): FloatIterator = array.iterator()
override fun copy(): MutableBuffer<Float> =
FloatBuffer(array.copyOf())
}
/**
* Creates a new [FloatBuffer] 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 buffer element given its index.
*/
inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) })
/**
* Returns a new [FloatBuffer] of given elements.
*/
fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats)
/**
* Returns a [FloatArray] containing all of the elements of this [MutableBuffer].
*/
val MutableBuffer<out Float>.array: FloatArray
get() = (if (this is FloatBuffer) array else FloatArray(size) { get(it) })
/**
* Returns [FloatBuffer] over this array.
*
* @receiver the array.
* @return the new buffer.
*/
fun FloatArray.asBuffer(): FloatBuffer = FloatBuffer(this)

View File

@ -26,15 +26,13 @@ inline class IntBuffer(val array: IntArray) : MutableBuffer<Int> {
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * 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. * It should return the value for an buffer element given its index.
*/ */
@Suppress("FunctionName")
inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) }) inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) })
/** /**
* Returns a new [IntBuffer] of given elements. * Returns a new [IntBuffer] of given elements.
*/ */
@Suppress("FunctionName")
fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints)
/** /**

View File

@ -1,5 +1,10 @@
package scientifik.kmath.structures package scientifik.kmath.structures
/**
* Specialized [MutableBuffer] implementation over [LongArray].
*
* @property array the underlying array.
*/
inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> { inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> {
override val size: Int get() = array.size override val size: Int get() = array.size
@ -16,4 +21,30 @@ inline class LongBuffer(val array: LongArray) : MutableBuffer<Long> {
} }
/**
* Creates a new [LongBuffer] 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 buffer element given its index.
*/
inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongBuffer(LongArray(size) { init(it) })
/**
* Returns a new [LongBuffer] of given elements.
*/
fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs)
/**
* Returns a [IntArray] containing all of the elements of this [MutableBuffer].
*/
val MutableBuffer<out Long>.array: LongArray
get() = (if (this is LongBuffer) array else LongArray(size) { get(it) })
/**
* Returns [LongBuffer] over this array.
*
* @receiver the array.
* @return the new buffer.
*/
fun LongArray.asBuffer(): LongBuffer = LongBuffer(this) fun LongArray.asBuffer(): LongBuffer = LongBuffer(this)

View File

@ -4,12 +4,16 @@ import scientifik.memory.*
/** /**
* A non-boxing buffer over [Memory] object. * A non-boxing buffer over [Memory] object.
*
* @param T the type of elements contained in the buffer.
* @property memory the underlying memory segment.
* @property spec the spec of [T] type.
*/ */
open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> { open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
override val size: Int get() = memory.size / spec.objectSize override val size: Int get() = memory.size / spec.objectSize
private val reader = memory.reader() private val reader: MemoryReader = memory.reader()
override fun get(index: Int): T = reader.read(spec, spec.objectSize * index) override fun get(index: Int): T = reader.read(spec, spec.objectSize * index)
@ -33,6 +37,13 @@ open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spe
} }
} }
/**
* A mutable non-boxing buffer over [Memory] object.
*
* @param T the type of elements contained in the buffer.
* @property memory the underlying memory segment.
* @property spec the spec of [T] type.
*/
class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : MemoryBuffer<T>(memory, spec), class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : MemoryBuffer<T>(memory, spec),
MutableBuffer<T> { MutableBuffer<T> {

View File

@ -107,8 +107,8 @@ interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N>
/** /**
* Field for n-dimensional structures. * Field for n-dimensional structures.
* *
* @param T - the type of the element contained in ND structure * @param T the type of the element contained in ND structure
* @param F - field of structure elements * @param F field of structure elements
*/ */
interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> { interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> {

View File

@ -1,5 +1,10 @@
package scientifik.kmath.structures package scientifik.kmath.structures
/**
* Specialized [MutableBuffer] implementation over [DoubleArray].
*
* @property array the underlying array.
*/
inline class RealBuffer(val array: DoubleArray) : MutableBuffer<Double> { inline class RealBuffer(val array: DoubleArray) : MutableBuffer<Double> {
override val size: Int get() = array.size override val size: Int get() = array.size
@ -16,19 +21,17 @@ inline class RealBuffer(val array: DoubleArray) : MutableBuffer<Double> {
} }
/** /**
* Creates a new array with the specified [size], where each element is calculated by calling the specified * Creates a new [RealBuffer] with the specified [size], where each element is calculated by calling the specified
* [init] function. * [init] function.
* *
* The function [init] is called for each array element sequentially starting from the first one. * 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. * It should return the value for an buffer element given its index.
*/ */
@Suppress("FunctionName")
inline fun RealBuffer(size: Int, init: (Int) -> Double): RealBuffer = RealBuffer(DoubleArray(size) { init(it) }) inline fun RealBuffer(size: Int, init: (Int) -> Double): RealBuffer = RealBuffer(DoubleArray(size) { init(it) })
/** /**
* Returns a new [RealBuffer] of given elements. * Returns a new [RealBuffer] of given elements.
*/ */
@Suppress("FunctionName")
fun RealBuffer(vararg doubles: Double): RealBuffer = RealBuffer(doubles) fun RealBuffer(vararg doubles: Double): RealBuffer = RealBuffer(doubles)
/** /**

View File

@ -6,7 +6,7 @@ import kotlin.math.*
/** /**
* A simple field over linear buffers of [Double] * [ExtendedFieldOperations] over [RealBuffer].
*/ */
object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> { object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer { override fun add(a: Buffer<Double>, b: Buffer<Double>): RealBuffer {
@ -109,6 +109,11 @@ object RealBufferFieldOperations : ExtendedFieldOperations<Buffer<Double>> {
RealBuffer(DoubleArray(arg.size) { ln(arg[it]) }) RealBuffer(DoubleArray(arg.size) { ln(arg[it]) })
} }
/**
* [ExtendedField] over [RealBuffer].
*
* @property size the size of buffers to operate on.
*/
class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> { class RealBufferField(val size: Int) : ExtendedField<Buffer<Double>> {
override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } } override val zero: Buffer<Double> by lazy { RealBuffer(size) { 0.0 } }
override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } } override val one: Buffer<Double> by lazy { RealBuffer(size) { 1.0 } }

View File

@ -1,5 +1,10 @@
package scientifik.kmath.structures package scientifik.kmath.structures
/**
* Specialized [MutableBuffer] implementation over [ShortBuffer].
*
* @property array the underlying array.
*/
inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> { inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> {
override val size: Int get() = array.size override val size: Int get() = array.size
@ -16,4 +21,30 @@ inline class ShortBuffer(val array: ShortArray) : MutableBuffer<Short> {
} }
/**
* Creates a new [ShortBuffer] 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 buffer element given its index.
*/
inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) })
/**
* Returns a new [ShortBuffer] of given elements.
*/
fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts)
/**
* Returns a [ShortArray] containing all of the elements of this [MutableBuffer].
*/
val MutableBuffer<out Short>.array: ShortArray
get() = (if (this is ShortBuffer) array else ShortArray(size) { get(it) })
/**
* Returns [ShortBuffer] over this array.
*
* @receiver the array.
* @return the new buffer.
*/
fun ShortArray.asBuffer(): ShortBuffer = ShortBuffer(this) fun ShortArray.asBuffer(): ShortBuffer = ShortBuffer(this)