2020-08-08 11:51:04 +03:00
|
|
|
# Algebraic Structures and Algebraic Elements
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an
|
|
|
|
operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up,
|
|
|
|
say `Group<T>`. Next one needs to run the actual operation in the context:
|
2019-01-05 20:15:36 +03:00
|
|
|
|
|
|
|
```kotlin
|
2021-02-18 11:17:28 +03:00
|
|
|
import space.kscience.kmath.operations.*
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2020-08-08 11:51:04 +03:00
|
|
|
val a: T = ...
|
|
|
|
val b: T = ...
|
2021-05-07 15:59:21 +03:00
|
|
|
val group: Group<T> = ...
|
2020-08-08 11:51:04 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
val c = group { a + b }
|
2019-01-05 20:15:36 +03:00
|
|
|
```
|
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in
|
|
|
|
mathematics, one could draw up different operations on same objects. For example, one could use different types of
|
2020-08-08 11:51:04 +03:00
|
|
|
geometry for vectors.
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2020-08-08 11:51:04 +03:00
|
|
|
## Algebraic Structures
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
Primary mathematical contexts have the following hierarchy:
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
`Field <: Ring <: Group <: Algebra`
|
2020-08-08 11:51:04 +03:00
|
|
|
|
|
|
|
These interfaces follow real algebraic structures:
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
- [Group](https://mathworld.wolfram.com/Group.html) defines addition, its identity element (i.e., 0) and additive
|
|
|
|
inverse (-x);
|
|
|
|
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its identity element (i.e., 1);
|
2020-08-08 11:51:04 +03:00
|
|
|
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2021-03-16 21:17:26 +03:00
|
|
|
A typical implementation of `Field<T>` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space<T>`.
|
2019-01-05 20:15:36 +03:00
|
|
|
|
2020-08-08 11:51:04 +03:00
|
|
|
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
|
2021-05-07 15:59:21 +03:00
|
|
|
interface. Also, contexts may have operations, which produce elements outside the context. For example, `Matrix.dot`
|
|
|
|
operation produces a matrix with new dimensions, which can be incompatible with initial matrix in linear operations.
|
2019-02-20 15:24:51 +03:00
|
|
|
|
2020-08-08 11:51:04 +03:00
|
|
|
## Spaces and Fields
|
2019-02-20 15:24:51 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
KMath introduces contexts for builtin algebraic structures:
|
2019-02-20 15:24:51 +03:00
|
|
|
|
|
|
|
```kotlin
|
2021-02-18 11:17:28 +03:00
|
|
|
import space.kscience.kmath.operations.*
|
2020-08-08 11:51:04 +03:00
|
|
|
|
2019-02-20 15:24:51 +03:00
|
|
|
val c1 = Complex(1.0, 2.0)
|
|
|
|
val c2 = ComplexField.i
|
2020-08-08 11:51:04 +03:00
|
|
|
|
2019-02-20 15:24:51 +03:00
|
|
|
val c3 = c1 + c2
|
2020-08-08 11:51:04 +03:00
|
|
|
// or
|
|
|
|
val c3 = ComplexField { c1 + c2 }
|
2019-02-20 15:24:51 +03:00
|
|
|
```
|
|
|
|
|
2020-08-08 11:51:04 +03:00
|
|
|
Also, `ComplexField` features special operations to mix complex and real numbers, for example:
|
2019-02-20 15:24:51 +03:00
|
|
|
|
|
|
|
```kotlin
|
2021-02-18 11:17:28 +03:00
|
|
|
import space.kscience.kmath.operations.*
|
2020-08-08 11:51:04 +03:00
|
|
|
|
2019-02-20 15:24:51 +03:00
|
|
|
val c1 = Complex(1.0, 2.0)
|
2020-08-08 11:51:04 +03:00
|
|
|
val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0)
|
|
|
|
val c3 = ComplexField { c1 - i * 2.0 }
|
2019-02-20 15:24:51 +03:00
|
|
|
```
|
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support
|
|
|
|
that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and
|
2020-08-08 11:51:04 +03:00
|
|
|
[KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates.
|
2019-02-20 15:24:51 +03:00
|
|
|
|
|
|
|
## Nested fields
|
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex
|
2020-08-08 11:51:04 +03:00
|
|
|
elements like so:
|
2019-02-20 15:24:51 +03:00
|
|
|
|
|
|
|
```kotlin
|
2020-08-08 11:51:04 +03:00
|
|
|
val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray ->
|
2019-02-20 15:24:51 +03:00
|
|
|
Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble())
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2020-08-08 11:51:04 +03:00
|
|
|
The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own
|
2021-05-07 15:59:21 +03:00
|
|
|
`ComplexField`. It is important one does not need to create a special n-d class to hold complex numbers and implement
|
|
|
|
operations on it, one just needs to provide a field for its elements.
|
2019-02-20 15:24:51 +03:00
|
|
|
|
2021-05-07 15:59:21 +03:00
|
|
|
**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts
|
|
|
|
like
|
2019-02-20 15:24:51 +03:00
|
|
|
`MemorySpec`.
|