pre-0.0.3 #46
@ -36,7 +36,7 @@ fun ComplexOperations.doSomethingWithComplex(c1: Complex, c2: Complex, c3: Compl
|
|||||||
ComplexOperations.doComethingWithComplex(c1,c2,c3)
|
ComplexOperations.doComethingWithComplex(c1,c2,c3)
|
||||||
```
|
```
|
||||||
|
|
||||||
In fact, whole parts of proram could run in a mathematical context or even multiple nested contexts.
|
In fact, whole parts of program could run in a mathematical context or even multiple nested contexts.
|
||||||
|
|
||||||
In `kmath` contexts are responsible not only for operations, but also for raw object creation and advanced features.
|
In `kmath` contexts are responsible not only for operations, but also for raw object creation and advanced features.
|
||||||
|
|
||||||
|
38
doc/operations.md
Normal file
38
doc/operations.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
## Spaces and fields
|
||||||
|
|
||||||
|
An obvious first choice of mathematical objects to implement in context-oriented style are algebra elements like spaces,
|
||||||
|
rings and fields. Those are located in a `scientifik.kmath.operations.Algebra.kt` file. Alongside algebric context
|
||||||
|
themselves, the file includes definitions for algebra elements such as `FieldElement`. A `FieldElement` object
|
||||||
|
stores a reference to the `Field` which contains a additive and multiplicative operations for it, meaning
|
||||||
|
it has one fixed context attached to it and does not require explicit external context. So those `MathElements` could be
|
||||||
|
operated without context:
|
||||||
|
```kotlin
|
||||||
|
val c1 = Complex(1.0, 2.0)
|
||||||
|
val c2 = ComplexField.i
|
||||||
|
val c3 = c1 + c2
|
||||||
|
```
|
||||||
|
`ComplexField` also features special operations to mix complex numbers with real numbers like:
|
||||||
|
```kotlin
|
||||||
|
val c1 = Complex(1.0,2.0)
|
||||||
|
val c2 = ComplexField.run{ c1 - 1.0} //returns [re:0.0, im: 2.0]
|
||||||
|
val c3 = ComplexField.run{ c1 - i*2.0}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: In theory it is possible to add behaviors directly to the context, but currently kotlin syntax does not support
|
||||||
|
that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) for news.
|
||||||
|
|
||||||
|
## Nested fields
|
||||||
|
|
||||||
|
Algebra contexts allow to create more complex structures. For example, it is possible to create a `Matrix` from complex
|
||||||
|
elements like this:
|
||||||
|
```kotlin
|
||||||
|
val element = NDElements.create(field = ComplexField, shape = intArrayOf(2,2)){index: IntArray ->
|
||||||
|
Complex(index[0] - index[1], index[0] + index[1])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `element` in this example is a member of `Field` of 2-d structures, each element of which is a member of its own
|
||||||
|
`ComplexField`. The important thing is that one does not need to create a special nd-structure to hold complex
|
||||||
|
numbers and implements operations on it, one need just to provide a field for its elements.
|
||||||
|
|
||||||
|
**Note**: Fields themselves do not solve problem of JVM boxing, but it is possible to solve with special contexts like
|
||||||
|
`BufferSpec`. This feature is in development phase.
|
@ -18,6 +18,15 @@ object ComplexField : Field<Complex> {
|
|||||||
|
|
||||||
override fun divide(a: Complex, b: Complex): Complex = Complex(a.re * b.re + a.im * b.im, a.re * b.im - a.im * b.re) / b.square
|
override fun divide(a: Complex, b: Complex): Complex = Complex(a.re * b.re + a.im * b.im, a.re * b.im - a.im * b.re) / b.square
|
||||||
|
|
||||||
|
operator fun Double.plus(c: Complex) = this.toComplex() + c
|
||||||
|
|
||||||
|
operator fun Double.minus(c: Complex) = this.toComplex() - c
|
||||||
|
|
||||||
|
operator fun Complex.plus(d: Double) = d + this
|
||||||
|
|
||||||
|
operator fun Complex.minus(d: Double) = this - d.toComplex()
|
||||||
|
|
||||||
|
operator fun Double.times(c: Complex) = Complex(c.re * this, c.im * this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,14 +54,4 @@ data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Compl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Double.toComplex() = Complex(this, 0.0)
|
fun Double.toComplex() = Complex(this, 0.0)
|
||||||
|
|
||||||
operator fun Double.plus(c: Complex) = this.toComplex() + c
|
|
||||||
|
|
||||||
operator fun Double.minus(c: Complex) = this.toComplex() - c
|
|
||||||
|
|
||||||
operator fun Complex.plus(d: Double) = d + this
|
|
||||||
|
|
||||||
operator fun Complex.minus(d: Double) = this - d.toComplex()
|
|
||||||
|
|
||||||
operator fun Double.times(c: Complex) = Complex(c.re * this, c.im * this)
|
|
@ -173,27 +173,27 @@ class GenericNDField<T : Any, F : Field<T>>(shape: IntArray, field: F) : NDField
|
|||||||
|
|
||||||
//typealias NDFieldFactory<T> = (IntArray)->NDField<T>
|
//typealias NDFieldFactory<T> = (IntArray)->NDField<T>
|
||||||
|
|
||||||
object NDArrays {
|
object NDElements {
|
||||||
/**
|
/**
|
||||||
* Create a platform-optimized NDArray of doubles
|
* Create a platform-optimized NDArray of doubles
|
||||||
*/
|
*/
|
||||||
fun realNDArray(shape: IntArray, initializer: DoubleField.(IntArray) -> Double = { 0.0 }): NDElement<Double, DoubleField> {
|
fun realNDElement(shape: IntArray, initializer: DoubleField.(IntArray) -> Double = { 0.0 }): NDElement<Double, DoubleField> {
|
||||||
return ExtendedNDField(shape, DoubleField).produce(initializer)
|
return ExtendedNDField(shape, DoubleField).produce(initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun real1DArray(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDElement<Double, DoubleField> {
|
fun real1DElement(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }): NDElement<Double, DoubleField> {
|
||||||
return realNDArray(intArrayOf(dim)) { initializer(it[0]) }
|
return realNDElement(intArrayOf(dim)) { initializer(it[0]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun real2DArray(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }): NDElement<Double, DoubleField> {
|
fun real2DElement(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }): NDElement<Double, DoubleField> {
|
||||||
return realNDArray(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) }
|
return realNDElement(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun real3DArray(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }): NDElement<Double, DoubleField> {
|
fun real3DElement(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }): NDElement<Double, DoubleField> {
|
||||||
return realNDArray(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) }
|
return realNDElement(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun produceReal(shape: IntArray, block: ExtendedNDField<Double, DoubleField>.() -> NDStructure<Double>): NDElement<Double, DoubleField> {
|
inline fun real(shape: IntArray, block: ExtendedNDField<Double, DoubleField>.() -> NDStructure<Double>): NDElement<Double, DoubleField> {
|
||||||
val field = ExtendedNDField(shape, DoubleField)
|
val field = ExtendedNDField(shape, DoubleField)
|
||||||
return NDStructureElement(field, field.run(block))
|
return NDStructureElement(field, field.run(block))
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package scientifik.kmath.structures
|
package scientifik.kmath.structures
|
||||||
|
|
||||||
import scientifik.kmath.operations.DoubleField
|
import scientifik.kmath.operations.DoubleField
|
||||||
import scientifik.kmath.structures.NDArrays.create
|
import scientifik.kmath.structures.NDElements.create
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package scientifik.kmath.structures
|
package scientifik.kmath.structures
|
||||||
|
|
||||||
import scientifik.kmath.operations.Norm
|
import scientifik.kmath.operations.Norm
|
||||||
import scientifik.kmath.structures.NDArrays.produceReal
|
import scientifik.kmath.structures.NDElements.real
|
||||||
import scientifik.kmath.structures.NDArrays.real2DArray
|
import scientifik.kmath.structures.NDElements.real2DElement
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class NumberNDFieldTest {
|
class NumberNDFieldTest {
|
||||||
val array1 = real2DArray(3, 3) { i, j -> (i + j).toDouble() }
|
val array1 = real2DElement(3, 3) { i, j -> (i + j).toDouble() }
|
||||||
val array2 = real2DArray(3, 3) { i, j -> (i - j).toDouble() }
|
val array2 = real2DElement(3, 3) { i, j -> (i - j).toDouble() }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSum() {
|
fun testSum() {
|
||||||
@ -27,7 +27,7 @@ class NumberNDFieldTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testGeneration() {
|
fun testGeneration() {
|
||||||
|
|
||||||
val array = real2DArray(3, 3) { i, j -> (i * 10 + j).toDouble() }
|
val array = real2DElement(3, 3) { i, j -> (i * 10 + j).toDouble() }
|
||||||
|
|
||||||
for (i in 0..2) {
|
for (i in 0..2) {
|
||||||
for (j in 0..2) {
|
for (j in 0..2) {
|
||||||
@ -64,7 +64,7 @@ class NumberNDFieldTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testInternalContext() {
|
fun testInternalContext() {
|
||||||
produceReal(array1.shape) {
|
real(array1.shape) {
|
||||||
with(L2Norm) {
|
with(L2Norm) {
|
||||||
1 + norm(array1) + exp(array2)
|
1 + norm(array1) + exp(array2)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class LazyNDFieldTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testLazyStructure() {
|
fun testLazyStructure() {
|
||||||
var counter = 0
|
var counter = 0
|
||||||
val regularStructure = NDArrays.create(IntField, intArrayOf(2, 2, 2)) { it[0] + it[1] - it[2] }
|
val regularStructure = NDElements.create(IntField, intArrayOf(2, 2, 2)) { it[0] + it[1] - it[2] }
|
||||||
val result = (regularStructure.lazy() + 2).transform {
|
val result = (regularStructure.lazy() + 2).transform {
|
||||||
counter++
|
counter++
|
||||||
it * it
|
it * it
|
||||||
|
Loading…
Reference in New Issue
Block a user