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 { buildscript {
val kotlin_version = "1.3.10" extra["kotlinVersion"] = "1.3.10"
val kotlinVersion: String by extra
repositories { repositories {
jcenter() jcenter()
} }
dependencies { 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+") 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( class PhantomHistogram(
val bins: Map<BinTemplate, IntArray>, val bins: Map<BinTemplate, IntArray>,
val data: NDStructure<Double> val data: NDStructure<Double>

View File

@ -225,7 +225,7 @@ class ArrayVectorSpace<T : Any>(
/** /**
* Member of [ArrayMatrixSpace] which wraps 2-D array * 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]) }) 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 val columns: Int get() = context.columns
override fun get(i: Int, j: Int): T { override fun get(i: Int, j: Int): T {
return array[i, j] return element[i, j]
} }
override val self: ArrayMatrix<T> get() = this 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]) }) constructor(context: ArrayVectorSpace<T>, initializer: (Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0]) })
init { init {
if (context.size != array.shape[0]) { if (context.size != element.shape[0]) {
error("Array dimension mismatch") error("Array dimension mismatch")
} }
} }
override fun get(index: Int): T { override fun get(index: Int): T {
return array[index] return element[index]
} }
override val self: ArrayVector<T> get() = this 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() } override fun toString(): String = this.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() }
} }

View File

@ -1,37 +1,40 @@
package scientifik.kmath.structures 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 * NDField that supports [ExtendedField] operations on its elements
*/ */
class ExtendedNDField<N: Any>(shape: IntArray, override val field: ExtendedField<N>) : NDField<N>(shape, field), class ExtendedNDField<N: Any>(shape: IntArray, override val field: ExtendedField<N>) : NDField<N>(shape, field),
TrigonometricOperations<NDArray<N>>, TrigonometricOperations<NDElement<N>>,
PowerOperations<NDArray<N>>, PowerOperations<NDElement<N>>,
ExponentialOperations<NDArray<N>> { ExponentialOperations<NDElement<N>> {
override fun produceStructure(initializer: (IntArray) -> N): NDStructure<N> { override fun produceStructure(initializer: (IntArray) -> N): NDStructure<N> {
return genericNdStructure(shape, initializer) 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)} } 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)} } 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)} } 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)} } 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)} } 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 field - operations field defined on individual array element
* @param T the type of the element contained in NDArray * @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> 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 * Create new instance of NDArray using field shape and given initializer
* The producer takes list of indices as argument and returns contained value * 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 } produce { this.field.zero }
} }
/** /**
* Check the shape of given NDArray and throw exception if it does not coincide with shape of the field * 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>) { private fun checkShape(vararg elements: NDElement<T>) {
arrays.forEach { elements.forEach {
if (!shape.contentEquals(it.shape)) { if (!shape.contentEquals(it.shape)) {
throw ShapeMismatchException(shape, 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 * 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) checkShape(a, b)
return produce { with(field) { a[it] + b[it] } } 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 * 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) checkShape(a)
return produce { with(field) { a[it] * k } } return produce { with(field) { a[it] * k } }
} }
override val one: NDArray<T> override val one: NDElement<T>
get() = produce { this.field.one } get() = produce { this.field.one }
/** /**
* Element-by-element multiplication * 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) checkShape(a)
return produce { with(field) { a[it] * b[it] } } 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 * 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) checkShape(a)
return produce { with(field) { a[it] / b[it] } } 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 * 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 * 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) { with(arg.context.field) {
this@minus - value this@minus - value
} }
@ -92,12 +92,12 @@ abstract class NDField<T>(val shape: IntArray, open val field: Field<T>) : Field
/** /**
* Reverse product operation * 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 * 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) { with(arg.context.field) {
this@div / value 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 * 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 //TODO ensure structure is immutable
override val self: NDArray<T> override val self: NDElement<T>
get() = this get() = this
inline fun transform(crossinline action: (IntArray, T) -> T): NDArray<T> = context.produce { action(it, 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): NDArray<T> = context.produce { action(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 * 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 */ /* 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) { with(context.field) {
arg + value 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) { with(context.field) {
arg - value arg - value
} }
@ -146,18 +146,18 @@ operator fun <T> NDArray<T>.minus(arg: T): NDArray<T> = transform { _, value ->
/* prod and div */ /* 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) { with(context.field) {
arg * value 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) { with(context.field) {
arg / value arg / value
} }
@ -173,23 +173,23 @@ object NDArrays {
/** /**
* Create a platform-optimized NDArray of doubles * 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) 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]) } 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]) } 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]) } 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 // * Simple boxing NDField
@ -199,7 +199,7 @@ object NDArrays {
/** /**
* Simple boxing NDArray * 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) } return GenericNDField(shape, field).produce { initializer(it) }
} }
} }

View File

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