Lazy structures revision
This commit is contained in:
parent
91207c8c9a
commit
d04ee956e5
@ -25,9 +25,9 @@ fun main() {
|
|||||||
|
|
||||||
val complexTime = measureTimeMillis {
|
val complexTime = measureTimeMillis {
|
||||||
complexField.run {
|
complexField.run {
|
||||||
var res: NDBuffer<Complex> = one
|
var res: ComplexNDElement = one
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
res += 1.0.toComplex()
|
res += 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package scientifik.kmath.structures
|
package scientifik.kmath.structures
|
||||||
|
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import scientifik.kmath.operations.RealField
|
import scientifik.kmath.operations.RealField
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
@ -11,8 +12,6 @@ fun main(args: Array<String>) {
|
|||||||
val autoField = NDField.auto(intArrayOf(dim, dim), RealField)
|
val autoField = NDField.auto(intArrayOf(dim, dim), RealField)
|
||||||
// specialized nd-field for Double. It works as generic Double field as well
|
// specialized nd-field for Double. It works as generic Double field as well
|
||||||
val specializedField = NDField.real(intArrayOf(dim, dim))
|
val specializedField = NDField.real(intArrayOf(dim, dim))
|
||||||
//A field implementing lazy computations. All elements are computed on-demand
|
|
||||||
val lazyField = NDField.lazy(intArrayOf(dim, dim), RealField)
|
|
||||||
//A generic boxing field. It should be used for objects, not primitives.
|
//A generic boxing field. It should be used for objects, not primitives.
|
||||||
val genericField = NDField.buffered(intArrayOf(dim, dim), RealField)
|
val genericField = NDField.buffered(intArrayOf(dim, dim), RealField)
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Buffered addition completed in $autoTime millis")
|
println("Automatic field addition completed in $autoTime millis")
|
||||||
|
|
||||||
val elementTime = measureTimeMillis {
|
val elementTime = measureTimeMillis {
|
||||||
var res = genericField.one
|
var res = genericField.one
|
||||||
@ -50,8 +49,7 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
|
|
||||||
val lazyTime = measureTimeMillis {
|
val lazyTime = measureTimeMillis {
|
||||||
lazyField.run {
|
val res = specializedField.one.mapAsync(GlobalScope) {
|
||||||
val res = one.map {
|
|
||||||
var c = 0.0
|
var c = 0.0
|
||||||
repeat(n) {
|
repeat(n) {
|
||||||
c += 1.0
|
c += 1.0
|
||||||
@ -61,7 +59,6 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
res.elements().forEach { it.second }
|
res.elements().forEach { it.second }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
println("Lazy addition completed in $lazyTime millis")
|
println("Lazy addition completed in $lazyTime millis")
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ plugins {
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
apply(plugin = "maven-publish")
|
apply(plugin = "maven-publish")
|
||||||
|
if(project.name.startsWith("kmath")) {
|
||||||
apply(plugin = "com.jfrog.artifactory")
|
apply(plugin = "com.jfrog.artifactory")
|
||||||
|
}
|
||||||
|
|
||||||
group = "scientifik"
|
group = "scientifik"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
|
15
examples/build.gradle.kts
Normal file
15
examples/build.gradle.kts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
description = "Examples for different kmath features"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":kmath-core"))
|
||||||
|
implementation(project(":kmath-coroutines"))
|
||||||
|
implementation(project(":kmath-commons"))
|
||||||
|
implementation(project(":kmath-koma"))
|
||||||
|
implementation(group = "com.kyonifer", name = "koma-core-ejml", version = "0.12")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
||||||
|
}
|
@ -4,7 +4,7 @@ import java.nio.ByteBuffer
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A specification for serialization and deserialization objects to buffer
|
* A specification for serialization and deserialization objects to buffer (at current buffer position)
|
||||||
*/
|
*/
|
||||||
interface BufferSpec<T : Any> {
|
interface BufferSpec<T : Any> {
|
||||||
/**
|
/**
|
||||||
|
@ -123,3 +123,9 @@ operator fun ComplexNDElement.plus(arg: Complex) =
|
|||||||
*/
|
*/
|
||||||
operator fun ComplexNDElement.minus(arg: Complex) =
|
operator fun ComplexNDElement.minus(arg: Complex) =
|
||||||
map { it - arg }
|
map { it - arg }
|
||||||
|
|
||||||
|
operator fun ComplexNDElement.plus(arg: Double) =
|
||||||
|
map { it + arg }
|
||||||
|
|
||||||
|
operator fun ComplexNDElement.minus(arg: Double) =
|
||||||
|
map { it - arg }
|
@ -6,9 +6,4 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
expect fun <R> runBlocking(
|
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
|
||||||
function: suspend CoroutineScope.() -> R
|
|
||||||
): R
|
|
||||||
|
|
||||||
val Dispatchers.Math: CoroutineDispatcher get() = Dispatchers.Default
|
val Dispatchers.Math: CoroutineDispatcher get() = Dispatchers.Default
|
@ -1,113 +0,0 @@
|
|||||||
package scientifik.kmath.structures
|
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import scientifik.kmath.operations.Field
|
|
||||||
import scientifik.kmath.operations.FieldElement
|
|
||||||
|
|
||||||
class LazyNDField<T, F : Field<T>>(
|
|
||||||
override val shape: IntArray,
|
|
||||||
override val elementContext: F,
|
|
||||||
val scope: CoroutineScope = GlobalScope
|
|
||||||
) : NDField<T, F, NDStructure<T>> {
|
|
||||||
|
|
||||||
override val zero by lazy { produce { zero } }
|
|
||||||
|
|
||||||
override val one by lazy { produce { one } }
|
|
||||||
|
|
||||||
override fun produce(initializer: F.(IntArray) -> T) =
|
|
||||||
LazyNDStructure(this) { elementContext.initializer(it) }
|
|
||||||
|
|
||||||
override fun mapIndexed(
|
|
||||||
arg: NDStructure<T>,
|
|
||||||
transform: F.(index: IntArray, T) -> T
|
|
||||||
): LazyNDStructure<T, F> {
|
|
||||||
check(arg)
|
|
||||||
return if (arg is LazyNDStructure<T, *>) {
|
|
||||||
LazyNDStructure(this) { index ->
|
|
||||||
//FIXME if value of arg is already calculated, it should be used
|
|
||||||
elementContext.transform(index, arg.function(index))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LazyNDStructure(this) { elementContext.transform(it, arg.await(it)) }
|
|
||||||
}
|
|
||||||
// return LazyNDStructure(this) { elementField.transform(it, arg.await(it)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun map(arg: NDStructure<T>, transform: F.(T) -> T) =
|
|
||||||
mapIndexed(arg) { _, t -> transform(t) }
|
|
||||||
|
|
||||||
override fun combine(a: NDStructure<T>, b: NDStructure<T>, transform: F.(T, T) -> T): LazyNDStructure<T, F> {
|
|
||||||
check(a, b)
|
|
||||||
return if (a is LazyNDStructure<T, *> && b is LazyNDStructure<T, *>) {
|
|
||||||
LazyNDStructure(this@LazyNDField) { index ->
|
|
||||||
elementContext.transform(
|
|
||||||
a.function(index),
|
|
||||||
b.function(index)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LazyNDStructure(this@LazyNDField) { elementContext.transform(a.await(it), b.await(it)) }
|
|
||||||
}
|
|
||||||
// return LazyNDStructure(this) { elementField.transform(a.await(it), b.await(it)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun NDStructure<T>.lazy(): LazyNDStructure<T, F> {
|
|
||||||
check(this)
|
|
||||||
return if (this is LazyNDStructure<T, *>) {
|
|
||||||
LazyNDStructure(this@LazyNDField, function)
|
|
||||||
} else {
|
|
||||||
LazyNDStructure(this@LazyNDField) { get(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LazyNDStructure<T, F : Field<T>>(
|
|
||||||
override val context: LazyNDField<T, F>,
|
|
||||||
val function: suspend (IntArray) -> T
|
|
||||||
) : FieldElement<NDStructure<T>, LazyNDStructure<T, F>, LazyNDField<T, F>>,
|
|
||||||
NDElement<T, F, NDStructure<T>> {
|
|
||||||
|
|
||||||
|
|
||||||
override fun unwrap(): NDStructure<T> = this
|
|
||||||
|
|
||||||
override fun NDStructure<T>.wrap(): LazyNDStructure<T, F> = LazyNDStructure(context) { await(it) }
|
|
||||||
|
|
||||||
override val shape: IntArray get() = context.shape
|
|
||||||
|
|
||||||
private val cache = HashMap<IntArray, Deferred<T>>()
|
|
||||||
|
|
||||||
fun deferred(index: IntArray) = cache.getOrPut(index) {
|
|
||||||
context.scope.async(context = Dispatchers.Math) {
|
|
||||||
function(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun await(index: IntArray): T = deferred(index).await()
|
|
||||||
|
|
||||||
override fun get(index: IntArray): T = runBlocking {
|
|
||||||
deferred(index).await()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun elements(): Sequence<Pair<IntArray, T>> {
|
|
||||||
val strides = DefaultStrides(shape)
|
|
||||||
val res = runBlocking {
|
|
||||||
strides.indices().toList().map { index -> index to await(index) }
|
|
||||||
}
|
|
||||||
return res.asSequence()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> NDStructure<T>.deferred(index: IntArray) =
|
|
||||||
if (this is LazyNDStructure<T, *>) this.deferred(index) else CompletableDeferred(get(index))
|
|
||||||
|
|
||||||
suspend fun <T> NDStructure<T>.await(index: IntArray) =
|
|
||||||
if (this is LazyNDStructure<T, *>) this.await(index) else get(index)
|
|
||||||
|
|
||||||
|
|
||||||
fun <T : Any, F : Field<T>> NDField.Companion.lazy(shape: IntArray, field: F, scope: CoroutineScope = GlobalScope) =
|
|
||||||
LazyNDField(shape, field, scope)
|
|
||||||
|
|
||||||
fun <T, F : Field<T>> NDStructure<T>.lazy(field: F, scope: CoroutineScope = GlobalScope): LazyNDStructure<T, F> {
|
|
||||||
val context: LazyNDField<T, F> = LazyNDField(shape, field, scope)
|
|
||||||
return LazyNDStructure(context) { get(it) }
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package scientifik.kmath.structures
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
|
|
||||||
actual fun <R> runBlocking(
|
|
||||||
context: CoroutineContext,
|
|
||||||
function: suspend CoroutineScope.() -> R
|
|
||||||
): R {
|
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
|
||||||
}
|
|
@ -0,0 +1,47 @@
|
|||||||
|
package scientifik.kmath.structures
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
class LazyNDStructure<T>(
|
||||||
|
val scope: CoroutineScope,
|
||||||
|
override val shape: IntArray,
|
||||||
|
val function: suspend (IntArray) -> T
|
||||||
|
) : NDStructure<T> {
|
||||||
|
|
||||||
|
private val cache = HashMap<IntArray, Deferred<T>>()
|
||||||
|
|
||||||
|
fun deferred(index: IntArray) = cache.getOrPut(index) {
|
||||||
|
scope.async(context = Dispatchers.Math) {
|
||||||
|
function(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun await(index: IntArray): T = deferred(index).await()
|
||||||
|
|
||||||
|
override fun get(index: IntArray): T = runBlocking {
|
||||||
|
deferred(index).await()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun elements(): Sequence<Pair<IntArray, T>> {
|
||||||
|
val strides = DefaultStrides(shape)
|
||||||
|
val res = runBlocking {
|
||||||
|
strides.indices().toList().map { index -> index to await(index) }
|
||||||
|
}
|
||||||
|
return res.asSequence()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> NDStructure<T>.deferred(index: IntArray) =
|
||||||
|
if (this is LazyNDStructure<T>) this.deferred(index) else CompletableDeferred(get(index))
|
||||||
|
|
||||||
|
suspend fun <T> NDStructure<T>.await(index: IntArray) =
|
||||||
|
if (this is LazyNDStructure<T>) this.await(index) else get(index)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PENDING would benifit from KEEP-176
|
||||||
|
*/
|
||||||
|
fun <T, R> NDStructure<T>.mapAsyncIndexed(scope: CoroutineScope, function: suspend (T, index: IntArray) -> R) =
|
||||||
|
LazyNDStructure(scope, shape) { index -> function(get(index), index) }
|
||||||
|
|
||||||
|
fun <T, R> NDStructure<T>.mapAsync(scope: CoroutineScope, function: suspend (T) -> R) =
|
||||||
|
LazyNDStructure(scope, shape) { index -> function(get(index)) }
|
@ -1,7 +0,0 @@
|
|||||||
package scientifik.kmath.structures
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
|
|
||||||
actual fun <R> runBlocking(context: CoroutineContext, function: suspend CoroutineScope.() -> R): R =
|
|
||||||
kotlinx.coroutines.runBlocking(context, function)
|
|
@ -25,5 +25,6 @@ include(
|
|||||||
":kmath-commons",
|
":kmath-commons",
|
||||||
":kmath-koma",
|
":kmath-koma",
|
||||||
":kmath-sequential",
|
":kmath-sequential",
|
||||||
":benchmarks"
|
":benchmarks",
|
||||||
|
":examples"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user