From f9836a64779c61a510716641b9f45c5ec658d80f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 8 Dec 2019 15:48:25 +0300 Subject: [PATCH] Viktor prototype --- examples/build.gradle.kts | 3 +- .../scientifik/kmath/structures/NDField.kt | 30 +++----- .../scientifik/kmath/structures/VictorTest.kt | 42 +++++++++++ kmath-commons/build.gradle.kts | 2 - .../kmath/structures/ExtendedNDField.kt | 1 - kmath-viktor/build.gradle.kts | 10 +++ .../scientifik/kmath/viktor/ViktorBuffer.kt | 20 +++++ .../kmath/viktor/ViktorNDStructure.kt | 73 +++++++++++++++++++ settings.gradle.kts | 1 + 9 files changed, 160 insertions(+), 22 deletions(-) create mode 100644 examples/src/main/kotlin/scientifik/kmath/structures/VictorTest.kt create mode 100644 kmath-viktor/build.gradle.kts create mode 100644 kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt create mode 100644 kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index ad59afc5c..dfd530618 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { java kotlin("jvm") - kotlin("plugin.allopen") version "1.3.60" + kotlin("plugin.allopen") version "1.3.61" id("kotlinx.benchmark") version "0.2.0-dev-5" } @@ -29,6 +29,7 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-koma")) + implementation(project(":kmath-viktor")) implementation("com.kyonifer:koma-core-ejml:0.12") implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:${Scientifik.ioVersion}") diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt index 7e8c433c0..cfd1206ff 100644 --- a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt @@ -4,7 +4,13 @@ import kotlinx.coroutines.GlobalScope import scientifik.kmath.operations.RealField import kotlin.system.measureTimeMillis -fun main(args: Array) { +internal inline fun measureAndPrint(title: String, block: () -> Unit) { + val time = measureTimeMillis(block) + println("$title completed in $time millis") +} + + +fun main() { val dim = 1000 val n = 1000 @@ -15,8 +21,7 @@ fun main(args: Array) { //A generic boxing field. It should be used for objects, not primitives. val genericField = NDField.boxing(RealField, dim, dim) - - val autoTime = measureTimeMillis { + measureAndPrint("Automatic field addition") { autoField.run { var res = one repeat(n) { @@ -25,18 +30,14 @@ fun main(args: Array) { } } - println("Automatic field addition completed in $autoTime millis") - - val elementTime = measureTimeMillis { + measureAndPrint("Element addition"){ var res = genericField.one repeat(n) { res += 1.0 } } - println("Element addition completed in $elementTime millis") - - val specializedTime = measureTimeMillis { + measureAndPrint("Specialized addition") { specializedField.run { var res: NDBuffer = one repeat(n) { @@ -45,10 +46,7 @@ fun main(args: Array) { } } - println("Specialized addition completed in $specializedTime millis") - - - val lazyTime = measureTimeMillis { + measureAndPrint("Lazy addition") { val res = specializedField.one.mapAsync(GlobalScope) { var c = 0.0 repeat(n) { @@ -60,9 +58,7 @@ fun main(args: Array) { res.elements().forEach { it.second } } - println("Lazy addition completed in $lazyTime millis") - - val genericTime = measureTimeMillis { + measureAndPrint("Generic addition") { //genericField.run(action) genericField.run { var res: NDBuffer = one @@ -72,6 +68,4 @@ fun main(args: Array) { } } - println("Generic addition completed in $genericTime millis") - } \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/VictorTest.kt b/examples/src/main/kotlin/scientifik/kmath/structures/VictorTest.kt new file mode 100644 index 000000000..da0c193ad --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/structures/VictorTest.kt @@ -0,0 +1,42 @@ +package scientifik.kmath.structures + +import org.jetbrains.bio.viktor.F64Array +import scientifik.kmath.operations.RealField +import scientifik.kmath.viktor.ViktorNDField + +fun main() { + val dim = 1000 + val n = 400 + + // automatically build context most suited for given type. + val autoField = NDField.auto(RealField, dim, dim) + + val viktorField = ViktorNDField(intArrayOf(dim, dim)) + + + measureAndPrint("Automatic field addition") { + autoField.run { + var res = one + repeat(n) { + res += 1.0 + } + } + } + + measureAndPrint("Raw Viktor") { + val one = F64Array.full(init = 1.0, shape = *intArrayOf(dim, dim)) + var res = one + repeat(n) { + res = res + one + } + } + + measureAndPrint("Viktor field addition") { + viktorField.run { + var res = one + repeat(n) { + res += 1.0 + } + } + } +} \ No newline at end of file diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 9b446f872..9ac0f6e95 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -9,6 +9,4 @@ dependencies { api(project(":kmath-coroutines")) api(project(":kmath-prob")) api("org.apache.commons:commons-math3:3.6.1") - testImplementation("org.jetbrains.kotlin:kotlin-test") - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt index 370dc646e..3437644ff 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt @@ -2,7 +2,6 @@ package scientifik.kmath.structures import scientifik.kmath.operations.* - interface ExtendedNDField> : NDField, TrigonometricOperations, diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts new file mode 100644 index 000000000..52ee7c497 --- /dev/null +++ b/kmath-viktor/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("scientifik.jvm") +} + +description = "Binding for https://github.com/JetBrains-Research/viktor" + +dependencies { + api(project(":kmath-core")) + api("org.jetbrains.bio:viktor:1.0.1") +} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt new file mode 100644 index 000000000..040eee951 --- /dev/null +++ b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt @@ -0,0 +1,20 @@ +package scientifik.kmath.viktor + +import org.jetbrains.bio.viktor.F64FlatArray +import scientifik.kmath.structures.MutableBuffer + +@Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") +inline class ViktorBuffer(val flatArray: F64FlatArray) : MutableBuffer { + override val size: Int get() = flatArray.size + + override inline fun get(index: Int): Double = flatArray[index] + override inline fun set(index: Int, value: Double) { + flatArray[index] = value + } + + override fun copy(): MutableBuffer { + return ViktorBuffer(flatArray.copy().flatten()) + } + + override fun iterator(): Iterator = flatArray.data.iterator() +} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt new file mode 100644 index 000000000..b572485ff --- /dev/null +++ b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt @@ -0,0 +1,73 @@ +package scientifik.kmath.viktor + +import org.jetbrains.bio.viktor.F64Array +import scientifik.kmath.operations.RealField +import scientifik.kmath.structures.DefaultStrides +import scientifik.kmath.structures.MutableNDStructure +import scientifik.kmath.structures.NDField + +inline class ViktorNDStructure(val f64Buffer: F64Array) : MutableNDStructure { + + override val shape: IntArray get() = f64Buffer.shape + + override fun get(index: IntArray): Double = f64Buffer.get(*index) + + override fun set(index: IntArray, value: Double) { + f64Buffer.set(value = value, indices = *index) + } + + override fun elements(): Sequence> { + return DefaultStrides(shape).indices().map { it to get(it) } + } +} + +fun F64Array.asStructure(): ViktorNDStructure = ViktorNDStructure(this) + +class ViktorNDField(override val shape: IntArray) : NDField { + override val zero: ViktorNDStructure + get() = F64Array.full(init = 0.0, shape = *shape).asStructure() + override val one: ViktorNDStructure + get() = F64Array.full(init = 1.0, shape = *shape).asStructure() + + val strides = DefaultStrides(shape) + + override val elementContext: RealField get() = RealField + + override fun produce(initializer: RealField.(IntArray) -> Double): ViktorNDStructure = F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.initializer(index), indices = *index) + } + }.asStructure() + + override fun map(arg: ViktorNDStructure, transform: RealField.(Double) -> Double): ViktorNDStructure = + F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.transform(arg[index]), indices = *index) + } + }.asStructure() + + override fun mapIndexed( + arg: ViktorNDStructure, + transform: RealField.(index: IntArray, Double) -> Double + ): ViktorNDStructure = F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.transform(index, arg[index]), indices = *index) + } + }.asStructure() + + override fun combine( + a: ViktorNDStructure, + b: ViktorNDStructure, + transform: RealField.(Double, Double) -> Double + ): ViktorNDStructure = F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.transform(a[index], b[index]), indices = *index) + } + }.asStructure() + + override fun ViktorNDStructure.plus(b: ViktorNDStructure): ViktorNDStructure = + (f64Buffer + b.f64Buffer).asStructure() + + override fun ViktorNDStructure.minus(b: ViktorNDStructure): ViktorNDStructure = + (f64Buffer - b.f64Buffer).asStructure() +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index f52edfac5..8c0c4420b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,6 +33,7 @@ include( ":kmath-coroutines", ":kmath-histograms", ":kmath-commons", + ":kmath-viktor", ":kmath-koma", ":kmath-prob", ":kmath-io",