forked from kscience/kmath
Lazy structures revision
This commit is contained in:
parent
91207c8c9a
commit
d04ee956e5
@ -25,9 +25,9 @@ fun main() {
|
||||
|
||||
val complexTime = measureTimeMillis {
|
||||
complexField.run {
|
||||
var res: NDBuffer<Complex> = one
|
||||
var res: ComplexNDElement = one
|
||||
repeat(n) {
|
||||
res += 1.0.toComplex()
|
||||
res += 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package scientifik.kmath.structures
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import scientifik.kmath.operations.RealField
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@ -11,8 +12,6 @@ fun main(args: Array<String>) {
|
||||
val autoField = NDField.auto(intArrayOf(dim, dim), RealField)
|
||||
// specialized nd-field for Double. It works as generic Double field as well
|
||||
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.
|
||||
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 {
|
||||
var res = genericField.one
|
||||
@ -50,17 +49,15 @@ fun main(args: Array<String>) {
|
||||
|
||||
|
||||
val lazyTime = measureTimeMillis {
|
||||
lazyField.run {
|
||||
val res = one.map {
|
||||
var c = 0.0
|
||||
repeat(n) {
|
||||
c += 1.0
|
||||
}
|
||||
c
|
||||
val res = specializedField.one.mapAsync(GlobalScope) {
|
||||
var c = 0.0
|
||||
repeat(n) {
|
||||
c += 1.0
|
||||
}
|
||||
|
||||
res.elements().forEach { it.second }
|
||||
c
|
||||
}
|
||||
|
||||
res.elements().forEach { it.second }
|
||||
}
|
||||
|
||||
println("Lazy addition completed in $lazyTime millis")
|
||||
|
@ -24,7 +24,9 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
apply(plugin = "maven-publish")
|
||||
apply(plugin = "com.jfrog.artifactory")
|
||||
if(project.name.startsWith("kmath")) {
|
||||
apply(plugin = "com.jfrog.artifactory")
|
||||
}
|
||||
|
||||
group = "scientifik"
|
||||
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> {
|
||||
/**
|
||||
|
@ -123,3 +123,9 @@ operator fun ComplexNDElement.plus(arg: Complex) =
|
||||
*/
|
||||
operator fun ComplexNDElement.minus(arg: Complex) =
|
||||
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.EmptyCoroutineContext
|
||||
|
||||
expect fun <R> runBlocking(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
function: suspend CoroutineScope.() -> R
|
||||
): R
|
||||
|
||||
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-koma",
|
||||
":kmath-sequential",
|
||||
":benchmarks"
|
||||
":benchmarks",
|
||||
":examples"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user