forked from kscience/kmath
Documentation update. Bump version to 0.1.0-dev
This commit is contained in:
parent
25e8e03494
commit
bcc27ac0e0
@ -1,6 +1,5 @@
|
||||
package scientifik.kmath.structures
|
||||
|
||||
import scientifik.kmath.structures.Buffer.Companion.DoubleBufferFactory
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
|
||||
@ -8,7 +7,7 @@ fun main(args: Array<String>) {
|
||||
|
||||
val n = 6000
|
||||
|
||||
val structure = NDStructure.build(intArrayOf(n, n), DoubleBufferFactory) { 1.0 }
|
||||
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||
|
||||
structure.mapToBuffer { it + 1 } // warm-up
|
||||
|
||||
|
@ -28,7 +28,7 @@ allprojects {
|
||||
}
|
||||
|
||||
group = "scientifik"
|
||||
version = "0.0.3-dev"
|
||||
version = "0.1.0-dev"
|
||||
|
||||
repositories {
|
||||
//maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
|
@ -68,3 +68,44 @@ One important distinction between algebra elements and algebra contexts is that
|
||||
The middle type is needed in case algebra members do not store context. For example, it is not possible to add
|
||||
a context to regular `Double`. The element performs automatic conversions from context types and back.
|
||||
One should used context operations in all important places. The performance of element operations is not guaranteed.
|
||||
|
||||
## Spaces and fields
|
||||
|
||||
An obvious first choice of mathematical objects to implement in a context-oriented style are algebraic elements like spaces,
|
||||
rings and fields. Those are located in the `scientifik.kmath.operations.Algebra.kt` file. Alongside common contexts, the file includes definitions for algebra elements like `FieldElement`. A `FieldElement` object
|
||||
stores a reference to the `Field` which contains additive and multiplicative operations, meaning
|
||||
it has one fixed context attached and does not require explicit external context. So those `MathElements` can 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 and real numbers, for example:
|
||||
|
||||
```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) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates.
|
||||
|
||||
## Nested fields
|
||||
|
||||
Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so:
|
||||
|
||||
```kotlin
|
||||
val element = NDElement.complex(shape = intArrayOf(2,2)){ index: IntArray ->
|
||||
Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble())
|
||||
}
|
||||
```
|
||||
|
||||
The `element` in this example is a member of the `Field` of 2-d structures, each element of which is a member of its own
|
||||
`ComplexField`. The important thing is 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.
|
||||
|
||||
**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like
|
||||
`MemorySpec`.
|
||||
|
@ -1 +1,15 @@
|
||||
**TODO**
|
||||
# Buffers
|
||||
Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`).
|
||||
There are different types of buffers:
|
||||
|
||||
* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays.
|
||||
* Boxing `ListBuffer` wrapping a list
|
||||
* Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value
|
||||
* `MemoryBuffer` allows direct allocation of objects in continuous memory block.
|
||||
|
||||
Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions defined in
|
||||
`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the most suitable
|
||||
buffer for given reified type (for types with custom memory buffer it still better to use their own `MemoryBuffer.create()` factory).
|
||||
|
||||
## Buffer performance
|
||||
One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers instead
|
@ -0,0 +1,17 @@
|
||||
# Features
|
||||
|
||||
* [Algebra](./algebra.md) - [Context-based](./contexts.md) operations on different primitives and structures.
|
||||
|
||||
* [NDStructures](./nd-structure.md)
|
||||
|
||||
* [Linear algebra](linear) - Matrices, operations and linear equations solving. To be moved to separate module. Currently supports basic
|
||||
api and multiple library back-ends.
|
||||
|
||||
* [Histograms](./histograms.md) - Multidimensional histogram calculation and operations.
|
||||
|
||||
* [Expressions](./expressions.md)
|
||||
|
||||
* Commons math integration
|
||||
|
||||
* Koma integration
|
||||
|
@ -1,3 +1,7 @@
|
||||
# Nd-structure generation and operations
|
||||
|
||||
**TODO**
|
||||
|
||||
# Performance for n-dimensional structures operations
|
||||
|
||||
One of the most sought after features of mathematical libraries is the high-performance operations on n-dimensional
|
@ -1,40 +0,0 @@
|
||||
## Spaces and fields
|
||||
|
||||
An obvious first choice of mathematical objects to implement in a context-oriented style are algebraic elements like spaces,
|
||||
rings and fields. Those are located in the `scientifik.kmath.operations.Algebra.kt` file. Alongside common contexts, the file includes definitions for algebra elements like `FieldElement`. A `FieldElement` object
|
||||
stores a reference to the `Field` which contains additive and multiplicative operations, meaning
|
||||
it has one fixed context attached and does not require explicit external context. So those `MathElements` can 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 and real numbers, for example:
|
||||
|
||||
```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) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates.
|
||||
|
||||
## Nested fields
|
||||
|
||||
Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so:
|
||||
|
||||
```kotlin
|
||||
val element = NDElement.complex(shape = intArrayOf(2,2)){ index: IntArray ->
|
||||
Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble())
|
||||
}
|
||||
```
|
||||
|
||||
The `element` in this example is a member of the `Field` of 2-d structures, each element of which is a member of its own
|
||||
`ComplexField`. The important thing is 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.
|
||||
|
||||
**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like
|
||||
`BufferSpec`. This feature is in development phase.
|
@ -4,7 +4,6 @@ import scientifik.kmath.operations.RealField
|
||||
import scientifik.kmath.operations.Ring
|
||||
import scientifik.kmath.operations.sum
|
||||
import scientifik.kmath.structures.*
|
||||
import scientifik.kmath.structures.Buffer.Companion.DoubleBufferFactory
|
||||
import scientifik.kmath.structures.Buffer.Companion.boxing
|
||||
import kotlin.math.sqrt
|
||||
|
||||
@ -33,7 +32,7 @@ interface MatrixContext<T : Any> {
|
||||
/**
|
||||
* Non-boxing double matrix
|
||||
*/
|
||||
val real = BufferMatrixContext(RealField, DoubleBufferFactory)
|
||||
val real = BufferMatrixContext(RealField, Buffer.Companion::auto)
|
||||
|
||||
/**
|
||||
* A structured matrix with custom buffer
|
||||
|
@ -42,7 +42,7 @@ interface VectorSpace<T : Any, S : Space<T>> : Space<Point<T>> {
|
||||
* Non-boxing double vector space
|
||||
*/
|
||||
fun real(size: Int): BufferVectorSpace<Double, RealField> {
|
||||
return realSpaceCache.getOrPut(size) { BufferVectorSpace(size, RealField, Buffer.DoubleBufferFactory) }
|
||||
return realSpaceCache.getOrPut(size) { BufferVectorSpace(size, RealField, Buffer.Companion::auto) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,8 @@
|
||||
package scientifik.kmath.operations
|
||||
|
||||
import scientifik.kmath.structures.Buffer
|
||||
import scientifik.kmath.structures.MemoryBuffer
|
||||
import scientifik.kmath.structures.MutableBuffer
|
||||
import scientifik.kmath.structures.ObjectBuffer
|
||||
import scientifik.memory.MemoryReader
|
||||
import scientifik.memory.MemorySpec
|
||||
import scientifik.memory.MemoryWriter
|
||||
@ -88,10 +88,10 @@ data class Complex(val re: Double, val im: Double) : FieldElement<Complex, Compl
|
||||
|
||||
fun Double.toComplex() = Complex(this, 0.0)
|
||||
|
||||
fun Buffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer<Complex> {
|
||||
return ObjectBuffer.create(Complex, size, init)
|
||||
inline fun Buffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer<Complex> {
|
||||
return MemoryBuffer.create(Complex, size, init)
|
||||
}
|
||||
|
||||
fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer<Complex> {
|
||||
return ObjectBuffer.create(Complex, size, init)
|
||||
inline fun MutableBuffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer<Complex> {
|
||||
return MemoryBuffer.create(Complex, size, init)
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package scientifik.kmath.structures
|
||||
|
||||
import scientifik.kmath.operations.Complex
|
||||
import scientifik.kmath.operations.complex
|
||||
|
||||
|
||||
typealias BufferFactory<T> = (Int, (Int) -> T) -> Buffer<T>
|
||||
typealias MutableBufferFactory<T> = (Int, (Int) -> T) -> MutableBuffer<T>
|
||||
@ -43,21 +46,16 @@ interface Buffer<T> {
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T : Any> auto(size: Int, crossinline initializer: (Int) -> T): Buffer<T> {
|
||||
//TODO add resolution based on Annotation or companion resolution
|
||||
return when (T::class) {
|
||||
Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
|
||||
Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as Buffer<T>
|
||||
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T>
|
||||
Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as Buffer<T>
|
||||
Complex::class -> complex(size) { initializer(it) as Complex } as Buffer<T>
|
||||
else -> boxing(size, initializer)
|
||||
}
|
||||
}
|
||||
|
||||
val DoubleBufferFactory: BufferFactory<Double> =
|
||||
{ size, initializer -> DoubleBuffer(DoubleArray(size, initializer)) }
|
||||
val ShortBufferFactory: BufferFactory<Short> =
|
||||
{ size, initializer -> ShortBuffer(ShortArray(size, initializer)) }
|
||||
val IntBufferFactory: BufferFactory<Int> = { size, initializer -> IntBuffer(IntArray(size, initializer)) }
|
||||
val LongBufferFactory: BufferFactory<Long> = { size, initializer -> LongBuffer(LongArray(size, initializer)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import scientifik.memory.*
|
||||
/**
|
||||
* A non-boxing buffer based on [ByteBuffer] storage
|
||||
*/
|
||||
open class ObjectBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
|
||||
open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
|
||||
|
||||
override val size: Int get() = memory.size / spec.objectSize
|
||||
|
||||
@ -18,14 +18,14 @@ open class ObjectBuffer<T : Any>(protected val memory: Memory, protected val spe
|
||||
|
||||
companion object {
|
||||
fun <T : Any> create(spec: MemorySpec<T>, size: Int) =
|
||||
ObjectBuffer(Memory.allocate(size * spec.objectSize), spec)
|
||||
MemoryBuffer(Memory.allocate(size * spec.objectSize), spec)
|
||||
|
||||
inline fun <T : Any> create(
|
||||
spec: MemorySpec<T>,
|
||||
size: Int,
|
||||
crossinline initializer: (Int) -> T
|
||||
): ObjectBuffer<T> =
|
||||
MutableObjectBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||
): MemoryBuffer<T> =
|
||||
MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||
(0 until size).forEach {
|
||||
buffer[it] = initializer(it)
|
||||
}
|
||||
@ -33,16 +33,28 @@ open class ObjectBuffer<T : Any>(protected val memory: Memory, protected val spe
|
||||
}
|
||||
}
|
||||
|
||||
class MutableObjectBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : ObjectBuffer<T>(memory, spec),
|
||||
class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : MemoryBuffer<T>(memory, spec),
|
||||
MutableBuffer<T> {
|
||||
|
||||
private val writer = memory.writer()
|
||||
|
||||
override fun set(index: Int, value: T) = writer.write(spec, spec.objectSize * index, value)
|
||||
|
||||
override fun copy(): MutableBuffer<T> = MutableObjectBuffer(memory.copy(), spec)
|
||||
override fun copy(): MutableBuffer<T> = MutableMemoryBuffer(memory.copy(), spec)
|
||||
|
||||
companion object {
|
||||
fun <T : Any> create(spec: MemorySpec<T>, size: Int) =
|
||||
MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec)
|
||||
|
||||
inline fun <T : Any> create(
|
||||
spec: MemorySpec<T>,
|
||||
size: Int,
|
||||
crossinline initializer: (Int) -> T
|
||||
) =
|
||||
MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||
(0 until size).forEach {
|
||||
buffer[it] = initializer(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package scientifik.memory
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* A specification to read or write custom objects with fixed size in bytes
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user