forked from kscience/kmath
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>
|
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 {
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user