Lazy structures, structure is no longer iterable, removed copy on read-only buffers.

This commit is contained in:
Alexander Nozik 2018-12-11 17:25:55 +03:00
parent bdd9dccd4f
commit cddea1869d
25 changed files with 465 additions and 68 deletions

View File

@ -58,11 +58,11 @@ repositories {
Then use regular dependency like
```groovy
compile(group: 'scientifik', name: 'kmath-core-jvm', version: '0.0.1-SNAPSHOT')
compile(group: 'scientifik', name: 'kmath-core', version: '0.0.1-SNAPSHOT')
```
or in kotlin
```kotlin
compile(group = "scientifik", name = "kmath-core-jvm", version = "0.0.1-SNAPSHOT")
compile(group = "scientifik", name = "kmath-core", version = "0.0.1-SNAPSHOT")
```
Work builds could be obtained with [![](https://jitpack.io/v/altavir/kmath.svg)](https://jitpack.io/#altavir/kmath).

View File

@ -1,7 +1,11 @@
buildscript {
extra["kotlinVersion"] = "1.3.10"
extra["kotlinVersion"] = "1.3.11"
extra["ioVersion"] = "0.1.2-dev-2"
extra["coroutinesVersion"] = "1.0.1"
val kotlinVersion: String by extra
val ioVersion: String by extra
val coroutinesVersion: String by extra
repositories {
jcenter()
@ -15,6 +19,7 @@ buildscript {
plugins {
id("com.jfrog.artifactory") version "4.8.1" apply false
// id("org.jetbrains.kotlin.multiplatform") apply false
}
allprojects {
@ -22,7 +27,7 @@ allprojects {
apply(plugin = "com.jfrog.artifactory")
group = "scientifik"
version = "0.0.1-SNAPSHOT"
version = "0.0.2-dev-1"
}
if(file("artifactory.gradle").exists()){

View File

@ -1,5 +1,5 @@
plugins {
id 'kotlin-multiplatform'
id "org.jetbrains.kotlin.multiplatform"
}
kotlin {
@ -14,7 +14,7 @@ kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
api 'org.jetbrains.kotlin:kotlin-stdlib-common'
}
}
commonTest {
@ -25,7 +25,7 @@ kotlin {
}
jvmMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
api 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
}
}
jvmTest {
@ -36,7 +36,7 @@ kotlin {
}
jsMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
api 'org.jetbrains.kotlin:kotlin-stdlib-js'
}
}
jsTest {

View File

@ -85,7 +85,7 @@ class FastHistogram(
values[index].increment()
}
override fun iterator(): Iterator<PhantomBin<Double>> = values.asSequence().map { (index, value) ->
override fun iterator(): Iterator<PhantomBin<Double>> = values.elements().map { (index, value) ->
PhantomBin(getTemplate(index), value.sum())
}.iterator()
@ -100,7 +100,7 @@ class FastHistogram(
* Create a phantom lightweight immutable copy of this histogram
*/
fun asPhantomHistogram(): PhantomHistogram<Double> {
val binTemplates = values.associate { (index, _) -> getTemplate(index) to index }
val binTemplates = values.elements().associate { (index, _) -> getTemplate(index) to index }
return PhantomHistogram(binTemplates, asNDStructure())
}

View File

@ -98,8 +98,6 @@ class ArrayVector<T : Any, F : Field<T>> internal constructor(override val conte
override fun iterator(): Iterator<T> = (0 until size).map { element[it] }.iterator()
override fun copy(): ArrayVector<T, F> = ArrayVector(context, element)
override fun toString(): String = this.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() }
}

View File

@ -38,4 +38,8 @@ data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Compl
val abs: Double
get() = kotlin.math.sqrt(square)
companion object {
}
}

View File

@ -49,6 +49,9 @@ inline class Real(val value: Double) : FieldElement<Real, RealField> {
override val context
get() = RealField
companion object {
}
}
/**
@ -72,3 +75,15 @@ object DoubleField : ExtendedField<Double>, Norm<Double, Double> {
override fun norm(arg: Double): Double = kotlin.math.abs(arg)
}
/**
* A field for double without boxing. Does not produce appropriate field element
*/
object IntField : Field<Int>{
override val zero: Int = 0
override fun add(a: Int, b: Int): Int = a + b
override fun multiply(a: Int, b: Int): Int = a * b
override fun multiply(a: Int, k: Double): Int = (k*a).toInt()
override val one: Int = 1
override fun divide(a: Int, b: Int): Int = a / b
}

View File

@ -11,11 +11,6 @@ interface Buffer<T> {
operator fun get(index: Int): T
operator fun iterator(): Iterator<T>
/**
* A shallow copy of the buffer
*/
fun copy(): Buffer<T>
}
fun <T> Buffer<T>.asSequence(): Sequence<T> = iterator().asSequence()
@ -26,7 +21,7 @@ interface MutableBuffer<T> : Buffer<T> {
/**
* A shallow copy of the buffer
*/
override fun copy(): MutableBuffer<T>
fun copy(): MutableBuffer<T>
}
@ -38,8 +33,6 @@ inline class ListBuffer<T>(private val list: List<T>) : Buffer<T> {
override fun get(index: Int): T = list[index]
override fun iterator(): Iterator<T> = list.iterator()
override fun copy(): ListBuffer<T> = ListBuffer(ArrayList(list))
}
inline class MutableListBuffer<T>(private val list: MutableList<T>) : MutableBuffer<T> {
@ -104,10 +97,43 @@ inline class IntBuffer(private val array: IntArray): MutableBuffer<Int>{
override fun copy(): MutableBuffer<Int> = IntBuffer(array.copyOf())
}
inline fun <reified T : Any> buffer(size: Int, noinline initializer: (Int) -> T): Buffer<T> {
return ArrayBuffer(Array(size, initializer))
inline class ReadOnlyBuffer<T>(private val buffer: MutableBuffer<T>) : Buffer<T> {
override val size: Int get() = buffer.size
override fun get(index: Int): T = buffer.get(index)
override fun iterator(): Iterator<T> = buffer.iterator()
}
inline fun <reified T : Any> mutableBuffer(size: Int, noinline initializer: (Int) -> T): MutableBuffer<T> {
return ArrayBuffer(Array(size, initializer))
/**
* Convert this buffer to read-only buffer
*/
fun <T> Buffer<T>.asReadOnly(): Buffer<T> = if (this is MutableBuffer) {
ReadOnlyBuffer(this)
} else {
this
}
/**
* Create most appropriate immutable buffer for given type avoiding boxing wherever possible
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> buffer(size: Int, noinline initializer: (Int) -> T): Buffer<T> {
return when (T::class) {
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T>
else -> ArrayBuffer(Array(size, initializer))
}
}
/**
* Create most appropriate mutable buffer for given type avoiding boxing wherever possible
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> mutableBuffer(size: Int, noinline initializer: (Int) -> T): MutableBuffer<T> {
return when (T::class) {
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer<T>
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer<T>
else -> ArrayBuffer(Array(size, initializer))
}
}

View File

@ -23,7 +23,7 @@ abstract class NDField<T, F : Field<T>>(val shape: IntArray, val field: F) : Fie
* Create new instance of NDArray using field shape and given initializer
* The producer takes list of indices as argument and returns contained value
*/
fun produce(initializer: F.(IntArray) -> T): NDElement<T, F> = NDElement(this, produceStructure(initializer))
fun produce(initializer: F.(IntArray) -> T): NDElement<T, F> = NDStructureElement(this, produceStructure(initializer))
override val zero: NDElement<T, F> by lazy {
produce { zero }
@ -83,7 +83,7 @@ abstract class NDField<T, F : Field<T>>(val shape: IntArray, val field: F) : Fie
// /**
// * Reverse minus operation
// */
// operator fun T.minus(arg: NDElement<T, F>): NDElement<T, F> = arg.transform { _, value ->
// operator fun T.minus(arg: NDElement<T, F>): NDElement<T, F> = arg.transformIndexed { _, value ->
// with(arg.context.field) {
// this@minus - value
// }
@ -97,38 +97,41 @@ abstract class NDField<T, F : Field<T>>(val shape: IntArray, val field: F) : Fie
// /**
// * Reverse division operation
// */
// operator fun T.div(arg: NDElement<T, F>): NDElement<T, F> = arg.transform { _, value ->
// operator fun T.div(arg: NDElement<T, F>): NDElement<T, F> = arg.transformIndexed { _, value ->
// with(arg.context.field) {
// this@div / value
// }
// }
}
interface NDElement<T, F : Field<T>>: FieldElement<NDElement<T, F>, NDField<T, F>>, NDStructure<T>
inline fun <T, F : Field<T>> NDElement<T, F>.transformIndexed(crossinline action: F.(IntArray, T) -> T): NDElement<T, F> = context.produce { action(it, get(*it)) }
inline fun <T, F : Field<T>> NDElement<T, F>.transform(crossinline action: F.(T) -> T): NDElement<T, F> = context.produce { action(get(*it)) }
/**
* Immutable [NDStructure] coupled to the context. Emulates Python ndarray
* Read-only [NDStructure] coupled to the context.
*/
class NDElement<T, F : Field<T>>(override val context: NDField<T, F>, private val structure: NDStructure<T>) : FieldElement<NDElement<T, F>, NDField<T, F>>, NDStructure<T> by structure {
class NDStructureElement<T, F : Field<T>>(override val context: NDField<T, F>, private val structure: NDStructure<T>) : NDElement<T,F>, NDStructure<T> by structure {
//TODO ensure structure is immutable
override val self: NDElement<T, F>
get() = this
inline fun transform(crossinline action: (IntArray, T) -> T): NDElement<T, F> = context.produce { action(it, get(*it)) }
inline fun transform(crossinline action: (T) -> T): NDElement<T, F> = context.produce { action(get(*it)) }
override val self: NDElement<T, F> get() = this
}
/**
* Element by element application of any operation on elements to the whole array. Just like in numpy
*/
operator fun <T, F : Field<T>> Function1<T, T>.invoke(ndElement: NDElement<T, F>): NDElement<T, F> = ndElement.transform { _, value -> this(value) }
operator fun <T, F : Field<T>> Function1<T, T>.invoke(ndElement: NDElement<T, F>): NDElement<T, F> = ndElement.transform {value -> this@invoke(value) }
/* plus and minus */
/**
* Summation operation for [NDElement] and single element
*/
operator fun <T, F : Field<T>> NDElement<T, F>.plus(arg: T): NDElement<T, F> = transform { _, value ->
operator fun <T, F : Field<T>> NDElement<T, F>.plus(arg: T): NDElement<T, F> = transform {value ->
with(context.field) {
arg + value
}
@ -137,7 +140,7 @@ operator fun <T, F : Field<T>> NDElement<T, F>.plus(arg: T): NDElement<T, F> = t
/**
* Subtraction operation between [NDElement] and single element
*/
operator fun <T, F : Field<T>> NDElement<T, F>.minus(arg: T): NDElement<T, F> = transform { _, value ->
operator fun <T, F : Field<T>> NDElement<T, F>.minus(arg: T): NDElement<T, F> = transform {value ->
with(context.field) {
arg - value
}
@ -148,7 +151,7 @@ operator fun <T, F : Field<T>> NDElement<T, F>.minus(arg: T): NDElement<T, F> =
/**
* Product operation for [NDElement] and single element
*/
operator fun <T, F : Field<T>> NDElement<T, F>.times(arg: T): NDElement<T, F> = transform { _, value ->
operator fun <T, F : Field<T>> NDElement<T, F>.times(arg: T): NDElement<T, F> = transform { value ->
with(context.field) {
arg * value
}
@ -157,7 +160,7 @@ operator fun <T, F : Field<T>> NDElement<T, F>.times(arg: T): NDElement<T, F> =
/**
* Division operation between [NDElement] and single element
*/
operator fun <T, F : Field<T>> NDElement<T, F>.div(arg: T): NDElement<T, F> = transform { _, value ->
operator fun <T, F : Field<T>> NDElement<T, F>.div(arg: T): NDElement<T, F> = transform { value ->
with(context.field) {
arg / value
}

View File

@ -1,7 +1,7 @@
package scientifik.kmath.structures
interface NDStructure<T> : Iterable<Pair<IntArray, T>> {
interface NDStructure<T> {
val shape: IntArray
@ -9,6 +9,8 @@ interface NDStructure<T> : Iterable<Pair<IntArray, T>> {
get() = shape.size
operator fun get(index: IntArray): T
fun elements(): Sequence<Pair<IntArray, T>>
}
operator fun <T> NDStructure<T>.get(vararg index: Int): T = get(index)
@ -18,7 +20,7 @@ interface MutableNDStructure<T> : NDStructure<T> {
}
fun <T> MutableNDStructure<T>.transformInPlace(action: (IntArray, T) -> T) {
for ((index, oldValue) in this) {
elements().forEach { (index, oldValue) ->
this[index] = action(index, oldValue)
}
}
@ -107,8 +109,8 @@ abstract class GenericNDStructure<T, B : Buffer<T>> : NDStructure<T> {
override val shape: IntArray
get() = strides.shape
override fun iterator(): Iterator<Pair<IntArray, T>> =
strides.indices().map { it to this[it] }.iterator()
override fun elements()=
strides.indices().map { it to this[it] }
}
/**
@ -169,6 +171,6 @@ fun <T> genericNdStructure(shape: IntArray, initializer: (IntArray) -> T): Mutab
yield(initializer(it))
}
}
val buffer = MutableListBuffer<T>(sequence.toMutableList())
val buffer = MutableListBuffer(sequence.toMutableList())
return MutableBufferNDStructure(strides, buffer)
}

View File

@ -0,0 +1,55 @@
package scientifik.kmath.structures
import java.nio.ByteBuffer
/**
* A specification for serialization and deserialization objects to buffer
*/
interface BufferSpec<T : Any> {
fun fromBuffer(buffer: ByteBuffer): T
fun toBuffer(value: T): ByteBuffer
}
/**
* A [BufferSpec] with fixed unit size. Allows storage of any object without boxing.
*/
interface FixedSizeBufferSpec<T : Any> : BufferSpec<T> {
val unitSize: Int
/**
* Read an object from buffer in current position
*/
fun ByteBuffer.readObject(): T {
val buffer = ByteArray(unitSize)
get(buffer)
return fromBuffer(ByteBuffer.wrap(buffer))
}
/**
* Read an object from buffer in given index (not buffer position
*/
fun ByteBuffer.readObject(index: Int): T {
val dup = duplicate()
dup.position(index*unitSize)
return dup.readObject()
}
/**
* Write object to [ByteBuffer] in current buffer position
*/
fun ByteBuffer.writeObject(obj: T) {
val buffer = toBuffer(obj).apply { rewind() }
assert(buffer.limit() == unitSize)
put(buffer)
}
/**
* Put an object in given index
*/
fun ByteBuffer.writeObject(index: Int, obj: T) {
val dup = duplicate()
dup.position(index*unitSize)
dup.writeObject(obj)
}
}

View File

@ -0,0 +1,25 @@
package scientifik.kmath.structures
import scientifik.kmath.operations.Complex
import java.nio.ByteBuffer
object ComplexBufferSpec : FixedSizeBufferSpec<Complex> {
override val unitSize: Int = 16
override fun fromBuffer(buffer: ByteBuffer): Complex {
val re = buffer.getDouble(0)
val im = buffer.getDouble(8)
return Complex(re, im)
}
override fun toBuffer(value: Complex): ByteBuffer = ByteBuffer.allocate(16).apply {
putDouble(value.re)
putDouble(value.im)
}
}
/**
* Create a mutable buffer which ignores boxing
*/
fun Complex.Companion.createBuffer(size: Int) = ObjectBuffer.create(ComplexBufferSpec, size)

View File

@ -0,0 +1,28 @@
package scientifik.kmath.structures
import java.nio.ByteBuffer
class ObjectBuffer<T : Any>(private val buffer: ByteBuffer, private val spec: FixedSizeBufferSpec<T>) : MutableBuffer<T> {
override val size: Int
get() = buffer.limit() / spec.unitSize
override fun get(index: Int): T = with(spec) { buffer.readObject(index) }
override fun iterator(): Iterator<T> = (0 until size).asSequence().map { get(it) }.iterator()
override fun set(index: Int, value: T) = with(spec) { buffer.writeObject(index, value) }
override fun copy(): MutableBuffer<T> {
val dup = buffer.duplicate()
val copy = ByteBuffer.allocate(dup.capacity())
dup.rewind()
copy.put(dup)
copy.flip()
return ObjectBuffer(copy, spec)
}
companion object {
fun <T : Any> create(spec: FixedSizeBufferSpec<T>, size: Int) =
ObjectBuffer<T>(ByteBuffer.allocate(size * spec.unitSize), spec)
}
}

View File

@ -0,0 +1,23 @@
package scientifik.kmath.structures
import scientifik.kmath.operations.Real
import java.nio.ByteBuffer
object RealBufferSpec : FixedSizeBufferSpec<Real> {
override val unitSize: Int = 8
override fun fromBuffer(buffer: ByteBuffer): Real = Real(buffer.double)
override fun toBuffer(value: Real): ByteBuffer = ByteBuffer.allocate(8).apply { putDouble(value.value) }
}
object DoubleBufferSpec : FixedSizeBufferSpec<Double> {
override val unitSize: Int = 8
override fun fromBuffer(buffer: ByteBuffer): Double = buffer.double
override fun toBuffer(value: Double): ByteBuffer = ByteBuffer.allocate(8).apply { putDouble(value) }
}
fun Double.Companion.createBuffer(size: Int) = ObjectBuffer.create(DoubleBufferSpec, size)
fun Real.Companion.createBuffer(size: Int) = ObjectBuffer.create(RealBufferSpec, size)

View File

@ -0,0 +1,17 @@
package scientifik.kmath.structures
import org.junit.Test
import scientifik.kmath.operations.Complex
import kotlin.test.assertEquals
class ComplexBufferSpecTest {
@Test
fun testComplexBuffer() {
val buffer = Complex.createBuffer(20)
(0 until 20).forEach {
buffer[it] = Complex(it.toDouble(), -it.toDouble())
}
assertEquals(Complex(5.0, -5.0), buffer[5])
}
}

View File

@ -0,0 +1,42 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
}
kotlin {
targets {
fromPreset(presets.jvm, 'jvm')
// For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64
// For Linux, preset should be changed to e.g. presets.linuxX64
// For MacOS, preset should be changed to e.g. presets.macosX64
//fromPreset(presets.mingwX64, 'mingw')
}
sourceSets {
commonMain {
dependencies {
api project(":kmath-core")
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutinesVersion"
}
}
commonTest {
dependencies {
api 'org.jetbrains.kotlin:kotlin-test-common'
api 'org.jetbrains.kotlin:kotlin-test-annotations-common'
}
}
jvmMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
}
}
jvmTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
}
// mingwMain {
// }
// mingwTest {
// }
}
}

View File

@ -0,0 +1,11 @@
package scientifik.kmath.structures
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
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

@ -0,0 +1,79 @@
package scientifik.kmath.structures
import kotlinx.coroutines.*
import scientifik.kmath.operations.Field
class LazyNDField<T, F : Field<T>>(shape: IntArray, field: F, val scope: CoroutineScope = GlobalScope) : NDField<T, F>(shape, field) {
override fun produceStructure(initializer: F.(IntArray) -> T): NDStructure<T> = LazyNDStructure(this) { initializer(field, it) }
override fun add(a: NDElement<T, F>, b: NDElement<T, F>): NDElement<T, F> {
return LazyNDStructure(this) { index ->
val aDeferred = a.deferred(index)
val bDeferred = b.deferred(index)
aDeferred.await() + bDeferred.await()
}
}
override fun multiply(a: NDElement<T, F>, k: Double): NDElement<T, F> {
return LazyNDStructure(this) { index -> a.await(index) * k }
}
override fun multiply(a: NDElement<T, F>, b: NDElement<T, F>): NDElement<T, F> {
return LazyNDStructure(this) { index ->
val aDeferred = a.deferred(index)
val bDeferred = b.deferred(index)
aDeferred.await() * bDeferred.await()
}
}
override fun divide(a: NDElement<T, F>, b: NDElement<T, F>): NDElement<T, F> {
return LazyNDStructure(this) { index ->
val aDeferred = a.deferred(index)
val bDeferred = b.deferred(index)
aDeferred.await() / bDeferred.await()
}
}
}
class LazyNDStructure<T, F : Field<T>>(override val context: LazyNDField<T, F>, val function: suspend F.(IntArray) -> T) : NDElement<T, F>, NDStructure<T> {
override val self: NDElement<T, F> get() = this
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.invoke(context.field, 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)
return strides.indices().map { index -> index to runBlocking { await(index) } }
}
}
fun <T> NDElement<T, *>.deferred(index: IntArray) = if (this is LazyNDStructure<T, *>) this.deferred(index) else CompletableDeferred(get(index))
suspend fun <T> NDElement<T, *>.await(index: IntArray) = if (this is LazyNDStructure<T, *>) this.await(index) else get(index)
fun <T, F : Field<T>> NDElement<T, F>.lazy(scope: CoroutineScope = GlobalScope): LazyNDStructure<T, F> {
return if (this is LazyNDStructure<T, F>) {
this
} else {
val context = LazyNDField(context.shape, context.field)
LazyNDStructure(context) { get(it) }
}
}
inline fun <T, F : Field<T>> LazyNDStructure<T, F>.transformIndexed(crossinline action: suspend F.(IntArray, T) -> T) = LazyNDStructure(context) { index ->
action.invoke(this, index, await(index))
}
inline fun <T, F : Field<T>> LazyNDStructure<T, F>.transform(crossinline action: suspend F.(T) -> T) = LazyNDStructure(context) { index ->
action.invoke(this, await(index))
}

View File

@ -0,0 +1,20 @@
package scientifik.kmath.structures
import scientifik.kmath.operations.IntField
import kotlin.test.Test
import kotlin.test.assertEquals
class LazyNDFieldTest {
@Test
fun testLazyStructure() {
var counter = 0
val regularStructure = NDArrays.create(IntField, intArrayOf(2, 2, 2)) { it[0] + it[1] - it[2] }
val result = (regularStructure.lazy() + 2).transform {
counter++
it * it
}
assertEquals(4, result[0,0,0])
assertEquals(1, counter)
}
}

View File

@ -0,0 +1,6 @@
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

@ -1,5 +1,5 @@
plugins {
id 'kotlin-multiplatform'
id "org.jetbrains.kotlin.multiplatform"
}
kotlin {
@ -16,6 +16,7 @@ kotlin {
dependencies {
api project(":kmath-core")
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
api "org.jetbrains.kotlinx:kotlinx-io:$ioVersion"
}
}
commonTest {
@ -27,6 +28,7 @@ kotlin {
jvmMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
api "org.jetbrains.kotlinx:kotlinx-io-jvm:$ioVersion"
}
}
jvmTest {

View File

@ -5,6 +5,6 @@ plugins {
}
dependencies {
implementation project(':kmath-core')
jmh 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
compile project(':kmath-core')
//jmh project(':kmath-core')
}

View File

@ -4,8 +4,7 @@ import org.openjdk.jmh.annotations.*
import java.nio.IntBuffer
@Fork(1)
@Warmup(iterations = 2)
@Warmup(iterations = 1)
@Measurement(iterations = 5)
@State(Scope.Benchmark)
open class ArrayBenchmark {
@ -30,7 +29,6 @@ open class ArrayBenchmark {
for (i in 1..10000) {
res += array[10000 - i]
}
print(res)
}
@Benchmark
@ -39,7 +37,6 @@ open class ArrayBenchmark {
for (i in 1..10000) {
res += arrayBuffer.get(10000 - i)
}
print(res)
}
@Benchmark
@ -48,6 +45,5 @@ open class ArrayBenchmark {
for (i in 1..10000) {
res += nativeBuffer.get(10000 - i)
}
print(res)
}
}

View File

@ -0,0 +1,38 @@
package scientifik.kmath.structures
import org.openjdk.jmh.annotations.*
import scientifik.kmath.operations.Complex
@Warmup(iterations = 1)
@Measurement(iterations = 5)
@State(Scope.Benchmark)
open class BufferBenchmark {
@Benchmark
fun genericDoubleBufferReadWrite() {
val buffer = Double.createBuffer(size)
(0 until size).forEach {
buffer[it] = it.toDouble()
}
(0 until size).forEach {
buffer[it]
}
}
@Benchmark
fun complexBufferReadWrite() {
val buffer = Complex.createBuffer(size/2)
(0 until size/2).forEach {
buffer[it] = Complex(it.toDouble(), -it.toDouble())
}
(0 until size/2).forEach {
buffer[it]
}
}
companion object {
const val size = 1000
}
}

View File

@ -5,10 +5,12 @@ pluginManagement {
}
}
enableFeaturePreview("GRADLE_METADATA")
//enableFeaturePreview("GRADLE_METADATA")
rootProject.name = "kmath"
include(
":kmath-core",
":kmath-io",
":kmath-coroutines",
":kmath-jmh"
)