Conceptual design of linear algebra on the way
This commit is contained in:
parent
7c3d561c63
commit
50a65524db
@ -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>
|
||||
}
|
@ -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>
|
||||
|
||||
override val zero: NDArray<T>
|
||||
get() = produce { this.field.zero }
|
||||
override val zero: NDArray<T> by lazy {
|
||||
produce { this.field.zero }
|
||||
}
|
||||
|
||||
private fun checkShape(vararg arrays: NDArray<T>) {
|
||||
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> {
|
||||
checkShape(a)
|
||||
return produce { with(field) {a[it] * k} }
|
||||
return produce { with(field) { a[it] * k } }
|
||||
}
|
||||
|
||||
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> {
|
||||
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> {
|
||||
checkShape(a)
|
||||
return produce { with(field) {a[it] / b[it]} }
|
||||
return produce { with(field) { a[it] / b[it] } }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ private class RealNDField(shape: List<Int>) : NDField<Double>(shape, DoubleField
|
||||
override fun produce(initializer: (List<Int>) -> Double): NDArray<Double> {
|
||||
//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))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user