Lazy structures revision

This commit is contained in:
Alexander Nozik 2019-02-12 14:06:37 +03:00
parent 91207c8c9a
commit d04ee956e5
12 changed files with 85 additions and 153 deletions

View File

@ -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
}
}
}

View File

@ -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")

View File

@ -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
View 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")
}

View File

@ -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> {
/**

View File

@ -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 }

View File

@ -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

View File

@ -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) }
}

View File

@ -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.
}

View File

@ -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)) }

View File

@ -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)

View File

@ -25,5 +25,6 @@ include(
":kmath-commons",
":kmath-koma",
":kmath-sequential",
":benchmarks"
":benchmarks",
":examples"
)