From 50a65524db2afbd03b298506661fa89a312fa986 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 3 May 2018 11:35:08 +0300 Subject: [PATCH] Conceptual design of linear algebra on the way --- .../kmath/structures/LinearAlgrebra.kt | 45 +++++++++++++++++++ .../scientifik/kmath/structures/NDArray.kt | 11 ++--- .../kmath/structures/RealNDArray.kt | 1 + 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 common/src/main/kotlin/scientifik/kmath/structures/LinearAlgrebra.kt diff --git a/common/src/main/kotlin/scientifik/kmath/structures/LinearAlgrebra.kt b/common/src/main/kotlin/scientifik/kmath/structures/LinearAlgrebra.kt new file mode 100644 index 000000000..3de6d7560 --- /dev/null +++ b/common/src/main/kotlin/scientifik/kmath/structures/LinearAlgrebra.kt @@ -0,0 +1,45 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.Space +import scientifik.kmath.operations.SpaceElement + +abstract class LinearSpace>(val rows: Int, val columns: Int, val field: Field) : Space { + + abstract fun produce(initializer: (Int, Int) -> T): E + + override val zero: E by lazy { + produce { _, _ -> field.zero } + } + + override fun add(a: E, b: E): E { + return produce { i, j -> with(field) { a[i, j] + b[i, j] } } + } + + override fun multiply(a: E, k: Double): E { + //TODO it is possible to implement scalable linear elements which normed values and adjustable scale to save memory and processing poser + return produce { i, j -> with(field) { a[i, j] * k } } + } +} + +/** + * An element of linear algebra with fixed dimension. The linear space allows linear operations on objects of the same dimensions. + * Scalar product operations are performed outside space. + * + * @param T the type of linear object element type. + */ +interface LinearObject : SpaceElement> { + val rows: Int + val columns: Int + operator fun get(i: Int, j: Int): T + + /** + * Get a transposed object with switched dimensions + */ + fun transpose(): LinearObject + + /** + * Perform scalar multiplication (dot) operation, checking dimensions. The argument object and result both could be outside initial space. + */ + operator fun times(other: LinearObject): LinearObject +} diff --git a/common/src/main/kotlin/scientifik/kmath/structures/NDArray.kt b/common/src/main/kotlin/scientifik/kmath/structures/NDArray.kt index 7f27222cc..4e2458fff 100644 --- a/common/src/main/kotlin/scientifik/kmath/structures/NDArray.kt +++ b/common/src/main/kotlin/scientifik/kmath/structures/NDArray.kt @@ -16,8 +16,9 @@ abstract class NDField(val shape: List, val field: Field) : Field) -> T): NDArray - override val zero: NDArray - get() = produce { this.field.zero } + override val zero: NDArray by lazy { + produce { this.field.zero } + } private fun checkShape(vararg arrays: NDArray) { arrays.forEach { @@ -40,7 +41,7 @@ abstract class NDField(val shape: List, val field: Field) : Field, k: Double): NDArray { checkShape(a) - return produce { with(field) {a[it] * k} } + return produce { with(field) { a[it] * k } } } override val one: NDArray @@ -51,7 +52,7 @@ abstract class NDField(val shape: List, val field: Field) : Field, b: NDArray): NDArray { checkShape(a) - return produce { with(field) {a[it] * b[it]} } + return produce { with(field) { a[it] * b[it] } } } /** @@ -59,7 +60,7 @@ abstract class NDField(val shape: List, val field: Field) : Field, b: NDArray): NDArray { checkShape(a) - return produce { with(field) {a[it] / b[it]} } + return produce { with(field) { a[it] / b[it] } } } } diff --git a/jvm/src/main/kotlin/scientifik/kmath/structures/RealNDArray.kt b/jvm/src/main/kotlin/scientifik/kmath/structures/RealNDArray.kt index 3be892ced..217e89033 100644 --- a/jvm/src/main/kotlin/scientifik/kmath/structures/RealNDArray.kt +++ b/jvm/src/main/kotlin/scientifik/kmath/structures/RealNDArray.kt @@ -35,6 +35,7 @@ private class RealNDField(shape: List) : NDField(shape, DoubleField override fun produce(initializer: (List) -> Double): NDArray { //TODO use sparse arrays for large capacities val buffer = DoubleBuffer.allocate(capacity) + //FIXME there could be performance degradation due to iteration procedure. Replace by straight iteration NDArray.iterateIndexes(shape).forEach { buffer.put(offset(it), initializer(it)) }