Conceptual design of linear algebra on the way

This commit is contained in:
Alexander Nozik 2018-05-03 11:35:08 +03:00
parent 7c3d561c63
commit 50a65524db
3 changed files with 52 additions and 5 deletions

View File

@ -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<T, E : LinearObject<T>>(val rows: Int, val columns: Int, val field: Field<T>) : Space<E> {
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<T> : SpaceElement<LinearObject<T>> {
val rows: Int
val columns: Int
operator fun get(i: Int, j: Int): T
/**
* Get a transposed object with switched dimensions
*/
fun transpose(): LinearObject<T>
/**
* Perform scalar multiplication (dot) operation, checking dimensions. The argument object and result both could be outside initial space.
*/
operator fun times(other: LinearObject<T>): LinearObject<T>
}

View File

@ -16,8 +16,9 @@ abstract class NDField<T>(val shape: List<Int>, val field: Field<T>) : Field<NDA
*/ */
abstract fun produce(initializer: (List<Int>) -> T): NDArray<T> abstract fun produce(initializer: (List<Int>) -> T): NDArray<T>
override val zero: NDArray<T> override val zero: NDArray<T> by lazy {
get() = produce { this.field.zero } produce { this.field.zero }
}
private fun checkShape(vararg arrays: NDArray<T>) { private fun checkShape(vararg arrays: NDArray<T>) {
arrays.forEach { arrays.forEach {
@ -40,7 +41,7 @@ abstract class NDField<T>(val shape: List<Int>, val field: Field<T>) : Field<NDA
*/ */
override fun multiply(a: NDArray<T>, k: Double): NDArray<T> { override fun multiply(a: NDArray<T>, k: Double): NDArray<T> {
checkShape(a) checkShape(a)
return produce { with(field) {a[it] * k} } return produce { with(field) { a[it] * k } }
} }
override val one: NDArray<T> override val one: NDArray<T>
@ -51,7 +52,7 @@ abstract class NDField<T>(val shape: List<Int>, val field: Field<T>) : Field<NDA
*/ */
override fun multiply(a: NDArray<T>, b: NDArray<T>): NDArray<T> { override fun multiply(a: NDArray<T>, b: NDArray<T>): NDArray<T> {
checkShape(a) 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<T>(val shape: List<Int>, val field: Field<T>) : Field<NDA
*/ */
override fun divide(a: NDArray<T>, b: NDArray<T>): NDArray<T> { override fun divide(a: NDArray<T>, b: NDArray<T>): NDArray<T> {
checkShape(a) checkShape(a)
return produce { with(field) {a[it] / b[it]} } return produce { with(field) { a[it] / b[it] } }
} }
} }

View File

@ -35,6 +35,7 @@ private class RealNDField(shape: List<Int>) : NDField<Double>(shape, DoubleField
override fun produce(initializer: (List<Int>) -> Double): NDArray<Double> { override fun produce(initializer: (List<Int>) -> Double): NDArray<Double> {
//TODO use sparse arrays for large capacities //TODO use sparse arrays for large capacities
val buffer = DoubleBuffer.allocate(capacity) val buffer = DoubleBuffer.allocate(capacity)
//FIXME there could be performance degradation due to iteration procedure. Replace by straight iteration
NDArray.iterateIndexes(shape).forEach { NDArray.iterateIndexes(shape).forEach {
buffer.put(offset(it), initializer(it)) buffer.put(offset(it), initializer(it))
} }