forked from kscience/kmath
Adjustments to RealNDField
This commit is contained in:
parent
334dadc6bf
commit
b47cdd12c2
@ -0,0 +1,42 @@
|
|||||||
|
package scientifik.kmath.structures
|
||||||
|
|
||||||
|
import scientifik.kmath.operations.DoubleField
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val dim = 1000
|
||||||
|
val n = 1000
|
||||||
|
|
||||||
|
val genericField = NDField.generic(intArrayOf(dim, dim), DoubleField)
|
||||||
|
val doubleField = NDField.inline(intArrayOf(dim, dim), DoubleField)
|
||||||
|
val specializedField = NDField.real(intArrayOf(dim, dim))
|
||||||
|
|
||||||
|
|
||||||
|
val doubleTime = measureTimeMillis {
|
||||||
|
var res = doubleField.produce { one }
|
||||||
|
repeat(n) {
|
||||||
|
res += 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Inlined addition completed in $doubleTime millis")
|
||||||
|
|
||||||
|
val specializedTime = measureTimeMillis {
|
||||||
|
var res = specializedField.produce { one }
|
||||||
|
repeat(n) {
|
||||||
|
res += 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Specialized addition completed in $specializedTime millis")
|
||||||
|
|
||||||
|
|
||||||
|
val genericTime = measureTimeMillis {
|
||||||
|
var res = genericField.produce { one }
|
||||||
|
repeat(n) {
|
||||||
|
res += 1.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Generic addition completed in $genericTime millis")
|
||||||
|
}
|
@ -2,15 +2,36 @@ package scientifik.kmath.structures
|
|||||||
|
|
||||||
import scientifik.kmath.operations.Field
|
import scientifik.kmath.operations.Field
|
||||||
|
|
||||||
class BufferNDField<T : Any, F : Field<T>>(override val shape: IntArray, override val field: F, val bufferFactory: BufferFactory<T>) : NDField<T, F> {
|
open class BufferNDField<T, F : Field<T>>(final override val shape: IntArray, final override val field: F, val bufferFactory: BufferFactory<T>) : NDField<T, F> {
|
||||||
val strides = DefaultStrides(shape)
|
val strides = DefaultStrides(shape)
|
||||||
|
|
||||||
override inline fun produce(crossinline initializer: F.(IntArray) -> T): NDElement<T, F> {
|
override fun produce(initializer: F.(IntArray) -> T): BufferNDElement<T, F> {
|
||||||
return BufferNDElement(this, bufferFactory(strides.linearSize) { offset -> field.initializer(strides.index(offset)) })
|
return BufferNDElement(this, bufferFactory(strides.linearSize) { offset -> field.initializer(strides.index(offset)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun produceBuffered(initializer: F.(Int) -> T) =
|
||||||
|
BufferNDElement(this, bufferFactory(strides.linearSize) { offset -> field.initializer(offset) })
|
||||||
|
|
||||||
|
// override fun add(a: NDStructure<T>, b: NDStructure<T>): NDElement<T, F> {
|
||||||
|
// checkShape(a, b)
|
||||||
|
// return if (a is BufferNDElement<T, *> && b is BufferNDElement<T, *>) {
|
||||||
|
// BufferNDElement(this,bufferFactory(strides.linearSize){i-> field.run { a.buffer[i] + b.buffer[i]}})
|
||||||
|
// } else {
|
||||||
|
// produce { field.run { a[it] + b[it] } }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun NDStructure<T>.plus(b: Number): NDElement<T,F> {
|
||||||
|
// checkShape(this)
|
||||||
|
// return if (this is BufferNDElement<T, *>) {
|
||||||
|
// BufferNDElement(this@BufferNDField,bufferFactory(strides.linearSize){i-> field.run { this@plus.buffer[i] + b}})
|
||||||
|
// } else {
|
||||||
|
// produce {index -> field.run { this@plus[index] + b } }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
class BufferNDElement<T : Any, F : Field<T>>(override val context: BufferNDField<T, F>, private val buffer: Buffer<T>) : NDElement<T, F> {
|
class BufferNDElement<T, F : Field<T>>(override val context: BufferNDField<T, F>, val buffer: Buffer<T>) : NDElement<T, F> {
|
||||||
|
|
||||||
override val self: NDStructure<T> get() = this
|
override val self: NDStructure<T> get() = this
|
||||||
override val shape: IntArray get() = context.shape
|
override val shape: IntArray get() = context.shape
|
||||||
@ -20,3 +41,38 @@ class BufferNDElement<T : Any, F : Field<T>>(override val context: BufferNDField
|
|||||||
override fun elements(): Sequence<Pair<IntArray, T>> = context.strides.indices().map { it to get(it) }
|
override fun elements(): Sequence<Pair<IntArray, T>> = context.strides.indices().map { it to get(it) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element by element application of any operation on elements to the whole array. Just like in numpy
|
||||||
|
*/
|
||||||
|
operator fun <T : Any, F : Field<T>> Function1<T, T>.invoke(ndElement: BufferNDElement<T, F>) =
|
||||||
|
ndElement.context.produceBuffered { i -> invoke(ndElement.buffer[i]) }
|
||||||
|
|
||||||
|
/* plus and minus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summation operation for [BufferNDElement] and single element
|
||||||
|
*/
|
||||||
|
operator fun <T : Any, F : Field<T>> BufferNDElement<T, F>.plus(arg: T) =
|
||||||
|
context.produceBuffered { i -> buffer[i] + arg }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtraction operation between [BufferNDElement] and single element
|
||||||
|
*/
|
||||||
|
operator fun <T: Any, F : Field<T>> BufferNDElement<T, F>.minus(arg: T) =
|
||||||
|
context.produceBuffered { i -> buffer[i] - arg }
|
||||||
|
|
||||||
|
/* prod and div */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product operation for [BufferNDElement] and single element
|
||||||
|
*/
|
||||||
|
operator fun <T: Any, F : Field<T>> BufferNDElement<T, F>.times(arg: T) =
|
||||||
|
context.produceBuffered { i -> buffer[i] * arg }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Division operation between [BufferNDElement] and single element
|
||||||
|
*/
|
||||||
|
operator fun <T: Any, F : Field<T>> BufferNDElement<T, F>.div(arg: T) =
|
||||||
|
context.produceBuffered { i -> buffer[i] / arg }
|
@ -133,13 +133,13 @@ fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) {
|
|||||||
/**
|
/**
|
||||||
* Create a boxing buffer of given type
|
* Create a boxing buffer of given type
|
||||||
*/
|
*/
|
||||||
fun <T : Any> boxingBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = ListBuffer(List(size, initializer))
|
inline fun <T> boxingBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = ListBuffer(List(size, initializer))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create most appropriate immutable buffer for given type avoiding boxing wherever possible
|
* Create most appropriate immutable buffer for given type avoiding boxing wherever possible
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
inline fun <reified T : Any> inlineBuffer(size: Int, noinline initializer: (Int) -> T): Buffer<T> {
|
inline fun <reified T : Any> inlineBuffer(size: Int, initializer: (Int) -> T): Buffer<T> {
|
||||||
return when (T::class) {
|
return when (T::class) {
|
||||||
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
|
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
|
||||||
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T>
|
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T>
|
||||||
@ -151,13 +151,13 @@ inline fun <reified T : Any> inlineBuffer(size: Int, noinline initializer: (Int)
|
|||||||
/**
|
/**
|
||||||
* Create a boxing mutable buffer of given type
|
* Create a boxing mutable buffer of given type
|
||||||
*/
|
*/
|
||||||
fun <T : Any> boxingMutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> = MutableListBuffer(MutableList(size, initializer))
|
inline fun <T : Any> boxingMutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> = MutableListBuffer(MutableList(size, initializer))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create most appropriate mutable buffer for given type avoiding boxing wherever possible
|
* Create most appropriate mutable buffer for given type avoiding boxing wherever possible
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
inline fun <reified T : Any> inlineMutableBuffer(size: Int, noinline initializer: (Int) -> T): MutableBuffer<T> {
|
inline fun <reified T : Any> inlineMutableBuffer(size: Int, initializer: (Int) -> T): MutableBuffer<T> {
|
||||||
return when (T::class) {
|
return when (T::class) {
|
||||||
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer<T>
|
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer<T>
|
||||||
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer<T>
|
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer<T>
|
||||||
|
@ -6,13 +6,17 @@ import scientifik.kmath.operations.PowerOperations
|
|||||||
import scientifik.kmath.operations.TrigonometricOperations
|
import scientifik.kmath.operations.TrigonometricOperations
|
||||||
|
|
||||||
|
|
||||||
|
interface ExtendedNDField<T : Any, F : ExtendedField<T>> :
|
||||||
|
NDField<T, F>,
|
||||||
|
TrigonometricOperations<NDStructure<T>>,
|
||||||
|
PowerOperations<NDStructure<T>>,
|
||||||
|
ExponentialOperations<NDStructure<T>>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NDField that supports [ExtendedField] operations on its elements
|
* NDField that supports [ExtendedField] operations on its elements
|
||||||
*/
|
*/
|
||||||
inline class ExtendedNDField<T : Any, F : ExtendedField<T>>(private val ndField: NDField<T, F>) : NDField<T, F>,
|
inline class ExtendedNDFieldWrapper<T : Any, F : ExtendedField<T>>(private val ndField: NDField<T, F>) : ExtendedNDField<T, F> {
|
||||||
TrigonometricOperations<NDStructure<T>>,
|
|
||||||
PowerOperations<NDStructure<T>>,
|
|
||||||
ExponentialOperations<NDStructure<T>> {
|
|
||||||
|
|
||||||
override val shape: IntArray get() = ndField.shape
|
override val shape: IntArray get() = ndField.shape
|
||||||
override val field: F get() = ndField.field
|
override val field: F get() = ndField.field
|
||||||
|
@ -73,12 +73,11 @@ interface NDField<T, F : Field<T>> : Field<NDStructure<T>> {
|
|||||||
return produce { field.run { a[it] / b[it] } }
|
return produce { field.run { a[it] / b[it] } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
* Create a nd-field for [Double] values
|
* Create a nd-field for [Double] values
|
||||||
*/
|
*/
|
||||||
fun real(shape: IntArray) = ExtendedNDField(BufferNDField(shape, DoubleField, DoubleBufferFactory))
|
fun real(shape: IntArray) = RealNDField(shape)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a nd-field with boxing generic buffer
|
* Create a nd-field with boxing generic buffer
|
||||||
@ -123,11 +122,11 @@ interface NDElement<T, F : Field<T>> : FieldElement<NDStructure<T>, NDField<T, F
|
|||||||
* Simple boxing NDArray
|
* Simple boxing NDArray
|
||||||
*/
|
*/
|
||||||
fun <T : Any, F : Field<T>> generic(shape: IntArray, field: F, initializer: F.(IntArray) -> T): NDElement<T, F> {
|
fun <T : Any, F : Field<T>> generic(shape: IntArray, field: F, initializer: F.(IntArray) -> T): NDElement<T, F> {
|
||||||
return NDField.generic(shape,field).produce(initializer)
|
return NDField.generic(shape, field).produce(initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Any, F : Field<T>> inline(shape: IntArray, field: F, crossinline initializer: F.(IntArray) -> T): NDElement<T, F> {
|
inline fun <reified T : Any, F : Field<T>> inline(shape: IntArray, field: F, noinline initializer: F.(IntArray) -> T): NDElement<T, F> {
|
||||||
return NDField.inline(shape,field).produce(initializer)
|
return NDField.inline(shape, field).produce(initializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package scientifik.kmath.structures
|
||||||
|
|
||||||
|
import scientifik.kmath.operations.DoubleField
|
||||||
|
|
||||||
|
typealias RealNDElement = BufferNDElement<Double, DoubleField>
|
||||||
|
|
||||||
|
class RealNDField(shape: IntArray) : BufferNDField<Double, DoubleField>(shape, DoubleField, DoubleBufferFactory), ExtendedNDField<Double, DoubleField> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inline map an NDStructure to
|
||||||
|
*/
|
||||||
|
private inline fun NDStructure<Double>.mapInline(crossinline operation: DoubleField.(Double) -> Double): RealNDElement {
|
||||||
|
return if (this is BufferNDElement<Double, *>) {
|
||||||
|
val array = DoubleArray(strides.linearSize) { offset -> DoubleField.operation(buffer[offset]) }
|
||||||
|
BufferNDElement(this@RealNDField, DoubleBuffer(array))
|
||||||
|
} else {
|
||||||
|
produce { index -> DoubleField.operation(get(index)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Suppress("OVERRIDE_BY_INLINE")
|
||||||
|
override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement {
|
||||||
|
val array = DoubleArray(strides.linearSize) { offset -> field.initializer(strides.index(offset)) }
|
||||||
|
return BufferNDElement(this, DoubleBuffer(array))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun power(arg: NDStructure<Double>, pow: Double) = arg.mapInline { power(it, pow) }
|
||||||
|
|
||||||
|
override fun exp(arg: NDStructure<Double>) = arg.mapInline { exp(it) }
|
||||||
|
|
||||||
|
override fun ln(arg: NDStructure<Double>) = arg.mapInline { ln(it) }
|
||||||
|
|
||||||
|
override fun sin(arg: NDStructure<Double>) = arg.mapInline { sin(it) }
|
||||||
|
|
||||||
|
override fun cos(arg: NDStructure<Double>) = arg.mapInline { cos(it) }
|
||||||
|
|
||||||
|
override fun NDStructure<Double>.times(k: Number) = mapInline { value -> value * k.toDouble() }
|
||||||
|
|
||||||
|
override fun NDStructure<Double>.div(k: Number) = mapInline { value -> value / k.toDouble() }
|
||||||
|
|
||||||
|
override fun Number.times(b: NDStructure<Double>) = b * this
|
||||||
|
|
||||||
|
override fun Number.div(b: NDStructure<Double>) = b * (1.0 / this.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast element production using function inlining
|
||||||
|
*/
|
||||||
|
inline fun BufferNDField<Double, DoubleField>.produceInline(crossinline initializer: DoubleField.(Int) -> Double): RealNDElement {
|
||||||
|
val array = DoubleArray(strides.linearSize) { offset -> field.initializer(offset) }
|
||||||
|
return BufferNDElement(this, DoubleBuffer(array))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element by element application of any operation on elements to the whole array. Just like in numpy
|
||||||
|
*/
|
||||||
|
operator fun Function1<Double, Double>.invoke(ndElement: RealNDElement) =
|
||||||
|
ndElement.context.produceInline { i -> invoke(ndElement.buffer[i]) }
|
||||||
|
|
||||||
|
/* plus and minus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Summation operation for [BufferNDElement] and single element
|
||||||
|
*/
|
||||||
|
operator fun RealNDElement.plus(arg: Double) =
|
||||||
|
context.produceInline { i -> buffer[i] + arg }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtraction operation between [BufferNDElement] and single element
|
||||||
|
*/
|
||||||
|
operator fun RealNDElement.minus(arg: Double) =
|
||||||
|
context.produceInline { i -> buffer[i] - arg }
|
@ -3,10 +3,7 @@ package scientifik.kmath.structures
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import scientifik.kmath.operations.Field
|
import scientifik.kmath.operations.Field
|
||||||
|
|
||||||
class LazyNDField<T, F : Field<T>>(shape: IntArray, field: F, val scope: CoroutineScope = GlobalScope) : NDField<T, F>(shape, field) {
|
class LazyNDField<T, F : Field<T>>(shape: IntArray, field: F, val scope: CoroutineScope = GlobalScope) : BufferNDField<T, F>(shape,field, ::boxingBuffer) {
|
||||||
|
|
||||||
override fun produceStructure(initializer: F.(IntArray) -> T): NDStructure<T> = LazyNDStructure(this) { initializer(field, it) }
|
|
||||||
|
|
||||||
|
|
||||||
override fun add(a: NDStructure<T>, b: NDStructure<T>): NDElement<T, F> {
|
override fun add(a: NDStructure<T>, b: NDStructure<T>): NDElement<T, F> {
|
||||||
return LazyNDStructure(this) { index ->
|
return LazyNDStructure(this) { index ->
|
||||||
|
Loading…
Reference in New Issue
Block a user