NDArray renamed to NDElement

This commit is contained in:
Alexander Nozik 2018-11-21 09:55:39 +03:00
parent 75bedde1fa
commit 5cd6301f45
6 changed files with 62 additions and 55 deletions

View File

@ -1,12 +1,14 @@
buildscript {
val kotlin_version = "1.3.10"
extra["kotlinVersion"] = "1.3.10"
val kotlinVersion: String by extra
repositories {
jcenter()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4+")
}
}

View File

@ -22,6 +22,10 @@ class PhantomBin(val template: BinTemplate, override val value: Number) : Bin<Do
}
/**
* Immutable histogram with explicit structure for content and additional external bin description.
* Bin search is slow, but full histogram algebra is supported.
*/
class PhantomHistogram(
val bins: Map<BinTemplate, IntArray>,
val data: NDStructure<Double>

View File

@ -225,7 +225,7 @@ class ArrayVectorSpace<T : Any>(
/**
* Member of [ArrayMatrixSpace] which wraps 2-D array
*/
class ArrayMatrix<T : Any> internal constructor(override val context: ArrayMatrixSpace<T>, val array: NDArray<T>) : Matrix<T> {
class ArrayMatrix<T : Any> internal constructor(override val context: ArrayMatrixSpace<T>, val element: NDElement<T>) : Matrix<T> {
constructor(context: ArrayMatrixSpace<T>, initializer: (Int, Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0], list[1]) })
@ -234,32 +234,32 @@ class ArrayMatrix<T : Any> internal constructor(override val context: ArrayMatri
override val columns: Int get() = context.columns
override fun get(i: Int, j: Int): T {
return array[i, j]
return element[i, j]
}
override val self: ArrayMatrix<T> get() = this
}
class ArrayVector<T : Any> internal constructor(override val context: ArrayVectorSpace<T>, val array: NDArray<T>) : Vector<T> {
class ArrayVector<T : Any> internal constructor(override val context: ArrayVectorSpace<T>, val element: NDElement<T>) : Vector<T> {
constructor(context: ArrayVectorSpace<T>, initializer: (Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0]) })
init {
if (context.size != array.shape[0]) {
if (context.size != element.shape[0]) {
error("Array dimension mismatch")
}
}
override fun get(index: Int): T {
return array[index]
return element[index]
}
override val self: ArrayVector<T> get() = this
override fun iterator(): Iterator<T> = (0 until size).map { array[it] }.iterator()
override fun iterator(): Iterator<T> = (0 until size).map { element[it] }.iterator()
override fun copy(): ArrayVector<T> = ArrayVector(context, array)
override fun copy(): ArrayVector<T> = ArrayVector(context, element)
override fun toString(): String = this.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() }
}

View File

@ -1,37 +1,40 @@
package scientifik.kmath.structures
import scientifik.kmath.operations.*
import scientifik.kmath.operations.ExponentialOperations
import scientifik.kmath.operations.ExtendedField
import scientifik.kmath.operations.PowerOperations
import scientifik.kmath.operations.TrigonometricOperations
/**
* NDField that supports [ExtendedField] operations on its elements
*/
class ExtendedNDField<N: Any>(shape: IntArray, override val field: ExtendedField<N>) : NDField<N>(shape, field),
TrigonometricOperations<NDArray<N>>,
PowerOperations<NDArray<N>>,
ExponentialOperations<NDArray<N>> {
TrigonometricOperations<NDElement<N>>,
PowerOperations<NDElement<N>>,
ExponentialOperations<NDElement<N>> {
override fun produceStructure(initializer: (IntArray) -> N): NDStructure<N> {
return genericNdStructure(shape, initializer)
}
override fun power(arg: NDArray<N>, pow: Double): NDArray<N> {
override fun power(arg: NDElement<N>, pow: Double): NDElement<N> {
return arg.transform { d -> with(field){power(d,pow)} }
}
override fun exp(arg: NDArray<N>): NDArray<N> {
override fun exp(arg: NDElement<N>): NDElement<N> {
return arg.transform { d -> with(field){exp(d)} }
}
override fun ln(arg: NDArray<N>): NDArray<N> {
override fun ln(arg: NDElement<N>): NDElement<N> {
return arg.transform { d -> with(field){ln(d)} }
}
override fun sin(arg: NDArray<N>): NDArray<N> {
override fun sin(arg: NDElement<N>): NDElement<N> {
return arg.transform { d -> with(field){sin(d)} }
}
override fun cos(arg: NDArray<N>): NDArray<N> {
override fun cos(arg: NDElement<N>): NDElement<N> {
return arg.transform { d -> with(field){cos(d)} }
}
}

View File

@ -15,7 +15,7 @@ class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : Run
* @param field - operations field defined on individual array element
* @param T the type of the element contained in NDArray
*/
abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field<NDArray<T>> {
abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field<NDElement<T>> {
abstract fun produceStructure(initializer: (IntArray) -> T): NDStructure<T>
@ -23,17 +23,17 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
* Create new instance of NDArray using field shape and given initializer
* The producer takes list of indices as argument and returns contained value
*/
fun produce(initializer: (IntArray) -> T): NDArray<T> = NDArray(this, produceStructure(initializer))
fun produce(initializer: (IntArray) -> T): NDElement<T> = NDElement(this, produceStructure(initializer))
override val zero: NDArray<T> by lazy {
override val zero: NDElement<T> by lazy {
produce { this.field.zero }
}
/**
* Check the shape of given NDArray and throw exception if it does not coincide with shape of the field
*/
private fun checkShape(vararg arrays: NDArray<T>) {
arrays.forEach {
private fun checkShape(vararg elements: NDElement<T>) {
elements.forEach {
if (!shape.contentEquals(it.shape)) {
throw ShapeMismatchException(shape, it.shape)
}
@ -43,7 +43,7 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/**
* Element-by-element addition
*/
override fun add(a: NDArray<T>, b: NDArray<T>): NDArray<T> {
override fun add(a: NDElement<T>, b: NDElement<T>): NDElement<T> {
checkShape(a, b)
return produce { with(field) { a[it] + b[it] } }
}
@ -51,18 +51,18 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/**
* Multiply all elements by cinstant
*/
override fun multiply(a: NDArray<T>, k: Double): NDArray<T> {
override fun multiply(a: NDElement<T>, k: Double): NDElement<T> {
checkShape(a)
return produce { with(field) { a[it] * k } }
}
override val one: NDArray<T>
override val one: NDElement<T>
get() = produce { this.field.one }
/**
* Element-by-element multiplication
*/
override fun multiply(a: NDArray<T>, b: NDArray<T>): NDArray<T> {
override fun multiply(a: NDElement<T>, b: NDElement<T>): NDElement<T> {
checkShape(a)
return produce { with(field) { a[it] * b[it] } }
}
@ -70,7 +70,7 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/**
* Element-by-element division
*/
override fun divide(a: NDArray<T>, b: NDArray<T>): NDArray<T> {
override fun divide(a: NDElement<T>, b: NDElement<T>): NDElement<T> {
checkShape(a)
return produce { with(field) { a[it] / b[it] } }
}
@ -78,12 +78,12 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/**
* Reverse sum operation
*/
operator fun <T> T.plus(arg: NDArray<T>): NDArray<T> = arg + this
operator fun <T> T.plus(arg: NDElement<T>): NDElement<T> = arg + this
/**
* Reverse minus operation
*/
operator fun <T> T.minus(arg: NDArray<T>): NDArray<T> = arg.transform { _, value ->
operator fun <T> T.minus(arg: NDElement<T>): NDElement<T> = arg.transform { _, value ->
with(arg.context.field) {
this@minus - value
}
@ -92,12 +92,12 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/**
* Reverse product operation
*/
operator fun <T> T.times(arg: NDArray<T>): NDArray<T> = arg * this
operator fun <T> T.times(arg: NDElement<T>): NDElement<T> = arg * this
/**
* Reverse division operation
*/
operator fun <T> T.div(arg: NDArray<T>): NDArray<T> = arg.transform { _, value ->
operator fun <T> T.div(arg: NDElement<T>): NDElement<T> = arg.transform { _, value ->
with(arg.context.field) {
this@div / value
}
@ -107,37 +107,37 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/**
* Immutable [NDStructure] coupled to the context. Emulates Python ndarray
*/
class NDArray<T>(override val context: NDField<T>, private val structure: NDStructure<T>) : FieldElement<NDArray<T>, NDField<T>>, NDStructure<T> by structure {
class NDElement<T>(override val context: NDField<T>, private val structure: NDStructure<T>) : FieldElement<NDElement<T>, NDField<T>>, NDStructure<T> by structure {
//TODO ensure structure is immutable
override val self: NDArray<T>
override val self: NDElement<T>
get() = this
inline fun transform(crossinline action: (IntArray, T) -> T): NDArray<T> = context.produce { action(it, get(*it)) }
inline fun transform(crossinline action: (T) -> T): NDArray<T> = context.produce { action(get(*it)) }
inline fun transform(crossinline action: (IntArray, T) -> T): NDElement<T> = context.produce { action(it, get(*it)) }
inline fun transform(crossinline action: (T) -> T): NDElement<T> = context.produce { action(get(*it)) }
}
/**
* Element by element application of any operation on elements to the whole array. Just like in numpy
*/
operator fun <T> Function1<T, T>.invoke(ndArray: NDArray<T>): NDArray<T> = ndArray.transform { _, value -> this(value) }
operator fun <T> Function1<T, T>.invoke(ndElement: NDElement<T>): NDElement<T> = ndElement.transform { _, value -> this(value) }
/* plus and minus */
/**
* Summation operation for [NDArray] and single element
* Summation operation for [NDElement] and single element
*/
operator fun <T> NDArray<T>.plus(arg: T): NDArray<T> = transform { _, value ->
operator fun <T> NDElement<T>.plus(arg: T): NDElement<T> = transform { _, value ->
with(context.field) {
arg + value
}
}
/**
* Subtraction operation between [NDArray] and single element
* Subtraction operation between [NDElement] and single element
*/
operator fun <T> NDArray<T>.minus(arg: T): NDArray<T> = transform { _, value ->
operator fun <T> NDElement<T>.minus(arg: T): NDElement<T> = transform { _, value ->
with(context.field) {
arg - value
}
@ -146,18 +146,18 @@ operator fun <T> NDArray<T>.minus(arg: T): NDArray<T> = transform { _, value ->
/* prod and div */
/**
* Product operation for [NDArray] and single element
* Product operation for [NDElement] and single element
*/
operator fun <T> NDArray<T>.times(arg: T): NDArray<T> = transform { _, value ->
operator fun <T> NDElement<T>.times(arg: T): NDElement<T> = transform { _, value ->
with(context.field) {
arg * value
}
}
/**
* Division operation between [NDArray] and single element
* Division operation between [NDElement] and single element
*/
operator fun <T> NDArray<T>.div(arg: T): NDArray<T> = transform { _, value ->
operator fun <T> NDElement<T>.div(arg: T): NDElement<T> = transform { _, value ->
with(context.field) {
arg / value
}
@ -173,23 +173,23 @@ object NDArrays {
/**
* Create a platform-optimized NDArray of doubles
*/
fun realNDArray(shape: IntArray, initializer: (IntArray) -> Double = { 0.0 }): NDArray<Double> {
fun realNDArray(shape: IntArray, initializer: (IntArray) -> Double = { 0.0 }): NDElement<Double> {
return ExtendedNDField(shape, DoubleField).produce(initializer)
}
fun real1DArray(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDArray<Double> {
fun real1DArray(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDElement<Double> {
return realNDArray(intArrayOf(dim)) { initializer(it[0]) }
}
fun real2DArray(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }): NDArray<Double> {
fun real2DArray(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }): NDElement<Double> {
return realNDArray(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) }
}
fun real3DArray(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }): NDArray<Double> {
fun real3DArray(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }): NDElement<Double> {
return realNDArray(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) }
}
inline fun produceReal(shape: IntArray, block: ExtendedNDField<Double>.() -> NDArray<Double>) = ExtendedNDField(shape, DoubleField).run(block)
inline fun produceReal(shape: IntArray, block: ExtendedNDField<Double>.() -> NDElement<Double>) = ExtendedNDField(shape, DoubleField).run(block)
// /**
// * Simple boxing NDField
@ -199,7 +199,7 @@ object NDArrays {
/**
* Simple boxing NDArray
*/
fun <T : Any> create(field: Field<T>, shape: IntArray, initializer: (IntArray) -> T): NDArray<T> {
fun <T : Any> create(field: Field<T>, shape: IntArray, initializer: (IntArray) -> T): NDElement<T> {
return GenericNDField(shape, field).produce { initializer(it) }
}
}

View File

@ -1,7 +1,5 @@
package scientifik.kmath.structures
import scientifik.kmath.linear.Vector
import scientifik.kmath.linear.VectorL2Norm
import scientifik.kmath.operations.Norm
import scientifik.kmath.structures.NDArrays.produceReal
import scientifik.kmath.structures.NDArrays.real2DArray
@ -53,8 +51,8 @@ class NumberNDFieldTest {
assertEquals(2.0, result[0,2])
}
object L2Norm: Norm<NDArray<out Number>, Double> {
override fun norm(arg: NDArray<out Number>): Double {
object L2Norm: Norm<NDElement<out Number>, Double> {
override fun norm(arg: NDElement<out Number>): Double {
return kotlin.math.sqrt(arg.sumByDouble { it.second.toDouble() })
}
}