diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 3d193efce..f0161afbb 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -26,9 +26,13 @@ dependencies { implementation(project(":kmath-prob")) implementation(project(":kmath-viktor")) implementation(project(":kmath-dimensions")) + implementation(project(":kmath-nd4j")) implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6") implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20") - "benchmarksCompile"(sourceSets.main.get().output + sourceSets.main.get().compileClasspath) //sourceSets.main.output + sourceSets.main.runtimeClasspath + implementation("org.slf4j:slf4j-simple:1.7.30") + implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") + "benchmarksImplementation"("org.jetbrains.kotlinx:kotlinx.benchmark.runtime-jvm:0.2.0-dev-8") + "benchmarksImplementation"(sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath) } // Configure benchmark diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BoxingNDField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BoxingNDField.kt index ddec7bd25..dc65b12c4 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BoxingNDField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BoxingNDField.kt @@ -15,8 +15,9 @@ public class BoxingNDField>( public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer = bufferFactory(size, initializer) - public override fun check(vararg elements: NDBuffer) { - check(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" } + public override fun check(vararg elements: NDBuffer): Array> { + require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" } + return elements } public override fun produce(initializer: F.(IntArray) -> T): BufferedNDFieldElement = diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BufferedNDAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BufferedNDAlgebra.kt index 66b4f19e1..251b1bcb5 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BufferedNDAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/BufferedNDAlgebra.kt @@ -5,8 +5,10 @@ import kscience.kmath.operations.* public interface BufferedNDAlgebra : NDAlgebra> { public val strides: Strides - public override fun check(vararg elements: NDBuffer): Unit = + public override fun check(vararg elements: NDBuffer): Array> { require(elements.all { it.strides == strides }) { ("Strides mismatch") } + return elements + } /** * Convert any [NDStructure] to buffered structure using strides from this context. diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDAlgebra.kt index 35a65c487..4315f0423 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDAlgebra.kt @@ -11,7 +11,7 @@ import kscience.kmath.operations.Space * @property expected the expected shape. * @property actual the actual shape. */ -public class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : +public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") /** diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index f8ca5eed2..fac24504a 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -13,26 +13,33 @@ This subproject implements the following features: > > ```gradle > repositories { +> mavenCentral() > maven { url 'https://dl.bintray.com/mipt-npm/scientifik' } > maven { url 'https://dl.bintray.com/mipt-npm/dev' } > } > > dependencies { > implementation 'scientifik:kmath-nd4j:0.1.4-dev-8' +> implementation 'org.nd4j:nd4j-native-platform:1.0.0-beta7' > } > ``` > **Gradle Kotlin DSL:** > > ```kotlin > repositories { +> mavenCentral() > maven("https://dl.bintray.com/mipt-npm/scientifik") > maven("https://dl.bintray.com/mipt-npm/dev") > } > > dependencies { > implementation("scientifik:kmath-nd4j:0.1.4-dev-8") +> implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") > } > ``` +> +> This distribution also needs an implementation of ND4J API. The ND4J Native Platform is usually the fastest one, so +> it is included to the snippet. > ## Examples diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index 110a2ac30..67569b870 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("scientifik.jvm") + id("ru.mipt.npm.jvm") } dependencies { diff --git a/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayAlgebra.kt new file mode 100644 index 000000000..728ce3773 --- /dev/null +++ b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayAlgebra.kt @@ -0,0 +1,284 @@ +package kscience.kmath.nd4j + +import org.nd4j.linalg.api.ndarray.INDArray +import org.nd4j.linalg.factory.Nd4j +import kscience.kmath.operations.* +import kscience.kmath.structures.* + +/** + * Represents [NDAlgebra] over [INDArrayAlgebra]. + * + * @param T the type of ND-structure element. + * @param C the type of the element context. + */ +public interface INDArrayAlgebra : NDAlgebra> { + /** + * Wraps [INDArray] to [N]. + */ + public fun INDArray.wrap(): INDArrayStructure + + public override fun produce(initializer: C.(IntArray) -> T): INDArrayStructure { + val struct = Nd4j.create(*shape)!!.wrap() + struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } + return struct + } + + public override fun map(arg: INDArrayStructure, transform: C.(T) -> T): INDArrayStructure { + check(arg) + val newStruct = arg.ndArray.dup().wrap() + newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } + return newStruct + } + + public override fun mapIndexed( + arg: INDArrayStructure, + transform: C.(index: IntArray, T) -> T + ): INDArrayStructure { + check(arg) + val new = Nd4j.create(*shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, arg[idx]) } + return new + } + + public override fun combine( + a: INDArrayStructure, + b: INDArrayStructure, + transform: C.(T, T) -> T + ): INDArrayStructure { + check(a, b) + val new = Nd4j.create(*shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) } + return new + } +} + +/** + * Represents [NDSpace] over [INDArrayStructure]. + * + * @param T the type of the element contained in ND structure. + * @param S the type of space of structure elements. + */ +public interface INDArraySpace : NDSpace>, INDArrayAlgebra where S : Space { + public override val zero: INDArrayStructure + get() = Nd4j.zeros(*shape).wrap() + + public override fun add(a: INDArrayStructure, b: INDArrayStructure): INDArrayStructure { + check(a, b) + return a.ndArray.add(b.ndArray).wrap() + } + + public override operator fun INDArrayStructure.minus(b: INDArrayStructure): INDArrayStructure { + check(this, b) + return ndArray.sub(b.ndArray).wrap() + } + + public override operator fun INDArrayStructure.unaryMinus(): INDArrayStructure { + check(this) + return ndArray.neg().wrap() + } + + public override fun multiply(a: INDArrayStructure, k: Number): INDArrayStructure { + check(a) + return a.ndArray.mul(k).wrap() + } + + public override operator fun INDArrayStructure.div(k: Number): INDArrayStructure { + check(this) + return ndArray.div(k).wrap() + } + + public override operator fun INDArrayStructure.times(k: Number): INDArrayStructure { + check(this) + return ndArray.mul(k).wrap() + } +} + +/** + * Represents [NDRing] over [INDArrayStructure]. + * + * @param T the type of the element contained in ND structure. + * @param R the type of ring of structure elements. + */ +public interface INDArrayRing : NDRing>, INDArraySpace where R : Ring { + public override val one: INDArrayStructure + get() = Nd4j.ones(*shape).wrap() + + public override fun multiply(a: INDArrayStructure, b: INDArrayStructure): INDArrayStructure { + check(a, b) + return a.ndArray.mul(b.ndArray).wrap() + } + + public override operator fun INDArrayStructure.minus(b: Number): INDArrayStructure { + check(this) + return ndArray.sub(b).wrap() + } + + public override operator fun INDArrayStructure.plus(b: Number): INDArrayStructure { + check(this) + return ndArray.add(b).wrap() + } + + public override operator fun Number.minus(b: INDArrayStructure): INDArrayStructure { + check(b) + return b.ndArray.rsub(this).wrap() + } +} + +/** + * Represents [NDField] over [INDArrayStructure]. + * + * @param T the type of the element contained in ND structure. + * @param N the type of ND structure. + * @param F the type field of structure elements. + */ +public interface INDArrayField : NDField>, INDArrayRing where F : Field { + public override fun divide(a: INDArrayStructure, b: INDArrayStructure): INDArrayStructure { + check(a, b) + return a.ndArray.div(b.ndArray).wrap() + } + + public override operator fun Number.div(b: INDArrayStructure): INDArrayStructure { + check(b) + return b.ndArray.rdiv(this).wrap() + } +} + +/** + * Represents [NDField] over [INDArrayRealStructure]. + */ +public class RealINDArrayField(public override val shape: IntArray) : INDArrayField { + public override val elementContext: RealField + get() = RealField + + public override fun INDArray.wrap(): INDArrayStructure = check(asRealStructure()) + + public override operator fun INDArrayStructure.div(arg: Double): INDArrayStructure { + check(this) + return ndArray.div(arg).wrap() + } + + public override operator fun INDArrayStructure.plus(arg: Double): INDArrayStructure { + check(this) + return ndArray.add(arg).wrap() + } + + public override operator fun INDArrayStructure.minus(arg: Double): INDArrayStructure { + check(this) + return ndArray.sub(arg).wrap() + } + + public override operator fun INDArrayStructure.times(arg: Double): INDArrayStructure { + check(this) + return ndArray.mul(arg).wrap() + } + + public override operator fun Double.div(arg: INDArrayStructure): INDArrayStructure { + check(arg) + return arg.ndArray.rdiv(this).wrap() + } + + public override operator fun Double.minus(arg: INDArrayStructure): INDArrayStructure { + check(arg) + return arg.ndArray.rsub(this).wrap() + } +} + +/** + * Represents [NDField] over [INDArrayStructure] of [Float]. + */ +public class FloatINDArrayField(public override val shape: IntArray) : INDArrayField { + public override val elementContext: FloatField + get() = FloatField + + public override fun INDArray.wrap(): INDArrayStructure = check(asFloatStructure()) + + public override operator fun INDArrayStructure.div(arg: Float): INDArrayStructure { + check(this) + return ndArray.div(arg).wrap() + } + + public override operator fun INDArrayStructure.plus(arg: Float): INDArrayStructure { + check(this) + return ndArray.add(arg).wrap() + } + + public override operator fun INDArrayStructure.minus(arg: Float): INDArrayStructure { + check(this) + return ndArray.sub(arg).wrap() + } + + public override operator fun INDArrayStructure.times(arg: Float): INDArrayStructure { + check(this) + return ndArray.mul(arg).wrap() + } + + public override operator fun Float.div(arg: INDArrayStructure): INDArrayStructure { + check(arg) + return arg.ndArray.rdiv(this).wrap() + } + + public override operator fun Float.minus(arg: INDArrayStructure): INDArrayStructure { + check(arg) + return arg.ndArray.rsub(this).wrap() + } +} + +/** + * Represents [NDRing] over [INDArrayIntStructure]. + */ +public class IntINDArrayRing(public override val shape: IntArray) : INDArrayRing { + public override val elementContext: IntRing + get() = IntRing + + public override fun INDArray.wrap(): INDArrayStructure = check(asIntStructure()) + + public override operator fun INDArrayStructure.plus(arg: Int): INDArrayStructure { + check(this) + return ndArray.add(arg).wrap() + } + + public override operator fun INDArrayStructure.minus(arg: Int): INDArrayStructure { + check(this) + return ndArray.sub(arg).wrap() + } + + public override operator fun INDArrayStructure.times(arg: Int): INDArrayStructure { + check(this) + return ndArray.mul(arg).wrap() + } + + public override operator fun Int.minus(arg: INDArrayStructure): INDArrayStructure { + check(arg) + return arg.ndArray.rsub(this).wrap() + } +} + +/** + * Represents [NDRing] over [INDArrayStructure] of [Long]. + */ +public class LongINDArrayRing(public override val shape: IntArray) : INDArrayRing { + public override val elementContext: LongRing + get() = LongRing + + public override fun INDArray.wrap(): INDArrayStructure = check(asLongStructure()) + + public override operator fun INDArrayStructure.plus(arg: Long): INDArrayStructure { + check(this) + return ndArray.add(arg).wrap() + } + + public override operator fun INDArrayStructure.minus(arg: Long): INDArrayStructure { + check(this) + return ndArray.sub(arg).wrap() + } + + public override operator fun INDArrayStructure.times(arg: Long): INDArrayStructure { + check(this) + return ndArray.mul(arg).wrap() + } + + public override operator fun Long.minus(arg: INDArrayStructure): INDArrayStructure { + check(arg) + return arg.ndArray.rsub(this).wrap() + } +} diff --git a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayIterators.kt b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayIterators.kt similarity index 94% rename from kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayIterators.kt rename to kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayIterators.kt index 2759f9fdb..9e7ef9e16 100644 --- a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayIterators.kt +++ b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayIterators.kt @@ -1,4 +1,4 @@ -package scientifik.kmath.nd4j +package kscience.kmath.nd4j import org.nd4j.linalg.api.ndarray.INDArray import org.nd4j.linalg.api.shape.Shape @@ -18,7 +18,7 @@ private class INDArrayIndicesIterator(private val iterateOver: INDArray) : Itera } } -internal fun INDArray.indicesIterator(): Iterator = INDArrayIndicesIterator(this) +internal fun INDArray.indicesIterator(): Iterator = INDArrayIndicesIterator(this) private sealed class INDArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { private var i: Int = 0 diff --git a/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayStructures.kt b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayStructures.kt new file mode 100644 index 000000000..5d4e1a979 --- /dev/null +++ b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/INDArrayStructures.kt @@ -0,0 +1,68 @@ +package kscience.kmath.nd4j + +import org.nd4j.linalg.api.ndarray.INDArray +import kscience.kmath.structures.MutableNDStructure +import kscience.kmath.structures.NDStructure + +/** + * Represents a [NDStructure] wrapping an [INDArray] object. + * + * @param T the type of items. + */ +public sealed class INDArrayStructure : MutableNDStructure { + /** + * The wrapped [INDArray]. + */ + public abstract val ndArray: INDArray + + public override val shape: IntArray + get() = ndArray.shape().toIntArray() + + internal abstract fun elementsIterator(): Iterator> + internal fun indicesIterator(): Iterator = ndArray.indicesIterator() + public override fun elements(): Sequence> = Sequence(::elementsIterator) +} + +private data class INDArrayIntStructure(override val ndArray: INDArray) : INDArrayStructure() { + override fun elementsIterator(): Iterator> = ndArray.intIterator() + override fun get(index: IntArray): Int = ndArray.getInt(*index) + override fun set(index: IntArray, value: Int): Unit = run { ndArray.putScalar(index, value) } +} + +/** + * Wraps this [INDArray] to [INDArrayStructure]. + */ +public fun INDArray.asIntStructure(): INDArrayStructure = INDArrayIntStructure(this) + +private data class INDArrayLongStructure(override val ndArray: INDArray) : INDArrayStructure() { + override fun elementsIterator(): Iterator> = ndArray.longIterator() + override fun get(index: IntArray): Long = ndArray.getLong(*index.toLongArray()) + override fun set(index: IntArray, value: Long): Unit = run { ndArray.putScalar(index, value.toDouble()) } +} + +/** + * Wraps this [INDArray] to [INDArrayStructure]. + */ +public fun INDArray.asLongStructure(): INDArrayStructure = INDArrayLongStructure(this) + +private data class INDArrayRealStructure(override val ndArray: INDArray) : INDArrayStructure() { + override fun elementsIterator(): Iterator> = ndArray.realIterator() + override fun get(index: IntArray): Double = ndArray.getDouble(*index) + override fun set(index: IntArray, value: Double): Unit = run { ndArray.putScalar(index, value) } +} + +/** + * Wraps this [INDArray] to [INDArrayStructure]. + */ +public fun INDArray.asRealStructure(): INDArrayStructure = INDArrayRealStructure(this) + +private data class INDArrayFloatStructure(override val ndArray: INDArray) : INDArrayStructure() { + override fun elementsIterator(): Iterator> = ndArray.floatIterator() + override fun get(index: IntArray): Float = ndArray.getFloat(*index) + override fun set(index: IntArray, value: Float): Unit = run { ndArray.putScalar(index, value) } +} + +/** + * Wraps this [INDArray] to [INDArrayStructure]. + */ +public fun INDArray.asFloatStructure(): INDArrayStructure = INDArrayFloatStructure(this) diff --git a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/arrays.kt similarity index 85% rename from kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/arrays.kt rename to kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/arrays.kt index 269fc89c2..798f81c35 100644 --- a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/arrays.kt +++ b/kmath-nd4j/src/main/kotlin/kscience.kmath.nd4j/arrays.kt @@ -1,4 +1,4 @@ -package scientifik.kmath.nd4j +package kscience.kmath.nd4j internal fun IntArray.toLongArray(): LongArray = LongArray(size) { this[it].toLong() } internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toInt() } diff --git a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayAlgebra.kt deleted file mode 100644 index c24e2ece6..000000000 --- a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayAlgebra.kt +++ /dev/null @@ -1,273 +0,0 @@ -package scientifik.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.factory.Nd4j -import scientifik.kmath.operations.* -import scientifik.kmath.structures.* - -/** - * Represents [NDAlgebra] over [INDArrayAlgebra]. - * - * @param T the type of ND-structure element. - * @param C the type of the element context. - * @param N the type of the structure. - */ -interface INDArrayAlgebra : NDAlgebra where N : INDArrayStructure, N : MutableNDStructure { - /** - * Wraps [INDArray] to [N]. - */ - fun INDArray.wrap(): N - - override fun produce(initializer: C.(IntArray) -> T): N { - val struct = Nd4j.create(*shape)!!.wrap() - struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } - return struct - } - - override fun map(arg: N, transform: C.(T) -> T): N { - check(arg) - val newStruct = arg.ndArray.dup().wrap() - newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } - return newStruct - } - - override fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N { - check(arg) - val new = Nd4j.create(*shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, arg[idx]) } - return new - } - - override fun combine(a: N, b: N, transform: C.(T, T) -> T): N { - check(a, b) - val new = Nd4j.create(*shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) } - return new - } -} - -/** - * Represents [NDSpace] over [INDArrayStructure]. - * - * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param S the type of space of structure elements. - */ -interface INDArraySpace : NDSpace, INDArrayAlgebra - where S : Space, N : INDArrayStructure, N : MutableNDStructure { - - override val zero: N - get() = Nd4j.zeros(*shape).wrap() - - override fun add(a: N, b: N): N { - check(a, b) - return a.ndArray.add(b.ndArray).wrap() - } - - override operator fun N.minus(b: N): N { - check(this, b) - return ndArray.sub(b.ndArray).wrap() - } - - override operator fun N.unaryMinus(): N { - check(this) - return ndArray.neg().wrap() - } - - override fun multiply(a: N, k: Number): N { - check(a) - return a.ndArray.mul(k).wrap() - } - - override operator fun N.div(k: Number): N { - check(this) - return ndArray.div(k).wrap() - } - - override operator fun N.times(k: Number): N { - check(this) - return ndArray.mul(k).wrap() - } -} - -/** - * Represents [NDRing] over [INDArrayStructure]. - * - * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param R the type of ring of structure elements. - */ -interface INDArrayRing : NDRing, INDArraySpace - where R : Ring, N : INDArrayStructure, N : MutableNDStructure { - - override val one: N - get() = Nd4j.ones(*shape).wrap() - - override fun multiply(a: N, b: N): N { - check(a, b) - return a.ndArray.mul(b.ndArray).wrap() - } - - override operator fun N.minus(b: Number): N { - check(this) - return ndArray.sub(b).wrap() - } - - override operator fun N.plus(b: Number): N { - check(this) - return ndArray.add(b).wrap() - } - - override operator fun Number.minus(b: N): N { - check(b) - return b.ndArray.rsub(this).wrap() - } -} - -/** - * Represents [NDField] over [INDArrayStructure]. - * - * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param F the type field of structure elements. - */ -interface INDArrayField : NDField, INDArrayRing - where F : Field, N : INDArrayStructure, N : MutableNDStructure { - override fun divide(a: N, b: N): N { - check(a, b) - return a.ndArray.div(b.ndArray).wrap() - } - - override operator fun Number.div(b: N): N { - check(b) - return b.ndArray.rdiv(this).wrap() - } -} - -/** - * Represents [NDField] over [INDArrayRealStructure]. - */ -class RealINDArrayField(override val shape: IntArray, override val elementContext: Field = RealField) : - INDArrayField, INDArrayRealStructure> { - override fun INDArray.wrap(): INDArrayRealStructure = check(asRealStructure()) - override operator fun INDArrayRealStructure.div(arg: Double): INDArrayRealStructure { - check(this) - return ndArray.div(arg).wrap() - } - - override operator fun INDArrayRealStructure.plus(arg: Double): INDArrayRealStructure { - check(this) - return ndArray.add(arg).wrap() - } - - override operator fun INDArrayRealStructure.minus(arg: Double): INDArrayRealStructure { - check(this) - return ndArray.sub(arg).wrap() - } - - override operator fun INDArrayRealStructure.times(arg: Double): INDArrayRealStructure { - check(this) - return ndArray.mul(arg).wrap() - } - - override operator fun Double.div(arg: INDArrayRealStructure): INDArrayRealStructure { - check(arg) - return arg.ndArray.rdiv(this).wrap() - } - - override operator fun Double.minus(arg: INDArrayRealStructure): INDArrayRealStructure { - check(arg) - return arg.ndArray.rsub(this).wrap() - } -} - -/** - * Represents [NDField] over [INDArrayFloatStructure]. - */ -class FloatINDArrayField(override val shape: IntArray, override val elementContext: Field = FloatField) : - INDArrayField, INDArrayFloatStructure> { - override fun INDArray.wrap(): INDArrayFloatStructure = check(asFloatStructure()) - override operator fun INDArrayFloatStructure.div(arg: Float): INDArrayFloatStructure { - check(this) - return ndArray.div(arg).wrap() - } - - override operator fun INDArrayFloatStructure.plus(arg: Float): INDArrayFloatStructure { - check(this) - return ndArray.add(arg).wrap() - } - - override operator fun INDArrayFloatStructure.minus(arg: Float): INDArrayFloatStructure { - check(this) - return ndArray.sub(arg).wrap() - } - - override operator fun INDArrayFloatStructure.times(arg: Float): INDArrayFloatStructure { - check(this) - return ndArray.mul(arg).wrap() - } - - override operator fun Float.div(arg: INDArrayFloatStructure): INDArrayFloatStructure { - check(arg) - return arg.ndArray.rdiv(this).wrap() - } - - override operator fun Float.minus(arg: INDArrayFloatStructure): INDArrayFloatStructure { - check(arg) - return arg.ndArray.rsub(this).wrap() - } -} - -/** - * Represents [NDRing] over [INDArrayIntStructure]. - */ -class IntINDArrayRing(override val shape: IntArray, override val elementContext: Ring = IntRing) : - INDArrayRing, INDArrayIntStructure> { - override fun INDArray.wrap(): INDArrayIntStructure = check(asIntStructure()) - override operator fun INDArrayIntStructure.plus(arg: Int): INDArrayIntStructure { - check(this) - return ndArray.add(arg).wrap() - } - - override operator fun INDArrayIntStructure.minus(arg: Int): INDArrayIntStructure { - check(this) - return ndArray.sub(arg).wrap() - } - - override operator fun INDArrayIntStructure.times(arg: Int): INDArrayIntStructure { - check(this) - return ndArray.mul(arg).wrap() - } - - override operator fun Int.minus(arg: INDArrayIntStructure): INDArrayIntStructure { - check(arg) - return arg.ndArray.rsub(this).wrap() - } -} - -/** - * Represents [NDRing] over [INDArrayLongStructure]. - */ -class LongINDArrayRing(override val shape: IntArray, override val elementContext: Ring = LongRing) : - INDArrayRing, INDArrayLongStructure> { - override fun INDArray.wrap(): INDArrayLongStructure = check(asLongStructure()) - override operator fun INDArrayLongStructure.plus(arg: Long): INDArrayLongStructure { - check(this) - return ndArray.add(arg).wrap() - } - - override operator fun INDArrayLongStructure.minus(arg: Long): INDArrayLongStructure { - check(this) - return ndArray.sub(arg).wrap() - } - - override operator fun INDArrayLongStructure.times(arg: Long): INDArrayLongStructure { - check(this) - return ndArray.mul(arg).wrap() - } - - override operator fun Long.minus(arg: INDArrayLongStructure): INDArrayLongStructure { - check(arg) - return arg.ndArray.rsub(this).wrap() - } -} diff --git a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayStructures.kt b/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayStructures.kt deleted file mode 100644 index 39cefee3d..000000000 --- a/kmath-nd4j/src/main/kotlin/scientifik.kmath.nd4j/INDArrayStructures.kt +++ /dev/null @@ -1,80 +0,0 @@ -package scientifik.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import scientifik.kmath.structures.MutableNDStructure -import scientifik.kmath.structures.NDStructure - -/** - * Represents a [NDStructure] wrapping an [INDArray] object. - * - * @param T the type of items. - */ -sealed class INDArrayStructure : MutableNDStructure { - /** - * The wrapped [INDArray]. - */ - abstract val ndArray: INDArray - - override val shape: IntArray - get() = ndArray.shape().toIntArray() - - internal abstract fun elementsIterator(): Iterator> - internal fun indicesIterator(): Iterator = ndArray.indicesIterator() - override fun elements(): Sequence> = Sequence(::elementsIterator) -} - -/** - * Represents a [NDStructure] over [INDArray] elements of which are accessed as ints. - */ -data class INDArrayIntStructure(override val ndArray: INDArray) : INDArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.intIterator() - override fun get(index: IntArray): Int = ndArray.getInt(*index) - override fun set(index: IntArray, value: Int): Unit = run { ndArray.putScalar(index, value) } -} - -/** - * Wraps this [INDArray] to [INDArrayIntStructure]. - */ -fun INDArray.asIntStructure(): INDArrayIntStructure = INDArrayIntStructure(this) - -/** - * Represents a [NDStructure] over [INDArray] elements of which are accessed as longs. - */ -data class INDArrayLongStructure(override val ndArray: INDArray) : INDArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.longIterator() - override fun get(index: IntArray): Long = ndArray.getLong(*index.toLongArray()) - override fun set(index: IntArray, value: Long): Unit = run { ndArray.putScalar(index, value.toDouble()) } -} - -/** - * Wraps this [INDArray] to [INDArrayLongStructure]. - */ -fun INDArray.asLongStructure(): INDArrayLongStructure = INDArrayLongStructure(this) - -/** - * Represents a [NDStructure] over [INDArray] elements of which are accessed as reals. - */ -data class INDArrayRealStructure(override val ndArray: INDArray) : INDArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.realIterator() - override fun get(index: IntArray): Double = ndArray.getDouble(*index) - override fun set(index: IntArray, value: Double): Unit = run { ndArray.putScalar(index, value) } -} - -/** - * Wraps this [INDArray] to [INDArrayRealStructure]. - */ -fun INDArray.asRealStructure(): INDArrayRealStructure = INDArrayRealStructure(this) - -/** - * Represents a [NDStructure] over [INDArray] elements of which are accessed as floats. - */ -data class INDArrayFloatStructure(override val ndArray: INDArray) : INDArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.floatIterator() - override fun get(index: IntArray): Float = ndArray.getFloat(*index) - override fun set(index: IntArray, value: Float): Unit = run { ndArray.putScalar(index, value) } -} - -/** - * Wraps this [INDArray] to [INDArrayFloatStructure]. - */ -fun INDArray.asFloatStructure(): INDArrayFloatStructure = INDArrayFloatStructure(this) diff --git a/kmath-nd4j/src/test/kotlin/scientifik/kmath/nd4j/INDArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/kscience/kmath/nd4j/INDArrayAlgebraTest.kt similarity index 78% rename from kmath-nd4j/src/test/kotlin/scientifik/kmath/nd4j/INDArrayAlgebraTest.kt rename to kmath-nd4j/src/test/kotlin/kscience/kmath/nd4j/INDArrayAlgebraTest.kt index 4aa40c233..1a4f4c9f3 100644 --- a/kmath-nd4j/src/test/kotlin/scientifik/kmath/nd4j/INDArrayAlgebraTest.kt +++ b/kmath-nd4j/src/test/kotlin/kscience/kmath/nd4j/INDArrayAlgebraTest.kt @@ -1,15 +1,16 @@ -package scientifik.kmath.nd4j +package kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j -import scientifik.kmath.operations.invoke +import kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.fail internal class INDArrayAlgebraTest { @Test fun testProduce() { val res = (RealINDArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } } - val expected = Nd4j.create(2, 2)!!.asRealStructure() + val expected = (Nd4j.create(2, 2) ?: fail()).asRealStructure() expected[intArrayOf(0, 0)] = 0.0 expected[intArrayOf(0, 1)] = 1.0 expected[intArrayOf(1, 0)] = 1.0 @@ -20,7 +21,7 @@ internal class INDArrayAlgebraTest { @Test fun testMap() { val res = (IntINDArrayRing(intArrayOf(2, 2))) { map(one) { it + it * 2 } } - val expected = Nd4j.create(2, 2)!!.asIntStructure() + val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 3 expected[intArrayOf(0, 1)] = 3 expected[intArrayOf(1, 0)] = 3 @@ -31,7 +32,7 @@ internal class INDArrayAlgebraTest { @Test fun testAdd() { val res = (IntINDArrayRing(intArrayOf(2, 2))) { one + 25 } - val expected = Nd4j.create(2, 2)!!.asIntStructure() + val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 26 expected[intArrayOf(0, 1)] = 26 expected[intArrayOf(1, 0)] = 26 diff --git a/kmath-nd4j/src/test/kotlin/scientifik/kmath/nd4j/INDArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/kscience/kmath/nd4j/INDArrayStructureTest.kt similarity index 55% rename from kmath-nd4j/src/test/kotlin/scientifik/kmath/nd4j/INDArrayStructureTest.kt rename to kmath-nd4j/src/test/kotlin/kscience/kmath/nd4j/INDArrayStructureTest.kt index dfede6d32..63426d7f9 100644 --- a/kmath-nd4j/src/test/kotlin/scientifik/kmath/nd4j/INDArrayStructureTest.kt +++ b/kmath-nd4j/src/test/kotlin/kscience/kmath/nd4j/INDArrayStructureTest.kt @@ -1,70 +1,71 @@ -package scientifik.kmath.nd4j +package kscience.kmath.nd4j +import kscience.kmath.structures.get import org.nd4j.linalg.factory.Nd4j -import scientifik.kmath.structures.get import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals +import kotlin.test.fail internal class INDArrayStructureTest { @Test fun testElements() { val nd = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct = INDArrayRealStructure(nd) + val struct = nd.asRealStructure() val res = struct.elements().map(Pair::second).toList() assertEquals(listOf(1.0, 2.0, 3.0), res) } @Test fun testShape() { - val nd = Nd4j.rand(10, 2, 3, 6)!! - val struct = INDArrayLongStructure(nd) + val nd = Nd4j.rand(10, 2, 3, 6) ?: fail() + val struct = nd.asRealStructure() assertEquals(intArrayOf(10, 2, 3, 6).toList(), struct.shape.toList()) } @Test fun testEquals() { - val nd1 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct1 = INDArrayRealStructure(nd1) + val nd1 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() + val struct1 = nd1.asRealStructure() assertEquals(struct1, struct1) - assertNotEquals(struct1, null as INDArrayRealStructure?) - val nd2 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct2 = INDArrayRealStructure(nd2) + assertNotEquals(struct1 as Any?, null) + val nd2 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() + val struct2 = nd2.asRealStructure() assertEquals(struct1, struct2) assertEquals(struct2, struct1) - val nd3 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct3 = INDArrayRealStructure(nd3) + val nd3 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() + val struct3 = nd3.asRealStructure() assertEquals(struct2, struct3) assertEquals(struct1, struct3) } @Test fun testHashCode() { - val nd1 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct1 = INDArrayRealStructure(nd1) - val nd2 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct2 = INDArrayRealStructure(nd2) + val nd1 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))?:fail() + val struct1 = nd1.asRealStructure() + val nd2 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))?:fail() + val struct2 = nd2.asRealStructure() assertEquals(struct1.hashCode(), struct2.hashCode()) } @Test fun testDimension() { val nd = Nd4j.rand(8, 16, 3, 7, 1)!! - val struct = INDArrayFloatStructure(nd) + val struct = nd.asFloatStructure() assertEquals(5, struct.dimension) } @Test fun testGet() { - val nd = Nd4j.rand(10, 2, 3, 6)!! - val struct = INDArrayIntStructure(nd) + val nd = Nd4j.rand(10, 2, 3, 6)?:fail() + val struct = nd.asIntStructure() assertEquals(nd.getInt(0, 0, 0, 0), struct[0, 0, 0, 0]) } @Test fun testSet() { val nd = Nd4j.rand(17, 12, 4, 8)!! - val struct = INDArrayIntStructure(nd) + val struct = nd.asLongStructure() struct[intArrayOf(1, 2, 3, 4)] = 777 assertEquals(777, struct[1, 2, 3, 4]) }