Even more documentation comments and minor refactorings #144
@ -6,10 +6,10 @@ back-ends. The new operations added as extensions to contexts instead of being m
|
|||||||
|
|
||||||
Two major contexts used for linear algebra and hyper-geometry:
|
Two major contexts used for linear algebra and hyper-geometry:
|
||||||
|
|
||||||
* `VectorSpace` forms a mathematical space on top of array-like structure (`Buffer` and its typealias `Point` used for geometry).
|
* `VectorSpace` forms a mathematical space on top of array-like structure (`Buffer` and its type alias `Point` used for geometry).
|
||||||
|
|
||||||
* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement
|
* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement
|
||||||
`Space` interface (it is not possible to create zero element without knowing the matrix size).
|
`Space` interface (it is impossible to create zero element without knowing the matrix size).
|
||||||
|
|
||||||
## Vector spaces
|
## Vector spaces
|
||||||
|
|
||||||
|
@ -28,7 +28,9 @@ dependencies {
|
|||||||
implementation(project(":kmath-dimensions"))
|
implementation(project(":kmath-dimensions"))
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6")
|
implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
|
implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
|
||||||
"benchmarksCompile"(sourceSets.main.get().output + sourceSets.main.get().compileClasspath) //sourceSets.main.output + sourceSets.main.runtimeClasspath
|
implementation("org.slf4j:slf4j-simple:1.7.30")
|
||||||
|
"benchmarksImplementation"("org.jetbrains.kotlinx:kotlinx.benchmark.runtime-jvm:0.2.0-dev-8")
|
||||||
|
"benchmarksImplementation"(sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure benchmark
|
// Configure benchmark
|
||||||
|
@ -6,7 +6,7 @@ import org.openjdk.jmh.annotations.State
|
|||||||
import java.nio.IntBuffer
|
import java.nio.IntBuffer
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
class ArrayBenchmark {
|
internal class ArrayBenchmark {
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun benchmarkArrayRead() {
|
fun benchmarkArrayRead() {
|
||||||
var res = 0
|
var res = 0
|
||||||
|
@ -7,8 +7,7 @@ import org.openjdk.jmh.annotations.Scope
|
|||||||
import org.openjdk.jmh.annotations.State
|
import org.openjdk.jmh.annotations.State
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
class BufferBenchmark {
|
internal class BufferBenchmark {
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun genericRealBufferReadWrite() {
|
fun genericRealBufferReadWrite() {
|
||||||
val buffer = RealBuffer(size) { it.toDouble() }
|
val buffer = RealBuffer(size) { it.toDouble() }
|
||||||
|
@ -7,7 +7,7 @@ import org.openjdk.jmh.annotations.Scope
|
|||||||
import org.openjdk.jmh.annotations.State
|
import org.openjdk.jmh.annotations.State
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
class NDFieldBenchmark {
|
internal class NDFieldBenchmark {
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun autoFieldAdd() {
|
fun autoFieldAdd() {
|
||||||
bufferedField {
|
bufferedField {
|
||||||
|
@ -9,7 +9,7 @@ import org.openjdk.jmh.annotations.Scope
|
|||||||
import org.openjdk.jmh.annotations.State
|
import org.openjdk.jmh.annotations.State
|
||||||
|
|
||||||
@State(Scope.Benchmark)
|
@State(Scope.Benchmark)
|
||||||
class ViktorBenchmark {
|
internal class ViktorBenchmark {
|
||||||
final val dim: Int = 1000
|
final val dim: Int = 1000
|
||||||
final val n: Int = 100
|
final val n: Int = 100
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class ViktorBenchmark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
fun realdFieldLog() {
|
fun realFieldLog() {
|
||||||
realField {
|
realField {
|
||||||
val fortyTwo = produce { 42.0 }
|
val fortyTwo = produce { 42.0 }
|
||||||
var res = one
|
var res = one
|
||||||
|
@ -14,11 +14,10 @@ private fun runChain(): Duration {
|
|||||||
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
|
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
|
||||||
val normal = Distribution.normal(NormalSamplerMethod.Ziggurat)
|
val normal = Distribution.normal(NormalSamplerMethod.Ziggurat)
|
||||||
val chain = normal.sample(generator) as BlockingRealChain
|
val chain = normal.sample(generator) as BlockingRealChain
|
||||||
|
|
||||||
val startTime = Instant.now()
|
val startTime = Instant.now()
|
||||||
var sum = 0.0
|
var sum = 0.0
|
||||||
repeat(10000001) { counter ->
|
|
||||||
|
|
||||||
|
repeat(10000001) { counter ->
|
||||||
sum += chain.nextDouble()
|
sum += chain.nextDouble()
|
||||||
|
|
||||||
if (counter % 100000 == 0) {
|
if (counter % 100000 == 0) {
|
||||||
@ -27,6 +26,7 @@ private fun runChain(): Duration {
|
|||||||
println("Chain sampler completed $counter elements in $duration: $meanValue")
|
println("Chain sampler completed $counter elements in $duration: $meanValue")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Duration.between(startTime, Instant.now())
|
return Duration.between(startTime, Instant.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +34,9 @@ private fun runDirect(): Duration {
|
|||||||
val provider = RandomSource.create(RandomSource.MT, 123L)
|
val provider = RandomSource.create(RandomSource.MT, 123L)
|
||||||
val sampler = ZigguratNormalizedGaussianSampler(provider)
|
val sampler = ZigguratNormalizedGaussianSampler(provider)
|
||||||
val startTime = Instant.now()
|
val startTime = Instant.now()
|
||||||
|
|
||||||
var sum = 0.0
|
var sum = 0.0
|
||||||
repeat(10000001) { counter ->
|
|
||||||
|
|
||||||
|
repeat(10000001) { counter ->
|
||||||
sum += sampler.sample()
|
sum += sampler.sample()
|
||||||
|
|
||||||
if (counter % 100000 == 0) {
|
if (counter % 100000 == 0) {
|
||||||
@ -46,6 +45,7 @@ private fun runDirect(): Duration {
|
|||||||
println("Direct sampler completed $counter elements in $duration: $meanValue")
|
println("Direct sampler completed $counter elements in $duration: $meanValue")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Duration.between(startTime, Instant.now())
|
return Duration.between(startTime, Instant.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,14 +54,8 @@ private fun runDirect(): Duration {
|
|||||||
*/
|
*/
|
||||||
fun main() {
|
fun main() {
|
||||||
runBlocking(Dispatchers.Default) {
|
runBlocking(Dispatchers.Default) {
|
||||||
val chainJob = async {
|
val chainJob = async { runChain() }
|
||||||
runChain()
|
val directJob = async { runDirect() }
|
||||||
}
|
|
||||||
|
|
||||||
val directJob = async {
|
|
||||||
runDirect()
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Chain: ${chainJob.await()}")
|
println("Chain: ${chainJob.await()}")
|
||||||
println("Direct: ${directJob.await()}")
|
println("Direct: ${directJob.await()}")
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import kscience.kmath.prob.Distribution
|
|||||||
import kscience.kmath.prob.RandomGenerator
|
import kscience.kmath.prob.RandomGenerator
|
||||||
import kscience.kmath.prob.normal
|
import kscience.kmath.prob.normal
|
||||||
|
|
||||||
data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
|
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
|
||||||
|
|
||||||
fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
|
private fun Chain<Double>.mean(): Chain<Double> = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
|
||||||
val next = chain.next()
|
val next = chain.next()
|
||||||
num++
|
num++
|
||||||
value += next
|
value += next
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package kscience.kmath.operations
|
package kscience.kmath.operations
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val res = BigIntField {
|
val res = BigIntField { number(1) * 2 }
|
||||||
number(1) * 2
|
|
||||||
}
|
|
||||||
println("bigint:$res")
|
println("bigint:$res")
|
||||||
}
|
}
|
@ -4,11 +4,9 @@ import kotlin.system.measureTimeMillis
|
|||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
|
|
||||||
val array = DoubleArray(n * n) { 1.0 }
|
val array = DoubleArray(n * n) { 1.0 }
|
||||||
val buffer = RealBuffer(array)
|
val buffer = RealBuffer(array)
|
||||||
val strides = DefaultStrides(intArrayOf(n, n))
|
val strides = DefaultStrides(intArrayOf(n, n))
|
||||||
|
|
||||||
val structure = BufferNDStructure(strides, buffer)
|
val structure = BufferNDStructure(strides, buffer)
|
||||||
|
|
||||||
measureTimeMillis {
|
measureTimeMillis {
|
||||||
|
@ -4,24 +4,17 @@ import kotlin.system.measureTimeMillis
|
|||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val n = 6000
|
val n = 6000
|
||||||
|
|
||||||
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
|
||||||
|
|
||||||
structure.mapToBuffer { it + 1 } // warm-up
|
structure.mapToBuffer { it + 1 } // warm-up
|
||||||
|
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
|
||||||
val time1 = measureTimeMillis {
|
|
||||||
val res = structure.mapToBuffer { it + 1 }
|
|
||||||
}
|
|
||||||
println("Structure mapping finished in $time1 millis")
|
println("Structure mapping finished in $time1 millis")
|
||||||
|
|
||||||
val array = DoubleArray(n * n) { 1.0 }
|
val array = DoubleArray(n * n) { 1.0 }
|
||||||
|
|
||||||
val time2 = measureTimeMillis {
|
val time2 = measureTimeMillis {
|
||||||
val target = DoubleArray(n * n)
|
val target = DoubleArray(n * n)
|
||||||
val res = array.forEachIndexed { index, value ->
|
val res = array.forEachIndexed { index, value -> target[index] = value + 1 }
|
||||||
target[index] = value + 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Array mapping finished in $time2 millis")
|
println("Array mapping finished in $time2 millis")
|
||||||
|
|
||||||
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
|
||||||
|
@ -6,7 +6,7 @@ import kscience.kmath.dimensions.DMatrixContext
|
|||||||
import kscience.kmath.dimensions.Dimension
|
import kscience.kmath.dimensions.Dimension
|
||||||
import kscience.kmath.operations.RealField
|
import kscience.kmath.operations.RealField
|
||||||
|
|
||||||
fun DMatrixContext<Double, RealField>.simple() {
|
private fun DMatrixContext<Double, RealField>.simple() {
|
||||||
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }
|
val m1 = produce<D2, D3> { i, j -> (i + j).toDouble() }
|
||||||
val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
|
val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
|
||||||
|
|
||||||
@ -14,12 +14,11 @@ fun DMatrixContext<Double, RealField>.simple() {
|
|||||||
m1.transpose() + m2
|
m1.transpose() + m2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object D5 : Dimension {
|
||||||
object D5 : Dimension {
|
|
||||||
override val dim: UInt = 5u
|
override val dim: UInt = 5u
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DMatrixContext<Double, RealField>.custom() {
|
private fun DMatrixContext<Double, RealField>.custom() {
|
||||||
val m1 = produce<D2, D5> { i, j -> (i + j).toDouble() }
|
val m1 = produce<D2, D5> { i, j -> (i + j).toDouble() }
|
||||||
val m2 = produce<D5, D2> { i, j -> (i - j).toDouble() }
|
val m2 = produce<D5, D2> { i, j -> (i - j).toDouble() }
|
||||||
val m3 = produce<D2, D2> { i, j -> (i - j).toDouble() }
|
val m3 = produce<D2, D2> { i, j -> (i - j).toDouble() }
|
||||||
|
@ -9,14 +9,17 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure
|
|||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A field wrapping commons-math derivative structures
|
* A field over commons-math [DerivativeStructure].
|
||||||
|
*
|
||||||
|
* @property order The derivation order.
|
||||||
|
* @property parameters The map of free parameters.
|
||||||
*/
|
*/
|
||||||
public class DerivativeStructureField(
|
public class DerivativeStructureField(
|
||||||
public val order: Int,
|
public val order: Int,
|
||||||
public val parameters: Map<String, Double>
|
public val parameters: Map<String, Double>
|
||||||
) : ExtendedField<DerivativeStructure> {
|
) : ExtendedField<DerivativeStructure> {
|
||||||
public override val zero: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size) }
|
public override val zero: DerivativeStructure by lazy { DerivativeStructure(parameters.size, order) }
|
||||||
public override val one: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size, 1.0) }
|
public override val one: DerivativeStructure by lazy { DerivativeStructure(parameters.size, order, 1.0) }
|
||||||
|
|
||||||
private val variables: Map<String, DerivativeStructure> = parameters.mapValues { (key, value) ->
|
private val variables: Map<String, DerivativeStructure> = parameters.mapValues { (key, value) ->
|
||||||
DerivativeStructure(parameters.size, order, parameters.keys.indexOf(key), value)
|
DerivativeStructure(parameters.size, order, parameters.keys.indexOf(key), value)
|
||||||
|
@ -3,6 +3,7 @@ package kscience.kmath.operations
|
|||||||
import kscience.kmath.structures.Buffer
|
import kscience.kmath.structures.Buffer
|
||||||
import kscience.kmath.structures.MemoryBuffer
|
import kscience.kmath.structures.MemoryBuffer
|
||||||
import kscience.kmath.structures.MutableBuffer
|
import kscience.kmath.structures.MutableBuffer
|
||||||
|
import kscience.kmath.structures.MutableMemoryBuffer
|
||||||
import kscience.memory.MemoryReader
|
import kscience.memory.MemoryReader
|
||||||
import kscience.memory.MemorySpec
|
import kscience.memory.MemorySpec
|
||||||
import kscience.memory.MemoryWriter
|
import kscience.memory.MemoryWriter
|
||||||
@ -177,10 +178,10 @@ public data class Complex(val re: Double, val im: Double) : FieldElement<Complex
|
|||||||
override fun compareTo(other: Complex): Int = r.compareTo(other.r)
|
override fun compareTo(other: Complex): Int = r.compareTo(other.r)
|
||||||
|
|
||||||
public companion object : MemorySpec<Complex> {
|
public companion object : MemorySpec<Complex> {
|
||||||
override val objectSize: Int = 16
|
override val objectSize: Int
|
||||||
|
get() = 16
|
||||||
|
|
||||||
override fun MemoryReader.read(offset: Int): Complex =
|
override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8))
|
||||||
Complex(readDouble(offset), readDouble(offset + 8))
|
|
||||||
|
|
||||||
override fun MemoryWriter.write(offset: Int, value: Complex) {
|
override fun MemoryWriter.write(offset: Int, value: Complex) {
|
||||||
writeDouble(offset, value.re)
|
writeDouble(offset, value.re)
|
||||||
@ -197,8 +198,16 @@ public data class Complex(val re: Double, val im: Double) : FieldElement<Complex
|
|||||||
*/
|
*/
|
||||||
public fun Number.toComplex(): Complex = Complex(this, 0.0)
|
public fun Number.toComplex(): Complex = Complex(this, 0.0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the
|
||||||
|
* specified [init] function.
|
||||||
|
*/
|
||||||
public inline fun Buffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer<Complex> =
|
public inline fun Buffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer<Complex> =
|
||||||
MemoryBuffer.create(Complex, size, init)
|
MemoryBuffer.create(Complex, size, init)
|
||||||
|
|
||||||
public inline fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer<Complex> =
|
/**
|
||||||
MemoryBuffer.create(Complex, size, init)
|
* Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the
|
||||||
|
* specified [init] function.
|
||||||
|
*/
|
||||||
|
public inline fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): MutableBuffer<Complex> =
|
||||||
|
MutableMemoryBuffer.create(Complex, size, init)
|
||||||
|
@ -15,8 +15,9 @@ public class BoxingNDField<T, F : Field<T>>(
|
|||||||
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
|
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||||
bufferFactory(size, initializer)
|
bufferFactory(size, initializer)
|
||||||
|
|
||||||
public override fun check(vararg elements: NDBuffer<T>) {
|
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
||||||
check(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }
|
require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }
|
||||||
|
return elements
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun produce(initializer: F.(IntArray) -> T): BufferedNDFieldElement<T, F> =
|
public override fun produce(initializer: F.(IntArray) -> T): BufferedNDFieldElement<T, F> =
|
||||||
@ -75,6 +76,6 @@ public inline fun <T : Any, F : Field<T>, R> F.nd(
|
|||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
action: NDField<T, F, *>.() -> R
|
action: NDField<T, F, *>.() -> R
|
||||||
): R {
|
): R {
|
||||||
val ndfield: BoxingNDField<T, F> = NDField.boxing(this, *shape, bufferFactory = bufferFactory)
|
val ndfield = NDField.boxing(this, *shape, bufferFactory = bufferFactory)
|
||||||
return ndfield.action()
|
return ndfield.action()
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@ public class BoxingNDRing<T, R : Ring<T>>(
|
|||||||
|
|
||||||
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
|
public fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer<T> = bufferFactory(size, initializer)
|
||||||
|
|
||||||
override fun check(vararg elements: NDBuffer<T>) {
|
override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
||||||
require(elements.all { it.strides == strides }) { "Element strides are not the same as context strides" }
|
if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides")
|
||||||
|
return elements
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun produce(initializer: R.(IntArray) -> T): BufferedNDRingElement<T, R> =
|
override fun produce(initializer: R.(IntArray) -> T): BufferedNDRingElement<T, R> =
|
||||||
|
@ -5,8 +5,10 @@ import kscience.kmath.operations.*
|
|||||||
public interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
|
public interface BufferedNDAlgebra<T, C> : NDAlgebra<T, C, NDBuffer<T>> {
|
||||||
public val strides: Strides
|
public val strides: Strides
|
||||||
|
|
||||||
public override fun check(vararg elements: NDBuffer<T>): Unit =
|
public override fun check(vararg elements: NDBuffer<T>): Array<out NDBuffer<T>> {
|
||||||
require(elements.all { it.strides == strides }) { ("Strides mismatch") }
|
require(elements.all { it.strides == strides }) { "Strides mismatch" }
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert any [NDStructure] to buffered structure using strides from this context.
|
* Convert any [NDStructure] to buffered structure using strides from this context.
|
||||||
|
@ -46,35 +46,48 @@ public interface Buffer<T> {
|
|||||||
asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
|
asSequence().mapIndexed { index, value -> value == other[index] }.all { it }
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer {
|
/**
|
||||||
val array = DoubleArray(size) { initializer(it) }
|
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
return RealBuffer(array)
|
* [initializer] function.
|
||||||
}
|
*/
|
||||||
|
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
|
||||||
|
RealBuffer(size) { initializer(it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a boxing buffer of given type
|
* Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
|
||||||
|
* specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
|
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||||
ListBuffer(List(size, initializer))
|
ListBuffer(List(size, initializer))
|
||||||
|
|
||||||
|
// TODO add resolution based on Annotation or companion resolution
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
|
||||||
|
* [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
|
*
|
||||||
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <T : Any> auto(type: KClass<T>, size: Int, crossinline initializer: (Int) -> T): Buffer<T> {
|
public inline fun <T : Any> auto(type: KClass<T>, size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||||
//TODO add resolution based on Annotation or companion resolution
|
when (type) {
|
||||||
return when (type) {
|
Double::class -> RealBuffer(size) { initializer(it) as Double } as Buffer<T>
|
||||||
Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer<T>
|
Short::class -> ShortBuffer(size) { initializer(it) as Short } as Buffer<T>
|
||||||
Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as Buffer<T>
|
Int::class -> IntBuffer(size) { initializer(it) as Int } as Buffer<T>
|
||||||
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer<T>
|
Long::class -> LongBuffer(size) { initializer(it) as Long } as Buffer<T>
|
||||||
Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as Buffer<T>
|
Float::class -> FloatBuffer(size) { initializer(it) as Float } as Buffer<T>
|
||||||
Complex::class -> complex(size) { initializer(it) as Complex } as Buffer<T>
|
Complex::class -> complex(size) { initializer(it) as Complex } as Buffer<T>
|
||||||
else -> boxing(size, initializer)
|
else -> boxing(size, initializer)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create most appropriate immutable buffer for given type avoiding boxing wherever possible
|
* Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer],
|
||||||
|
* [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
|
*
|
||||||
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <reified T : Any> auto(size: Int, crossinline initializer: (Int) -> T): Buffer<T> =
|
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): Buffer<T> =
|
||||||
auto(T::class, size, initializer)
|
auto(T::class, size, initializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,25 +130,40 @@ public interface MutableBuffer<T> : Buffer<T> {
|
|||||||
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
public inline fun <T> boxing(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||||
MutableListBuffer(MutableList(size, initializer))
|
MutableListBuffer(MutableList(size, initializer))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
|
||||||
|
* ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
|
*
|
||||||
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
public inline fun <T : Any> auto(type: KClass<out T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||||
when (type) {
|
when (type) {
|
||||||
Double::class -> RealBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer<T>
|
Double::class -> RealBuffer(size) { initializer(it) as Double } as MutableBuffer<T>
|
||||||
Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as MutableBuffer<T>
|
Short::class -> ShortBuffer(size) { initializer(it) as Short } as MutableBuffer<T>
|
||||||
Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer<T>
|
Int::class -> IntBuffer(size) { initializer(it) as Int } as MutableBuffer<T>
|
||||||
Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as MutableBuffer<T>
|
Float::class -> FloatBuffer(size) { initializer(it) as Float } as MutableBuffer<T>
|
||||||
|
Long::class -> LongBuffer(size) { initializer(it) as Long } as MutableBuffer<T>
|
||||||
|
Complex::class -> complex(size) { initializer(it) as Complex } as MutableBuffer<T>
|
||||||
else -> boxing(size, initializer)
|
else -> boxing(size, initializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create most appropriate mutable buffer for given type avoiding boxing wherever possible
|
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
|
||||||
|
* ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise.
|
||||||
|
*
|
||||||
|
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
public inline fun <reified T : Any> auto(size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
||||||
auto(T::class, size, initializer)
|
auto(T::class, size, initializer)
|
||||||
|
|
||||||
public val real: MutableBufferFactory<Double> =
|
/**
|
||||||
{ size, initializer -> RealBuffer(DoubleArray(size) { initializer(it) }) }
|
* Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
|
||||||
|
* [initializer] function.
|
||||||
|
*/
|
||||||
|
public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
|
||||||
|
RealBuffer(size) { initializer(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) :
|
|||||||
public inline fun <T : Any> create(
|
public inline fun <T : Any> create(
|
||||||
spec: MemorySpec<T>,
|
spec: MemorySpec<T>,
|
||||||
size: Int,
|
size: Int,
|
||||||
crossinline initializer: (Int) -> T
|
initializer: (Int) -> T
|
||||||
): MutableMemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
): MutableMemoryBuffer<T> = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer ->
|
||||||
(0 until size).forEach { buffer[it] = initializer(it) }
|
(0 until size).forEach { buffer[it] = initializer(it) }
|
||||||
}
|
}
|
||||||
|
@ -6,49 +6,77 @@ import kscience.kmath.operations.Ring
|
|||||||
import kscience.kmath.operations.Space
|
import kscience.kmath.operations.Space
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An exception is thrown when the expected ans actual shape of NDArray differs
|
* An exception is thrown when the expected ans actual shape of NDArray differs.
|
||||||
|
*
|
||||||
|
* @property expected the expected shape.
|
||||||
|
* @property actual the actual shape.
|
||||||
*/
|
*/
|
||||||
public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : RuntimeException()
|
public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) :
|
||||||
|
RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base interface for all nd-algebra implementations
|
* The base interface for all ND-algebra implementations.
|
||||||
* @param T the type of nd-structure element
|
*
|
||||||
* @param C the type of the element context
|
* @param T the type of ND-structure element.
|
||||||
* @param N the type of the structure
|
* @param C the type of the element context.
|
||||||
|
* @param N the type of the structure.
|
||||||
*/
|
*/
|
||||||
public interface NDAlgebra<T, C, N : NDStructure<T>> {
|
public interface NDAlgebra<T, C, N : NDStructure<T>> {
|
||||||
|
/**
|
||||||
|
* The shape of ND-structures this algebra operates on.
|
||||||
|
*/
|
||||||
public val shape: IntArray
|
public val shape: IntArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The algebra over elements of ND structure.
|
||||||
|
*/
|
||||||
public val elementContext: C
|
public val elementContext: C
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce a new [N] structure using given initializer function
|
* Produces a new [N] structure using given initializer function.
|
||||||
*/
|
*/
|
||||||
public fun produce(initializer: C.(IntArray) -> T): N
|
public fun produce(initializer: C.(IntArray) -> T): N
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map elements from one structure to another one
|
* Maps elements from one structure to another one by applying [transform] to them.
|
||||||
*/
|
*/
|
||||||
public fun map(arg: N, transform: C.(T) -> T): N
|
public fun map(arg: N, transform: C.(T) -> T): N
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map indexed elements
|
* Maps elements from one structure to another one by applying [transform] to them alongside with their indices.
|
||||||
*/
|
*/
|
||||||
public fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N
|
public fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine two structures into one
|
* Combines two structures into one.
|
||||||
*/
|
*/
|
||||||
public fun combine(a: N, b: N, transform: C.(T, T) -> T): N
|
public fun combine(a: N, b: N, transform: C.(T, T) -> T): N
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if given elements are consistent with this context
|
* Checks if given element is consistent with this context.
|
||||||
|
*
|
||||||
|
* @param element the structure to check.
|
||||||
|
* @return the valid structure.
|
||||||
*/
|
*/
|
||||||
public fun check(vararg elements: N): Unit = elements.forEach {
|
public fun check(element: N): N {
|
||||||
if (!shape.contentEquals(it.shape)) throw ShapeMismatchException(shape, it.shape)
|
if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape)
|
||||||
|
return element
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* element-by-element invoke a function working on [T] on a [NDStructure]
|
* Checks if given elements are consistent with this context.
|
||||||
|
*
|
||||||
|
* @param elements the structures to check.
|
||||||
|
* @return the array of valid structures.
|
||||||
|
*/
|
||||||
|
public fun check(vararg elements: N): Array<out N> = elements
|
||||||
|
.map(NDStructure<T>::shape)
|
||||||
|
.singleOrNull { !shape.contentEquals(it) }
|
||||||
|
?.let { throw ShapeMismatchException(shape, it) }
|
||||||
|
?: elements
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element-wise invocation of function working on [T] on a [NDStructure].
|
||||||
*/
|
*/
|
||||||
public operator fun Function1<T, T>.invoke(structure: N): N = map(structure) { value -> this@invoke(value) }
|
public operator fun Function1<T, T>.invoke(structure: N): N = map(structure) { value -> this@invoke(value) }
|
||||||
|
|
||||||
@ -56,42 +84,107 @@ public interface NDAlgebra<T, C, N : NDStructure<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An nd-space over element space
|
* Space of [NDStructure].
|
||||||
|
*
|
||||||
|
* @param T the type of the element contained in ND structure.
|
||||||
|
* @param N the type of ND structure.
|
||||||
|
* @param S the type of space of structure elements.
|
||||||
*/
|
*/
|
||||||
public interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T, S, N> {
|
public interface NDSpace<T, S : Space<T>, N : NDStructure<T>> : Space<N>, NDAlgebra<T, S, N> {
|
||||||
/**
|
/**
|
||||||
* Element-by-element addition
|
* Element-wise addition.
|
||||||
|
*
|
||||||
|
* @param a the addend.
|
||||||
|
* @param b the augend.
|
||||||
|
* @return the sum.
|
||||||
*/
|
*/
|
||||||
override fun add(a: N, b: N): N = combine(a, b) { aValue, bValue -> add(aValue, bValue) }
|
public override fun add(a: N, b: N): N = combine(a, b) { aValue, bValue -> add(aValue, bValue) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiply all elements by constant
|
* Element-wise multiplication by scalar.
|
||||||
|
*
|
||||||
|
* @param a the multiplicand.
|
||||||
|
* @param k the multiplier.
|
||||||
|
* @return the product.
|
||||||
*/
|
*/
|
||||||
override fun multiply(a: N, k: Number): N = map(a) { multiply(it, k) }
|
public override fun multiply(a: N, k: Number): N = map(a) { multiply(it, k) }
|
||||||
|
|
||||||
//TODO move to extensions after KEEP-176
|
// TODO move to extensions after KEEP-176
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an ND structure to an element of it.
|
||||||
|
*
|
||||||
|
* @receiver the addend.
|
||||||
|
* @param arg the augend.
|
||||||
|
* @return the sum.
|
||||||
|
*/
|
||||||
public operator fun N.plus(arg: T): N = map(this) { value -> add(arg, value) }
|
public operator fun N.plus(arg: T): N = map(this) { value -> add(arg, value) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtracts an element from ND structure of it.
|
||||||
|
*
|
||||||
|
* @receiver the dividend.
|
||||||
|
* @param arg the divisor.
|
||||||
|
* @return the quotient.
|
||||||
|
*/
|
||||||
public operator fun N.minus(arg: T): N = map(this) { value -> add(arg, -value) }
|
public operator fun N.minus(arg: T): N = map(this) { value -> add(arg, -value) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an element to ND structure of it.
|
||||||
|
*
|
||||||
|
* @receiver the addend.
|
||||||
|
* @param arg the augend.
|
||||||
|
* @return the sum.
|
||||||
|
*/
|
||||||
public operator fun T.plus(arg: N): N = map(arg) { value -> add(this@plus, value) }
|
public operator fun T.plus(arg: N): N = map(arg) { value -> add(this@plus, value) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtracts an ND structure from an element of it.
|
||||||
|
*
|
||||||
|
* @receiver the dividend.
|
||||||
|
* @param arg the divisor.
|
||||||
|
* @return the quotient.
|
||||||
|
*/
|
||||||
public operator fun T.minus(arg: N): N = map(arg) { value -> add(-this@minus, value) }
|
public operator fun T.minus(arg: N): N = map(arg) { value -> add(-this@minus, value) }
|
||||||
|
|
||||||
public companion object
|
public companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An nd-ring over element ring
|
* Ring of [NDStructure].
|
||||||
|
*
|
||||||
|
* @param T the type of the element contained in ND structure.
|
||||||
|
* @param N the type of ND structure.
|
||||||
|
* @param R the type of ring of structure elements.
|
||||||
*/
|
*/
|
||||||
public interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N> {
|
public interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T, R, N> {
|
||||||
/**
|
/**
|
||||||
* Element-by-element multiplication
|
* Element-wise multiplication.
|
||||||
|
*
|
||||||
|
* @param a the multiplicand.
|
||||||
|
* @param b the multiplier.
|
||||||
|
* @return the product.
|
||||||
*/
|
*/
|
||||||
override fun multiply(a: N, b: N): N = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
|
public override fun multiply(a: N, b: N): N = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) }
|
||||||
|
|
||||||
//TODO move to extensions after KEEP-176
|
//TODO move to extensions after KEEP-176
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies an ND structure by an element of it.
|
||||||
|
*
|
||||||
|
* @receiver the multiplicand.
|
||||||
|
* @param arg the multiplier.
|
||||||
|
* @return the product.
|
||||||
|
*/
|
||||||
public operator fun N.times(arg: T): N = map(this) { value -> multiply(arg, value) }
|
public operator fun N.times(arg: T): N = map(this) { value -> multiply(arg, value) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies an element by a ND structure of it.
|
||||||
|
*
|
||||||
|
* @receiver the multiplicand.
|
||||||
|
* @param arg the multiplier.
|
||||||
|
* @return the product.
|
||||||
|
*/
|
||||||
public operator fun T.times(arg: N): N = map(arg) { value -> multiply(this@times, value) }
|
public operator fun T.times(arg: N): N = map(arg) { value -> multiply(this@times, value) }
|
||||||
|
|
||||||
public companion object
|
public companion object
|
||||||
@ -102,29 +195,47 @@ public interface NDRing<T, R : Ring<T>, N : NDStructure<T>> : Ring<N>, NDSpace<T
|
|||||||
*
|
*
|
||||||
* @param T the type of the element contained in ND structure.
|
* @param T the type of the element contained in ND structure.
|
||||||
* @param N the type of ND structure.
|
* @param N the type of ND structure.
|
||||||
* @param F field of structure elements.
|
* @param F the type field of structure elements.
|
||||||
*/
|
*/
|
||||||
public interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> {
|
public interface NDField<T, F : Field<T>, N : NDStructure<T>> : Field<N>, NDRing<T, F, N> {
|
||||||
/**
|
/**
|
||||||
* Element-by-element division
|
* Element-wise division.
|
||||||
|
*
|
||||||
|
* @param a the dividend.
|
||||||
|
* @param b the divisor.
|
||||||
|
* @return the quotient.
|
||||||
*/
|
*/
|
||||||
override fun divide(a: N, b: N): N = combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
|
public override fun divide(a: N, b: N): N = combine(a, b) { aValue, bValue -> divide(aValue, bValue) }
|
||||||
|
|
||||||
//TODO move to extensions after KEEP-176
|
//TODO move to extensions after KEEP-176
|
||||||
|
/**
|
||||||
|
* Divides an ND structure by an element of it.
|
||||||
|
*
|
||||||
|
* @receiver the dividend.
|
||||||
|
* @param arg the divisor.
|
||||||
|
* @return the quotient.
|
||||||
|
*/
|
||||||
public operator fun N.div(arg: T): N = map(this) { value -> divide(arg, value) }
|
public operator fun N.div(arg: T): N = map(this) { value -> divide(arg, value) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divides an element by an ND structure of it.
|
||||||
|
*
|
||||||
|
* @receiver the dividend.
|
||||||
|
* @param arg the divisor.
|
||||||
|
* @return the quotient.
|
||||||
|
*/
|
||||||
public operator fun T.div(arg: N): N = map(arg) { divide(it, this@div) }
|
public operator fun T.div(arg: N): N = map(arg) { divide(it, this@div) }
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
private val realNDFieldCache: MutableMap<IntArray, RealNDField> = hashMapOf()
|
private val realNDFieldCache: MutableMap<IntArray, RealNDField> = hashMapOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a nd-field for [Double] values or pull it from cache if it was created previously
|
* Create a nd-field for [Double] values or pull it from cache if it was created previously.
|
||||||
*/
|
*/
|
||||||
public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) }
|
public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a nd-field with boxing generic buffer
|
* Create an ND field with boxing generic buffer.
|
||||||
*/
|
*/
|
||||||
public fun <T : Any, F : Field<T>> boxing(
|
public fun <T : Any, F : Field<T>> boxing(
|
||||||
field: F,
|
field: F,
|
||||||
|
@ -37,9 +37,8 @@ public interface NDStructure<T> {
|
|||||||
*/
|
*/
|
||||||
public fun elements(): Sequence<Pair<IntArray, T>>
|
public fun elements(): Sequence<Pair<IntArray, T>>
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean
|
public override fun equals(other: Any?): Boolean
|
||||||
|
public override fun hashCode(): Int
|
||||||
override fun hashCode(): Int
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
/**
|
/**
|
||||||
@ -49,13 +48,8 @@ public interface NDStructure<T> {
|
|||||||
if (st1 === st2) return true
|
if (st1 === st2) return true
|
||||||
|
|
||||||
// fast comparison of buffers if possible
|
// fast comparison of buffers if possible
|
||||||
if (
|
if (st1 is NDBuffer && st2 is NDBuffer && st1.strides == st2.strides)
|
||||||
st1 is NDBuffer &&
|
|
||||||
st2 is NDBuffer &&
|
|
||||||
st1.strides == st2.strides
|
|
||||||
) {
|
|
||||||
return st1.buffer.contentEquals(st2.buffer)
|
return st1.buffer.contentEquals(st2.buffer)
|
||||||
}
|
|
||||||
|
|
||||||
//element by element comparison if it could not be avoided
|
//element by element comparison if it could not be avoided
|
||||||
return st1.elements().all { (index, value) -> value == st2[index] }
|
return st1.elements().all { (index, value) -> value == st2[index] }
|
||||||
|
@ -3,8 +3,9 @@ package kscience.kmath.dimensions
|
|||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract class which is not used in runtime. Designates a size of some structure.
|
* Represents a quantity of dimensions in certain structure.
|
||||||
* Could be replaced later by fully inline constructs
|
*
|
||||||
|
* @property dim The number of dimensions.
|
||||||
*/
|
*/
|
||||||
public interface Dimension {
|
public interface Dimension {
|
||||||
public val dim: UInt
|
public val dim: UInt
|
||||||
@ -16,18 +17,33 @@ public fun <D : Dimension> KClass<D>.dim(): UInt = Dimension.resolve(this).dim
|
|||||||
|
|
||||||
public expect fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D
|
public expect fun <D : Dimension> Dimension.Companion.resolve(type: KClass<D>): D
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds or creates [Dimension] with [Dimension.dim] equal to [dim].
|
||||||
|
*/
|
||||||
public expect fun Dimension.Companion.of(dim: UInt): Dimension
|
public expect fun Dimension.Companion.of(dim: UInt): Dimension
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds [Dimension.dim] of given type [D].
|
||||||
|
*/
|
||||||
public inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt = D::class.dim()
|
public inline fun <reified D : Dimension> Dimension.Companion.dim(): UInt = D::class.dim()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing 1 dimension.
|
||||||
|
*/
|
||||||
public object D1 : Dimension {
|
public object D1 : Dimension {
|
||||||
override val dim: UInt get() = 1U
|
override val dim: UInt get() = 1U
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing 2 dimensions.
|
||||||
|
*/
|
||||||
public object D2 : Dimension {
|
public object D2 : Dimension {
|
||||||
override val dim: UInt get() = 2U
|
override val dim: UInt get() = 2U
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type representing 3 dimensions.
|
||||||
|
*/
|
||||||
public object D3 : Dimension {
|
public object D3 : Dimension {
|
||||||
override val dim: UInt get() = 3U
|
override val dim: UInt get() = 3U
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,10 @@ import kscience.kmath.structures.RealBuffer
|
|||||||
*/
|
*/
|
||||||
public interface Bin<T : Any> : Domain<T> {
|
public interface Bin<T : Any> : Domain<T> {
|
||||||
/**
|
/**
|
||||||
* The value of this bin
|
* The value of this bin.
|
||||||
*/
|
*/
|
||||||
public val value: Number
|
public val value: Number
|
||||||
|
|
||||||
public val center: Point<T>
|
public val center: Point<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,16 +3,59 @@ package kscience.kmath.prob
|
|||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic generator
|
* An interface that is implemented by random number generator algorithms.
|
||||||
*/
|
*/
|
||||||
public interface RandomGenerator {
|
public interface RandomGenerator {
|
||||||
|
/**
|
||||||
|
* Gets the next random [Boolean] value.
|
||||||
|
*/
|
||||||
public fun nextBoolean(): Boolean
|
public fun nextBoolean(): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next random [Double] value uniformly distributed between 0 (inclusive) and 1 (exclusive).
|
||||||
|
*/
|
||||||
public fun nextDouble(): Double
|
public fun nextDouble(): Double
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next random `Int` from the random number generator.
|
||||||
|
*
|
||||||
|
* Generates an `Int` random value uniformly distributed between [Int.MIN_VALUE] and [Int.MAX_VALUE] (inclusive).
|
||||||
|
*/
|
||||||
public fun nextInt(): Int
|
public fun nextInt(): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next random non-negative `Int` from the random number generator less than the specified [until] bound.
|
||||||
|
*
|
||||||
|
* Generates an `Int` random value uniformly distributed between `0` (inclusive) and the specified [until] bound
|
||||||
|
* (exclusive).
|
||||||
|
*/
|
||||||
public fun nextInt(until: Int): Int
|
public fun nextInt(until: Int): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next random `Long` from the random number generator.
|
||||||
|
*
|
||||||
|
* Generates a `Long` random value uniformly distributed between [Long.MIN_VALUE] and [Long.MAX_VALUE] (inclusive).
|
||||||
|
*/
|
||||||
public fun nextLong(): Long
|
public fun nextLong(): Long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next random non-negative `Long` from the random number generator less than the specified [until] bound.
|
||||||
|
*
|
||||||
|
* Generates a `Long` random value uniformly distributed between `0` (inclusive) and the specified [until] bound (exclusive).
|
||||||
|
*/
|
||||||
public fun nextLong(until: Long): Long
|
public fun nextLong(until: Long): Long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a subrange of the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive
|
||||||
|
* with random bytes.
|
||||||
|
*
|
||||||
|
* @return [array] with the subrange filled with random bytes.
|
||||||
|
*/
|
||||||
public fun fillBytes(array: ByteArray, fromIndex: Int = 0, toIndex: Int = array.size)
|
public fun fillBytes(array: ByteArray, fromIndex: Int = 0, toIndex: Int = array.size)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a byte array of the specified [size], filled with random bytes.
|
||||||
|
*/
|
||||||
public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) }
|
public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,12 +68,21 @@ public interface RandomGenerator {
|
|||||||
public fun fork(): RandomGenerator
|
public fun fork(): RandomGenerator
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public val default: DefaultGenerator by lazy { DefaultGenerator() }
|
/**
|
||||||
|
* The [DefaultGenerator] instance.
|
||||||
|
*/
|
||||||
|
public val default: DefaultGenerator by lazy(::DefaultGenerator)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [DefaultGenerator] of given [seed].
|
||||||
|
*/
|
||||||
public fun default(seed: Long): DefaultGenerator = DefaultGenerator(Random(seed))
|
public fun default(seed: Long): DefaultGenerator = DefaultGenerator(Random(seed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements [RandomGenerator] by delegating all operations to [Random].
|
||||||
|
*/
|
||||||
public inline class DefaultGenerator(public val random: Random = Random) : RandomGenerator {
|
public inline class DefaultGenerator(public val random: Random = Random) : RandomGenerator {
|
||||||
public override fun nextBoolean(): Boolean = random.nextBoolean()
|
public override fun nextBoolean(): Boolean = random.nextBoolean()
|
||||||
public override fun nextDouble(): Double = random.nextDouble()
|
public override fun nextDouble(): Double = random.nextDouble()
|
||||||
|
Loading…
Reference in New Issue
Block a user