From 8f5276bdcbe51658729f7828fa8ca7ba0b08f6c0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 23 Nov 2018 14:08:28 +0300 Subject: [PATCH] Broaden scope of VectorSpace to include Points --- .../scientifik/kmath/histogram/Histogram.kt | 13 +- .../kmath/histogram/PhantomHistogram.kt | 41 ++++-- .../scientifik/kmath/linear/LinearAlgrebra.kt | 100 +-------------- .../kotlin/scientifik/kmath/linear/Vector.kt | 118 ++++++++++++++++++ .../scientifik/kmath/structures/Buffers.kt | 2 +- 5 files changed, 151 insertions(+), 123 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt index e143bd90d..f605f6df3 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt @@ -1,6 +1,5 @@ package scientifik.kmath.histogram -import scientifik.kmath.operations.Space import scientifik.kmath.structures.ArrayBuffer import scientifik.kmath.structures.Buffer @@ -55,14 +54,4 @@ fun MutableHistogram.fill(sequence: Iterable>) = sequence /** * Pass a sequence builder into histogram */ -fun MutableHistogram.fill(buider: suspend SequenceScope>.() -> Unit) = fill(sequence(buider).asIterable()) - -/** - * A space to perform arithmetic operations on histograms - */ -interface HistogramSpace, H : Histogram> : Space { - /** - * Rules for performing operations on bins - */ - val binSpace: Space> -} \ No newline at end of file +fun MutableHistogram.fill(buider: suspend SequenceScope>.() -> Unit) = fill(sequence(buider).asIterable()) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/PhantomHistogram.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/PhantomHistogram.kt index 0bd5de0e2..041eccfe2 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/PhantomHistogram.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/histogram/PhantomHistogram.kt @@ -1,23 +1,38 @@ package scientifik.kmath.histogram -import scientifik.kmath.linear.RealVector +import scientifik.kmath.linear.Vector +import scientifik.kmath.operations.Space import scientifik.kmath.structures.NDStructure -class BinTemplate(val center: RealVector, val sizes: RealVector) { - fun contains(vector: Point): Boolean { +class BinTemplate>(val center: Vector, val sizes: Vector) { + fun contains(vector: Point): Boolean { if (vector.size != center.size) error("Dimension mismatch for input vector. Expected ${center.size}, but found ${vector.size}") - return vector.asSequence().mapIndexed { i, value -> value in (center[i] - sizes[i] / 2)..(center[i] + sizes[i] / 2) }.all { it } + val upper = center + sizes/2.0 + val lower = center - sizes/2.0 + return vector.asSequence().mapIndexed { i, value -> + value in lower[i]..upper[i] + }.all { it } } } -class PhantomBin(val template: BinTemplate, override val value: Number) : Bin { +/** + * A space to perform arithmetic operations on histograms + */ +interface HistogramSpace, H : Histogram> : Space { + /** + * Rules for performing operations on bins + */ + val binSpace: Space> +} - override fun contains(vector: Point): Boolean = template.contains(vector) +class PhantomBin>(val template: BinTemplate, override val value: Number) : Bin { + + override fun contains(vector: Point): Boolean = template.contains(vector) override val dimension: Int get() = template.center.size - override val center: Point + override val center: Point get() = template.center } @@ -26,19 +41,19 @@ class PhantomBin(val template: BinTemplate, override val value: Number) : Bin, +class PhantomHistogram>( + val bins: Map, IntArray>, val data: NDStructure -) : Histogram { +) : Histogram> { override val dimension: Int get() = data.dimension - override fun iterator(): Iterator { - return bins.asSequence().map {entry-> PhantomBin(entry.key,data[entry.value]) }.iterator() + override fun iterator(): Iterator> { + return bins.asSequence().map { entry -> PhantomBin(entry.key, data[entry.value]) }.iterator() } - override fun get(point: Point): PhantomBin? { + override fun get(point: Point): PhantomBin? { val template = bins.keys.find { it.contains(point) } return template?.let { PhantomBin(it, data[bins[it]!!]) } } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt index 62852ff5d..9e8692b42 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgrebra.kt @@ -1,7 +1,9 @@ package scientifik.kmath.linear import scientifik.kmath.operations.* -import scientifik.kmath.structures.* +import scientifik.kmath.structures.ExtendedNDField +import scientifik.kmath.structures.GenericNDField +import scientifik.kmath.structures.NDField /** * The space for linear elements. Supports scalar product alongside with standard linear operations. @@ -139,49 +141,7 @@ interface Matrix : SpaceElement, MatrixSpace> { } -/** - * A linear space for vectors - */ -abstract class VectorSpace(val size: Int, val field: Field) : Space> { - abstract fun produce(initializer: (Int) -> T): Vector - - override val zero: Vector by lazy { produce { field.zero } } - - override fun add(a: Vector, b: Vector): Vector = produce { with(field) { a[it] + b[it] } } - - override fun multiply(a: Vector, k: Double): Vector = produce { with(field) { a[it] * k } } -} - - -interface Vector : SpaceElement, VectorSpace>, Buffer, Iterable { - override val size: Int get() = context.size - - companion object { - /** - * Create vector with custom field - */ - fun of(size: Int, field: Field, initializer: (Int) -> T) = - ArrayVector(ArrayVectorSpace(size, field), initializer) - - /** - * Create vector of [Double] - */ - fun ofReal(size: Int, initializer: (Int) -> Double) = - ArrayVector(ArrayVectorSpace(size, DoubleField, realNDFieldFactory), initializer) - - fun ofReal(vararg point: Double) = point.toVector() - - fun equals(v1: Vector<*>, v2: Vector<*>): Boolean { - if (v1 === v2) return true - if (v1.context != v2.context) return false - for (i in 0 until v2.size) { - if (v1[i] != v2[i]) return false - } - return true - } - } -} typealias NDFieldFactory = (IntArray) -> NDField @@ -210,61 +170,7 @@ class ArrayMatrixSpace( } } -class ArrayVectorSpace( - size: Int, - field: Field, - val ndFactory: NDFieldFactory = genericNDFieldFactory(field) -) : VectorSpace(size, field) { - val ndField by lazy { - ndFactory(intArrayOf(size)) - } - override fun produce(initializer: (Int) -> T): Vector = ArrayVector(this, initializer) -} - -/** - * Member of [ArrayMatrixSpace] which wraps 2-D array - */ -class ArrayMatrix internal constructor(override val context: ArrayMatrixSpace, val element: NDElement) : Matrix { - - constructor(context: ArrayMatrixSpace, initializer: (Int, Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0], list[1]) }) - - override val rows: Int get() = context.rows - - override val columns: Int get() = context.columns - - override fun get(i: Int, j: Int): T { - return element[i, j] - } - - override val self: ArrayMatrix get() = this -} - - -class ArrayVector internal constructor(override val context: ArrayVectorSpace, val element: NDElement) : Vector { - - constructor(context: ArrayVectorSpace, initializer: (Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0]) }) - - init { - if (context.size != element.shape[0]) { - error("Array dimension mismatch") - } - } - - override fun get(index: Int): T { - return element[index] - } - - override val self: ArrayVector get() = this - - override fun iterator(): Iterator = (0 until size).map { element[it] }.iterator() - - override fun copy(): ArrayVector = ArrayVector(context, element) - - override fun toString(): String = this.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() } -} - -typealias RealVector = Vector /** * A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt new file mode 100644 index 000000000..70480542f --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/Vector.kt @@ -0,0 +1,118 @@ +package scientifik.kmath.linear + +import scientifik.kmath.histogram.Point +import scientifik.kmath.operations.DoubleField +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.Space +import scientifik.kmath.operations.SpaceElement +import scientifik.kmath.structures.NDElement +import scientifik.kmath.structures.get + +/** + * A linear space for vectors. + * Could be used on any point-like structure + */ +abstract class VectorSpace(val size: Int, val field: Field) : Space> { + + abstract fun produce(initializer: (Int) -> T): Vector + + override val zero: Vector by lazy { produce { field.zero } } + + override fun add(a: Point, b: Point): Vector = produce { with(field) { a[it] + b[it] } } + + override fun multiply(a: Point, k: Double): Vector = produce { with(field) { a[it] * k } } +} + + +/** + * A point coupled to the linear space + */ +interface Vector : SpaceElement, VectorSpace>, Point, Iterable { + override val size: Int get() = context.size + + override operator fun plus(b: Point): Vector = context.add(self, b) + override operator fun minus(b: Point): Vector = context.add(self, context.multiply(b, -1.0)) + override operator fun times(k: Number): Vector = context.multiply(self, k.toDouble()) + override operator fun div(k: Number): Vector = context.multiply(self, 1.0 / k.toDouble()) + + companion object { + /** + * Create vector with custom field + */ + fun of(size: Int, field: Field, initializer: (Int) -> T) = + ArrayVector(ArrayVectorSpace(size, field), initializer) + + /** + * Create vector of [Double] + */ + fun ofReal(size: Int, initializer: (Int) -> Double) = + ArrayVector(ArrayVectorSpace(size, DoubleField, realNDFieldFactory), initializer) + + fun ofReal(vararg point: Double) = point.toVector() + + fun equals(v1: Vector<*>, v2: Vector<*>): Boolean { + if (v1 === v2) return true + if (v1.context != v2.context) return false + for (i in 0 until v2.size) { + if (v1[i] != v2[i]) return false + } + return true + } + } +} + +class ArrayVectorSpace( + size: Int, + field: Field, + val ndFactory: NDFieldFactory = genericNDFieldFactory(field) +) : VectorSpace(size, field) { + val ndField by lazy { + ndFactory(intArrayOf(size)) + } + + override fun produce(initializer: (Int) -> T): Vector = ArrayVector(this, initializer) +} + +/** + * Member of [ArrayMatrixSpace] which wraps 2-D array + */ +class ArrayMatrix internal constructor(override val context: ArrayMatrixSpace, val element: NDElement) : Matrix { + + constructor(context: ArrayMatrixSpace, initializer: (Int, Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0], list[1]) }) + + override val rows: Int get() = context.rows + + override val columns: Int get() = context.columns + + override fun get(i: Int, j: Int): T { + return element[i, j] + } + + override val self: ArrayMatrix get() = this +} + + +class ArrayVector internal constructor(override val context: VectorSpace, val element: NDElement) : Vector { + + constructor(context: ArrayVectorSpace, initializer: (Int) -> T) : this(context, context.ndField.produce { list -> initializer(list[0]) }) + + init { + if (context.size != element.shape[0]) { + error("Array dimension mismatch") + } + } + + override fun get(index: Int): T { + return element[index] + } + + override val self: ArrayVector get() = this + + override fun iterator(): Iterator = (0 until size).map { element[it] }.iterator() + + override fun copy(): ArrayVector = ArrayVector(context, element) + + override fun toString(): String = this.joinToString(prefix = "[", postfix = "]", separator = ", ") { it.toString() } +} + +typealias RealVector = Vector \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt index b68072332..052f9caa4 100644 --- a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -2,7 +2,7 @@ package scientifik.kmath.structures /** - * A generic linear buffer for both primitives and objects + * A generic random access structure for both primitives and objects */ interface Buffer : Iterable {