forked from kscience/kmath
0.4 WIP
This commit is contained in:
parent
46eacbb750
commit
2386ecba41
@ -106,4 +106,11 @@ public fun <T : Any, A : Attribute<T>> Attributes(
|
|||||||
attrValue: T,
|
attrValue: T,
|
||||||
): Attributes = Attributes(mapOf(attribute to attrValue))
|
): Attributes = Attributes(mapOf(attribute to attrValue))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Attributes with a single [Unit] valued attribute
|
||||||
|
*/
|
||||||
|
public fun <A : Attribute<Unit>> Attributes(
|
||||||
|
attribute: A
|
||||||
|
): Attributes = Attributes(mapOf(attribute to Unit))
|
||||||
|
|
||||||
public operator fun Attributes.plus(other: Attributes): Attributes = Attributes(content + other.content)
|
public operator fun Attributes.plus(other: Attributes): Attributes = Attributes(content + other.content)
|
@ -26,3 +26,10 @@ public inline fun <reified T> safeTypeOf(): SafeType<T> = SafeType(typeOf<T>())
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@UnstableAttributesAPI
|
@UnstableAttributesAPI
|
||||||
public val <T> SafeType<T>.kClass: KClass<T & Any> get() = kType.classifier as KClass<T & Any>
|
public val <T> SafeType<T>.kClass: KClass<T & Any> get() = kType.classifier as KClass<T & Any>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface containing [type] for dynamic type checking.
|
||||||
|
*/
|
||||||
|
public interface WithType<out T> {
|
||||||
|
public val type: SafeType<T>
|
||||||
|
}
|
@ -47,7 +47,7 @@ internal class MatrixInverseBenchmark {
|
|||||||
@Benchmark
|
@Benchmark
|
||||||
fun ejmlInverse(blackhole: Blackhole) {
|
fun ejmlInverse(blackhole: Blackhole) {
|
||||||
EjmlLinearSpaceDDRM {
|
EjmlLinearSpaceDDRM {
|
||||||
blackhole.consume(matrix.toEjml().inverse())
|
blackhole.consume(matrix.toEjml().inverted())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import space.kscience.kmath.complex.ComplexField
|
|||||||
import space.kscience.kmath.expressions.interpret
|
import space.kscience.kmath.expressions.interpret
|
||||||
import space.kscience.kmath.operations.Algebra
|
import space.kscience.kmath.operations.Algebra
|
||||||
import space.kscience.kmath.operations.Float64Field
|
import space.kscience.kmath.operations.Float64Field
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -39,6 +40,8 @@ internal class TestParser {
|
|||||||
@Test
|
@Test
|
||||||
fun evaluateMstBinary() {
|
fun evaluateMstBinary() {
|
||||||
val magicalAlgebra = object : Algebra<String> {
|
val magicalAlgebra = object : Algebra<String> {
|
||||||
|
override val bufferFactory: MutableBufferFactory<String> get() = MutableBufferFactory()
|
||||||
|
|
||||||
override fun bindSymbolOrNull(value: String): String = value
|
override fun bindSymbolOrNull(value: String): String = value
|
||||||
|
|
||||||
override fun unaryOperationFunction(operation: String): (arg: String) -> String {
|
override fun unaryOperationFunction(operation: String): (arg: String) -> String {
|
||||||
|
@ -10,6 +10,7 @@ kscience {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.kmathCore)
|
api(projects.kmathCore)
|
||||||
|
api(projects.kmathMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
testDependencies {
|
testDependencies {
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.complex
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.safeTypeOf
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.memory.MemoryReader
|
import space.kscience.kmath.memory.*
|
||||||
import space.kscience.kmath.memory.MemorySpec
|
|
||||||
import space.kscience.kmath.memory.MemoryWriter
|
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,8 +53,11 @@ public object ComplexField :
|
|||||||
Norm<Complex, Complex>,
|
Norm<Complex, Complex>,
|
||||||
NumbersAddOps<Complex>,
|
NumbersAddOps<Complex>,
|
||||||
ScaleOperations<Complex> {
|
ScaleOperations<Complex> {
|
||||||
override val bufferFactory: MutableBufferFactory<Complex> = MutableBufferFactory { size, init ->
|
override val bufferFactory: MutableBufferFactory<Complex> = object : MutableBufferFactory<Complex> {
|
||||||
MutableMemoryBuffer.create(Complex, size, init)
|
override fun invoke(size: Int, builder: (Int) -> Complex): MutableBuffer<Complex> =
|
||||||
|
MutableMemoryBuffer.create(Complex, size, builder)
|
||||||
|
|
||||||
|
override val type: SafeType<Complex> = safeTypeOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val zero: Complex = 0.0.toComplex()
|
override val zero: Complex = 0.0.toComplex()
|
||||||
@ -202,8 +207,10 @@ public data class Complex(val re: Double, val im: Double) {
|
|||||||
override fun toString(): String = "($re + i * $im)"
|
override fun toString(): String = "($re + i * $im)"
|
||||||
|
|
||||||
public companion object : MemorySpec<Complex> {
|
public companion object : MemorySpec<Complex> {
|
||||||
override val objectSize: Int
|
|
||||||
get() = 16
|
override val type: SafeType<Complex> get() = safeTypeOf()
|
||||||
|
|
||||||
|
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))
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.complex
|
package space.kscience.kmath.complex
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.safeTypeOf
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.memory.MemoryReader
|
import space.kscience.kmath.memory.*
|
||||||
import space.kscience.kmath.memory.MemorySpec
|
|
||||||
import space.kscience.kmath.memory.MemoryWriter
|
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.MemoryBuffer
|
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.MutableMemoryBuffer
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,6 +36,8 @@ public class Quaternion(
|
|||||||
require(!z.isNaN()) { "z-component of quaternion is not-a-number" }
|
require(!z.isNaN()) { "z-component of quaternion is not-a-number" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val type: SafeType<Double> get() = safeTypeOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string representation of this quaternion.
|
* Returns a string representation of this quaternion.
|
||||||
*/
|
*/
|
||||||
@ -78,6 +79,7 @@ public class Quaternion(
|
|||||||
|
|
||||||
public companion object : MemorySpec<Quaternion> {
|
public companion object : MemorySpec<Quaternion> {
|
||||||
override val objectSize: Int get() = 32
|
override val objectSize: Int get() = 32
|
||||||
|
override val type: SafeType<Quaternion> get() = safeTypeOf()
|
||||||
|
|
||||||
override fun MemoryReader.read(offset: Int): Quaternion = Quaternion(
|
override fun MemoryReader.read(offset: Int): Quaternion = Quaternion(
|
||||||
readDouble(offset),
|
readDouble(offset),
|
||||||
@ -122,7 +124,7 @@ public val Quaternion.reciprocal: Quaternion
|
|||||||
/**
|
/**
|
||||||
* Produce a normalized version of this quaternion
|
* Produce a normalized version of this quaternion
|
||||||
*/
|
*/
|
||||||
public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra){ this@normalized / norm(this@normalized) }
|
public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra) { this@normalized / norm(this@normalized) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A field of [Quaternion].
|
* A field of [Quaternion].
|
||||||
@ -131,6 +133,8 @@ public fun Quaternion.normalized(): Quaternion = with(QuaternionAlgebra){ this@n
|
|||||||
public object QuaternionAlgebra : Group<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
|
public object QuaternionAlgebra : Group<Quaternion>, Norm<Quaternion, Double>, PowerOperations<Quaternion>,
|
||||||
ExponentialOperations<Quaternion>, NumbersAddOps<Quaternion>, ScaleOperations<Quaternion> {
|
ExponentialOperations<Quaternion>, NumbersAddOps<Quaternion>, ScaleOperations<Quaternion> {
|
||||||
|
|
||||||
|
override val bufferFactory: MutableBufferFactory<Quaternion> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Quaternion = Quaternion(0.0)
|
override val zero: Quaternion = Quaternion(0.0)
|
||||||
public val one: Quaternion = Quaternion(1.0)
|
public val one: Quaternion = Quaternion(1.0)
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ kscience{
|
|||||||
wasm()
|
wasm()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.kmathMemory)
|
|
||||||
api(projects.attributesKt)
|
api(projects.attributesKt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ public abstract class DSAlgebra<T, A : Ring<T>>(
|
|||||||
vararg derivatives: T,
|
vararg derivatives: T,
|
||||||
): DS<T, A> {
|
): DS<T, A> {
|
||||||
require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" }
|
require(derivatives.size == compiler.size) { "dimension mismatch: ${derivatives.size} and ${compiler.size}" }
|
||||||
val data = derivatives.asBuffer()
|
val data = derivatives.asList().asBuffer(algebra.type)
|
||||||
|
|
||||||
return DS(data)
|
return DS(data)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package space.kscience.kmath.expressions
|
package space.kscience.kmath.expressions
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.linear.Point
|
import space.kscience.kmath.linear.Point
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
|
@ -5,15 +5,12 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
|
||||||
import space.kscience.kmath.PerformancePitfall
|
import space.kscience.kmath.PerformancePitfall
|
||||||
import space.kscience.kmath.nd.*
|
import space.kscience.kmath.nd.*
|
||||||
import space.kscience.kmath.operations.*
|
import space.kscience.kmath.operations.*
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.VirtualBuffer
|
import space.kscience.kmath.structures.VirtualBuffer
|
||||||
import space.kscience.kmath.structures.indices
|
import space.kscience.kmath.structures.indices
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
|
|
||||||
public class BufferedLinearSpace<T, out A : Ring<T>>(
|
public class BufferedLinearSpace<T, out A : Ring<T>>(
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.*
|
import space.kscience.kmath.nd.*
|
||||||
import space.kscience.kmath.operations.BufferRingOps
|
import space.kscience.kmath.operations.BufferRingOps
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import space.kscience.kmath.operations.WithType
|
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
|
||||||
@ -173,15 +173,15 @@ public interface LinearSpace<T, out A : Ring<T>> : MatrixOperations<T> {
|
|||||||
public operator fun T.times(v: Point<T>): Point<T> = v * this
|
public operator fun T.times(v: Point<T>): Point<T> = v * this
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an attribute value for the structure in this scope. Structure features take precedence other context features.
|
* Get an attribute value for the structure in this scope. Structure attributes are preferred to computed attributes.
|
||||||
*
|
*
|
||||||
* @param structure the structure.
|
* @param structure the structure.
|
||||||
* @param attribute to be computed.
|
* @param attribute to be computed.
|
||||||
* @return a feature object or `null` if it isn't present.
|
* @return a feature object or `null` if it isn't present.
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T? =
|
public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T =
|
||||||
structure.attributes[attribute]
|
structure.attributes[attribute] ?: error("Can't compute attribute $attribute for $structure")
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
|
import space.kscience.attributes.Attributes
|
||||||
import space.kscience.attributes.PolymorphicAttribute
|
import space.kscience.attributes.PolymorphicAttribute
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
import space.kscience.attributes.safeTypeOf
|
import space.kscience.attributes.safeTypeOf
|
||||||
@ -19,32 +20,42 @@ import space.kscience.kmath.structures.*
|
|||||||
* *a* is the owning matrix.
|
* *a* is the owning matrix.
|
||||||
*
|
*
|
||||||
* @param T the type of matrices' items.
|
* @param T the type of matrices' items.
|
||||||
* @param l The lower triangular matrix in this decomposition. It may have [LowerTriangular].
|
* @param lu combined L and U matrix
|
||||||
* @param u The upper triangular matrix in this decomposition. It may have [UpperTriangular].
|
|
||||||
*/
|
*/
|
||||||
public class LupDecomposition<T>(
|
public class LupDecomposition<T>(
|
||||||
public val linearSpace: LinearSpace<T, Ring<T>>,
|
public val linearSpace: LinearSpace<T, Ring<T>>,
|
||||||
public val l: Matrix<T>,
|
private val lu: Matrix<T>,
|
||||||
public val u: Matrix<T>,
|
|
||||||
public val pivot: IntBuffer,
|
public val pivot: IntBuffer,
|
||||||
|
private val even: Boolean,
|
||||||
) {
|
) {
|
||||||
public val elementAlgebra: Ring<T> get() = linearSpace.elementAlgebra
|
public val elementAlgebra: Ring<T> get() = linearSpace.elementAlgebra
|
||||||
|
|
||||||
public val pivotMatrix: VirtualMatrix<T>
|
public val l: Matrix<T>
|
||||||
|
get() = VirtualMatrix(lu.type, lu.rowNum, lu.colNum, attributes = Attributes(LowerTriangular)) { i, j ->
|
||||||
|
when {
|
||||||
|
j < i -> lu[i, j]
|
||||||
|
j == i -> elementAlgebra.one
|
||||||
|
else -> elementAlgebra.zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val u: Matrix<T>
|
||||||
|
get() = VirtualMatrix(lu.type, lu.rowNum, lu.colNum, attributes = Attributes(UpperTriangular)) { i, j ->
|
||||||
|
if (j >= i) lu[i, j] else elementAlgebra.zero
|
||||||
|
}
|
||||||
|
|
||||||
|
public val pivotMatrix: Matrix<T>
|
||||||
get() = VirtualMatrix(linearSpace.type, l.rowNum, l.colNum) { row, column ->
|
get() = VirtualMatrix(linearSpace.type, l.rowNum, l.colNum) { row, column ->
|
||||||
if (column == pivot[row]) elementAlgebra.one else elementAlgebra.zero
|
if (column == pivot[row]) elementAlgebra.one else elementAlgebra.zero
|
||||||
}
|
}
|
||||||
|
|
||||||
public val <T> LupDecomposition<T>.determinant by lazy {
|
public val determinant: T by lazy {
|
||||||
elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
|
elementAlgebra { (0 until l.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class LupDecompositionAttribute<T>(type: SafeType<LupDecomposition<T>>) :
|
public class LupDecompositionAttribute<T>(type: SafeType<LupDecomposition<T>>) :
|
||||||
PolymorphicAttribute<LupDecomposition<T>>(type),
|
PolymorphicAttribute<LupDecomposition<T>>(type),
|
||||||
MatrixAttribute<LupDecomposition<T>>
|
MatrixAttribute<LupDecomposition<T>>
|
||||||
@ -52,59 +63,6 @@ public class LupDecompositionAttribute<T>(type: SafeType<LupDecomposition<T>>) :
|
|||||||
public val <T> MatrixOperations<T>.LUP: LupDecompositionAttribute<T>
|
public val <T> MatrixOperations<T>.LUP: LupDecompositionAttribute<T>
|
||||||
get() = LupDecompositionAttribute(safeTypeOf())
|
get() = LupDecompositionAttribute(safeTypeOf())
|
||||||
|
|
||||||
|
|
||||||
///**
|
|
||||||
// * Common implementation of [LupDecomposition].
|
|
||||||
// */
|
|
||||||
//private class LupDecompositionImpl<T : Any>(
|
|
||||||
// public val elementContext: Field<T>,
|
|
||||||
// public val lu: Matrix<T>,
|
|
||||||
// public val pivot: IntBuffer,
|
|
||||||
// private val even: Boolean,
|
|
||||||
//) : LupDecomposition<T> {
|
|
||||||
// /**
|
|
||||||
// * Returns the matrix L of the decomposition.
|
|
||||||
// *
|
|
||||||
// * L is a lower-triangular matrix with [Ring.one] in diagonal
|
|
||||||
// */
|
|
||||||
// override val l: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
|
|
||||||
// when {
|
|
||||||
// j < i -> lu[i, j]
|
|
||||||
// j == i -> elementContext.one
|
|
||||||
// else -> elementContext.zero
|
|
||||||
// }
|
|
||||||
// }.withFeature(LowerTriangular)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Returns the matrix U of the decomposition.
|
|
||||||
// *
|
|
||||||
// * U is an upper-triangular matrix including the diagonal
|
|
||||||
// */
|
|
||||||
// override val u: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
|
|
||||||
// if (j >= i) lu[i, j] else elementContext.zero
|
|
||||||
// }.withFeature(UpperTriangular)
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Returns the P rows permutation matrix.
|
|
||||||
// *
|
|
||||||
// * P is a sparse matrix with exactly one element set to [Ring.one] in
|
|
||||||
// * each row and each column, all other elements being set to [Ring.zero].
|
|
||||||
// */
|
|
||||||
// override val p: Matrix<T> = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j ->
|
|
||||||
// if (j == pivot[i]) elementContext.one else elementContext.zero
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Return the determinant of the matrix
|
|
||||||
// * @return determinant of the matrix
|
|
||||||
// */
|
|
||||||
// override val determinant: T by lazy {
|
|
||||||
// elementContext { (0 until lu.shape[0]).fold(if(even) one else -one) { value, i -> value * lu[i, i] } }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
|
internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
|
||||||
if (value > elementAlgebra.zero) value else elementAlgebra { -value }
|
if (value > elementAlgebra.zero) value else elementAlgebra { -value }
|
||||||
@ -115,97 +73,81 @@ internal fun <T : Comparable<T>> LinearSpace<T, Ring<T>>.abs(value: T): T =
|
|||||||
public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
|
public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
|
||||||
matrix: Matrix<T>,
|
matrix: Matrix<T>,
|
||||||
checkSingular: (T) -> Boolean,
|
checkSingular: (T) -> Boolean,
|
||||||
): LupDecomposition<T> {
|
): LupDecomposition<T> = elementAlgebra {
|
||||||
require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" }
|
require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" }
|
||||||
val m = matrix.colNum
|
val m = matrix.colNum
|
||||||
val pivot = IntArray(matrix.rowNum)
|
val pivot = IntArray(matrix.rowNum)
|
||||||
|
|
||||||
//TODO just waits for multi-receivers
|
//TODO just waits for multi-receivers
|
||||||
BufferAccessor2D(matrix.rowNum, matrix.colNum, elementAlgebra.bufferFactory).run {
|
with(BufferAccessor2D(matrix.rowNum, matrix.colNum, elementAlgebra.bufferFactory)){
|
||||||
elementAlgebra {
|
|
||||||
val lu = create(matrix)
|
|
||||||
|
|
||||||
// Initialize the permutation array and parity
|
val lu = create(matrix)
|
||||||
for (row in 0 until m) pivot[row] = row
|
|
||||||
var even = true
|
|
||||||
|
|
||||||
// Initialize the permutation array and parity
|
// Initialize the permutation array and parity
|
||||||
for (row in 0 until m) pivot[row] = row
|
for (row in 0 until m) pivot[row] = row
|
||||||
|
var even = true
|
||||||
|
|
||||||
// Loop over columns
|
// Initialize the permutation array and parity
|
||||||
for (col in 0 until m) {
|
for (row in 0 until m) pivot[row] = row
|
||||||
// upper
|
|
||||||
for (row in 0 until col) {
|
|
||||||
val luRow = lu.row(row)
|
|
||||||
var sum = luRow[col]
|
|
||||||
for (i in 0 until row) sum -= luRow[i] * lu[i, col]
|
|
||||||
luRow[col] = sum
|
|
||||||
}
|
|
||||||
|
|
||||||
// lower
|
// Loop over columns
|
||||||
var max = col // permutation row
|
for (col in 0 until m) {
|
||||||
var largest = -one
|
// upper
|
||||||
|
for (row in 0 until col) {
|
||||||
for (row in col until m) {
|
val luRow = lu.row(row)
|
||||||
val luRow = lu.row(row)
|
var sum = luRow[col]
|
||||||
var sum = luRow[col]
|
for (i in 0 until row) sum -= luRow[i] * lu[i, col]
|
||||||
for (i in 0 until col) sum -= luRow[i] * lu[i, col]
|
luRow[col] = sum
|
||||||
luRow[col] = sum
|
|
||||||
|
|
||||||
// maintain the best permutation choice
|
|
||||||
if (abs(sum) > largest) {
|
|
||||||
largest = abs(sum)
|
|
||||||
max = row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Singularity check
|
|
||||||
check(!checkSingular(abs(lu[max, col]))) { "The matrix is singular" }
|
|
||||||
|
|
||||||
// Pivot if necessary
|
|
||||||
if (max != col) {
|
|
||||||
val luMax = lu.row(max)
|
|
||||||
val luCol = lu.row(col)
|
|
||||||
|
|
||||||
for (i in 0 until m) {
|
|
||||||
val tmp = luMax[i]
|
|
||||||
luMax[i] = luCol[i]
|
|
||||||
luCol[i] = tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
val temp = pivot[max]
|
|
||||||
pivot[max] = pivot[col]
|
|
||||||
pivot[col] = temp
|
|
||||||
even = !even
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divide the lower elements by the "winning" diagonal elt.
|
|
||||||
val luDiag = lu[col, col]
|
|
||||||
for (row in col + 1 until m) lu[row, col] /= luDiag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val l: MatrixWrapper<T> = VirtualMatrix(type, rowNum, colNum) { i, j ->
|
// lower
|
||||||
when {
|
var max = col // permutation row
|
||||||
j < i -> lu[i, j]
|
var largest = -one
|
||||||
j == i -> one
|
|
||||||
else -> zero
|
for (row in col until m) {
|
||||||
|
val luRow = lu.row(row)
|
||||||
|
var sum = luRow[col]
|
||||||
|
for (i in 0 until col) sum -= luRow[i] * lu[i, col]
|
||||||
|
luRow[col] = sum
|
||||||
|
|
||||||
|
// maintain the best permutation choice
|
||||||
|
if (abs(sum) > largest) {
|
||||||
|
largest = abs(sum)
|
||||||
|
max = row
|
||||||
}
|
}
|
||||||
}.withAttribute(LowerTriangular)
|
}
|
||||||
|
|
||||||
val u = VirtualMatrix(type, rowNum, colNum) { i, j ->
|
// Singularity check
|
||||||
if (j >= i) lu[i, j] else zero
|
check(!checkSingular(abs(lu[max, col]))) { "The matrix is singular" }
|
||||||
}.withAttribute(UpperTriangular)
|
|
||||||
//
|
|
||||||
// val p = VirtualMatrix(rowNum, colNum) { i, j ->
|
|
||||||
// if (j == pivot[i]) one else zero
|
|
||||||
// }.withAttribute(Determinant, if (even) one else -one)
|
|
||||||
|
|
||||||
return LupDecomposition(this@lup, l, u, pivot.asBuffer())
|
// Pivot if necessary
|
||||||
|
if (max != col) {
|
||||||
|
val luMax = lu.row(max)
|
||||||
|
val luCol = lu.row(col)
|
||||||
|
|
||||||
|
for (i in 0 until m) {
|
||||||
|
val tmp = luMax[i]
|
||||||
|
luMax[i] = luCol[i]
|
||||||
|
luCol[i] = tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
val temp = pivot[max]
|
||||||
|
pivot[max] = pivot[col]
|
||||||
|
pivot[col] = temp
|
||||||
|
even = !even
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide the lower elements by the "winning" diagonal elt.
|
||||||
|
val luDiag = lu[col, col]
|
||||||
|
for (row in col + 1 until m) lu[row, col] /= luDiag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return LupDecomposition(this@lup, lu.toStructure2D(), pivot.asBuffer(), even)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public fun LinearSpace<Double, Float64Field>.lup(
|
public fun LinearSpace<Double, Float64Field>.lup(
|
||||||
matrix: Matrix<Double>,
|
matrix: Matrix<Double>,
|
||||||
singularityThreshold: Double = 1e-11,
|
singularityThreshold: Double = 1e-11,
|
||||||
|
@ -7,9 +7,9 @@ package space.kscience.kmath.linear
|
|||||||
|
|
||||||
import space.kscience.attributes.FlagAttribute
|
import space.kscience.attributes.FlagAttribute
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import space.kscience.kmath.operations.WithType
|
|
||||||
import space.kscience.kmath.structures.BufferAccessor2D
|
import space.kscience.kmath.structures.BufferAccessor2D
|
||||||
import space.kscience.kmath.structures.MutableBufferFactory
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ import space.kscience.kmath.operations.Ring
|
|||||||
*
|
*
|
||||||
* @param T the type of items.
|
* @param T the type of items.
|
||||||
*/
|
*/
|
||||||
public class MatrixWrapper<out T : Any> internal constructor(
|
public class MatrixWrapper<out T> internal constructor(
|
||||||
public val origin: Matrix<T>,
|
public val origin: Matrix<T>,
|
||||||
override val attributes: Attributes,
|
override val attributes: Attributes,
|
||||||
) : Matrix<T> by origin {
|
) : Matrix<T> by origin {
|
||||||
|
@ -5,17 +5,12 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.nd
|
package space.kscience.kmath.nd
|
||||||
|
|
||||||
import space.kscience.attributes.Attribute
|
import space.kscience.attributes.*
|
||||||
import space.kscience.attributes.AttributeContainer
|
|
||||||
import space.kscience.attributes.Attributes
|
|
||||||
import space.kscience.attributes.SafeType
|
|
||||||
import space.kscience.kmath.PerformancePitfall
|
import space.kscience.kmath.PerformancePitfall
|
||||||
import space.kscience.kmath.linear.LinearSpace
|
import space.kscience.kmath.linear.LinearSpace
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import space.kscience.kmath.operations.WithType
|
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import kotlin.jvm.JvmName
|
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
public interface StructureAttribute<T> : Attribute<T>
|
public interface StructureAttribute<T> : Attribute<T>
|
||||||
@ -148,28 +143,20 @@ public inline fun <reified T : Any> BufferND(
|
|||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): BufferND<T> = BufferND(strides, Buffer(strides.linearSize) { i -> initializer(strides.index(i)) })
|
): BufferND<T> = BufferND(strides, Buffer(strides.linearSize) { i -> initializer(strides.index(i)) })
|
||||||
|
|
||||||
public inline fun <T : Any> BufferND(
|
|
||||||
type: SafeType<T>,
|
|
||||||
strides: Strides,
|
|
||||||
crossinline initializer: (IntArray) -> T,
|
|
||||||
): BufferND<T> = BufferND(strides, Buffer(type, strides.linearSize) { i -> initializer(strides.index(i)) })
|
|
||||||
|
|
||||||
|
|
||||||
public inline fun <reified T : Any> BufferND(
|
public inline fun <reified T : Any> BufferND(
|
||||||
shape: ShapeND,
|
shape: ShapeND,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): BufferND<T> = BufferND(ColumnStrides(shape), initializer)
|
): BufferND<T> = BufferND(ColumnStrides(shape), initializer)
|
||||||
|
|
||||||
@JvmName("autoVarArg")
|
|
||||||
public inline fun <reified T : Any> BufferND(
|
public inline fun <reified T : Any> BufferND(
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
crossinline initializer: (IntArray) -> T,
|
crossinline initializer: (IntArray) -> T,
|
||||||
): BufferND<T> = BufferND(ColumnStrides(ShapeND(shape)), initializer)
|
): BufferND<T> = BufferND(ColumnStrides(ShapeND(shape)), initializer)
|
||||||
|
|
||||||
public inline fun <T : Any> BufferND(
|
public fun <T : Any> BufferND(
|
||||||
type: SafeType<T>,
|
type: SafeType<T>,
|
||||||
vararg shape: Int,
|
vararg shape: Int,
|
||||||
crossinline initializer: (IntArray) -> T,
|
initializer: (IntArray) -> T,
|
||||||
): BufferND<T> = BufferND(type, ColumnStrides(ShapeND(shape)), initializer)
|
): BufferND<T> = BufferND(type, ColumnStrides(ShapeND(shape)), initializer)
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,19 +6,12 @@
|
|||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.expressions.Symbol
|
||||||
import space.kscience.kmath.operations.Ring.Companion.optimizedPower
|
import space.kscience.kmath.operations.Ring.Companion.optimizedPower
|
||||||
import space.kscience.kmath.structures.MutableBufferFactory
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface containing [type] for dynamic type checking.
|
|
||||||
*/
|
|
||||||
public interface WithType<out T> {
|
|
||||||
public val type: SafeType<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an algebraic structure.
|
* Represents an algebraic structure.
|
||||||
*
|
*
|
||||||
|
@ -5,20 +5,18 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
|
||||||
import space.kscience.attributes.safeTypeOf
|
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.BufferedRingOpsND
|
import space.kscience.kmath.nd.BufferedRingOpsND
|
||||||
import space.kscience.kmath.operations.BigInt.Companion.BASE
|
import space.kscience.kmath.operations.BigInt.Companion.BASE
|
||||||
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
|
import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import kotlin.math.log2
|
import kotlin.math.log2
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.sign
|
import kotlin.math.sign
|
||||||
|
|
||||||
private typealias Magnitude = UIntArray
|
private typealias Magnitude = UIntArray
|
||||||
private typealias TBase = ULong
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
|
* Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger).
|
||||||
@ -29,7 +27,7 @@ private typealias TBase = ULong
|
|||||||
@OptIn(UnstableKMathAPI::class)
|
@OptIn(UnstableKMathAPI::class)
|
||||||
public object BigIntField : Field<BigInt>, NumbersAddOps<BigInt>, ScaleOperations<BigInt> {
|
public object BigIntField : Field<BigInt>, NumbersAddOps<BigInt>, ScaleOperations<BigInt> {
|
||||||
|
|
||||||
override val type: SafeType<BigInt> = safeTypeOf()
|
override val bufferFactory: MutableBufferFactory<BigInt> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: BigInt = BigInt.ZERO
|
override val zero: BigInt = BigInt.ZERO
|
||||||
override val one: BigInt = BigInt.ONE
|
override val one: BigInt = BigInt.ONE
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
|
||||||
import space.kscience.attributes.safeTypeOf
|
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.MutableBufferFactory
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
@ -21,10 +19,10 @@ public interface WithSize {
|
|||||||
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
|
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
|
||||||
public val elementAlgebra: A
|
public val elementAlgebra: A
|
||||||
|
|
||||||
override val type: SafeType<Buffer<T>> get() = safeTypeOf<Buffer<T>>()
|
|
||||||
|
|
||||||
public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
|
public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
|
||||||
|
|
||||||
|
override val bufferFactory: MutableBufferFactory<Buffer<T>> get() = MutableBufferFactory()
|
||||||
|
|
||||||
public fun buffer(size: Int, vararg elements: T): Buffer<T> {
|
public fun buffer(size: Int, vararg elements: T): Buffer<T> {
|
||||||
require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
|
require(elements.size == size) { "Expected $size elements but found ${elements.size}" }
|
||||||
return elementBufferFactory(size) { elements[it] }
|
return elementBufferFactory(size) { elements[it] }
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
|
||||||
import space.kscience.attributes.safeTypeOf
|
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.expressions.Symbol
|
import space.kscience.kmath.expressions.Symbol
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An algebra for generic boolean logic
|
* An algebra for generic boolean logic
|
||||||
@ -74,7 +73,7 @@ public interface LogicAlgebra<T : Any> : Algebra<T> {
|
|||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||||
public object BooleanAlgebra : LogicAlgebra<Boolean> {
|
public object BooleanAlgebra : LogicAlgebra<Boolean> {
|
||||||
|
|
||||||
override val type: SafeType<Boolean> get() = safeTypeOf()
|
override val bufferFactory: MutableBufferFactory<Boolean> get() = MutableBufferFactory()
|
||||||
|
|
||||||
override fun const(boolean: Boolean): Boolean = boolean
|
override fun const(boolean: Boolean): Boolean = boolean
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
import space.kscience.kmath.structures.*
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import kotlin.math.pow as kpow
|
import kotlin.math.pow as kpow
|
||||||
|
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ public val Double.Companion.algebra: Float64Field get() = Float64Field
|
|||||||
*/
|
*/
|
||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||||
public object Float32Field : ExtendedField<Float>, Norm<Float, Float> {
|
public object Float32Field : ExtendedField<Float>, Norm<Float, Float> {
|
||||||
override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory(::Float32Buffer)
|
override val bufferFactory: MutableBufferFactory<Float> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Float get() = 0.0f
|
override val zero: Float get() = 0.0f
|
||||||
override val one: Float get() = 1.0f
|
override val one: Float get() = 1.0f
|
||||||
@ -187,7 +187,7 @@ public val Float.Companion.algebra: Float32Field get() = Float32Field
|
|||||||
*/
|
*/
|
||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||||
public object Int32Ring : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
|
public object Int32Ring : Ring<Int>, Norm<Int, Int>, NumericAlgebra<Int> {
|
||||||
override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory(::Int32Buffer)
|
override val bufferFactory: MutableBufferFactory<Int> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Int get() = 0
|
override val zero: Int get() = 0
|
||||||
override val one: Int get() = 1
|
override val one: Int get() = 1
|
||||||
@ -212,7 +212,7 @@ public val Int.Companion.algebra: Int32Ring get() = Int32Ring
|
|||||||
*/
|
*/
|
||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||||
public object Int16Ring : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> {
|
public object Int16Ring : Ring<Short>, Norm<Short, Short>, NumericAlgebra<Short> {
|
||||||
override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory(::Int16Buffer)
|
override val bufferFactory: MutableBufferFactory<Short> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Short get() = 0
|
override val zero: Short get() = 0
|
||||||
override val one: Short get() = 1
|
override val one: Short get() = 1
|
||||||
@ -237,7 +237,7 @@ public val Short.Companion.algebra: Int16Ring get() = Int16Ring
|
|||||||
*/
|
*/
|
||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||||
public object Int8Ring : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
|
public object Int8Ring : Ring<Byte>, Norm<Byte, Byte>, NumericAlgebra<Byte> {
|
||||||
override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory(::Int8Buffer)
|
override val bufferFactory: MutableBufferFactory<Byte> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Byte get() = 0
|
override val zero: Byte get() = 0
|
||||||
override val one: Byte get() = 1
|
override val one: Byte get() = 1
|
||||||
@ -262,7 +262,7 @@ public val Byte.Companion.algebra: Int8Ring get() = Int8Ring
|
|||||||
*/
|
*/
|
||||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||||
public object Int64Ring : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
|
public object Int64Ring : Ring<Long>, Norm<Long, Long>, NumericAlgebra<Long> {
|
||||||
override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory(::Int64Buffer)
|
override val bufferFactory: MutableBufferFactory<Long> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Long get() = 0L
|
override val zero: Long get() = 0L
|
||||||
override val one: Long get() = 1L
|
override val one: Long get() = 1L
|
||||||
|
@ -5,13 +5,16 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.safeTypeOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [MutableBuffer] implementation over [Array].
|
* [MutableBuffer] implementation over [Array].
|
||||||
*
|
*
|
||||||
* @param T the type of elements contained in the buffer.
|
* @param T the type of elements contained in the buffer.
|
||||||
* @property array The underlying array.
|
* @property array The underlying array.
|
||||||
*/
|
*/
|
||||||
public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
|
public class ArrayBuffer<T>(override val type: SafeType<T>, internal val array: Array<T>) : MutableBuffer<T> {
|
||||||
// Can't inline because array is invariant
|
// Can't inline because array is invariant
|
||||||
override val size: Int get() = array.size
|
override val size: Int get() = array.size
|
||||||
|
|
||||||
@ -22,13 +25,17 @@ public class ArrayBuffer<T>(internal val array: Array<T>) : MutableBuffer<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override operator fun iterator(): Iterator<T> = array.iterator()
|
override operator fun iterator(): Iterator<T> = array.iterator()
|
||||||
override fun copy(): MutableBuffer<T> = ArrayBuffer(array.copyOf())
|
override fun copy(): MutableBuffer<T> = ArrayBuffer(type, array.copyOf())
|
||||||
|
|
||||||
override fun toString(): String = Buffer.toString(this)
|
override fun toString(): String = Buffer.toString(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an [ArrayBuffer] that wraps the original array.
|
||||||
|
*/
|
||||||
|
public fun <T> Array<T>.asBuffer(type: SafeType<T>): ArrayBuffer<T> = ArrayBuffer(type, this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an [ArrayBuffer] that wraps the original array.
|
* Returns an [ArrayBuffer] that wraps the original array.
|
||||||
*/
|
*/
|
||||||
public fun <T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(this)
|
public inline fun <reified T> Array<T>.asBuffer(): ArrayBuffer<T> = ArrayBuffer(safeTypeOf<T>(), this)
|
@ -6,9 +6,9 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
import space.kscience.attributes.safeTypeOf
|
import space.kscience.attributes.safeTypeOf
|
||||||
import space.kscience.kmath.operations.WithSize
|
import space.kscience.kmath.operations.WithSize
|
||||||
import space.kscience.kmath.operations.WithType
|
|
||||||
import space.kscience.kmath.operations.asSequence
|
import space.kscience.kmath.operations.asSequence
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,6 +9,8 @@ import space.kscience.kmath.UnstableKMathAPI
|
|||||||
public interface BufferView<T> : Buffer<T> {
|
public interface BufferView<T> : Buffer<T> {
|
||||||
public val origin: Buffer<T>
|
public val origin: Buffer<T>
|
||||||
|
|
||||||
|
override val type: SafeType<T> get() = origin.type
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index in [origin] buffer from index in this buffer.
|
* Get the index in [origin] buffer from index in this buffer.
|
||||||
* Return -1 if element not present in the original buffer
|
* Return -1 if element not present in the original buffer
|
||||||
@ -36,6 +39,7 @@ public class BufferSlice<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun get(index: Int): T = if (index >= size) {
|
override fun get(index: Int): T = if (index >= size) {
|
||||||
throw IndexOutOfBoundsException("$index is out of ${0 until size} rage")
|
throw IndexOutOfBoundsException("$index is out of ${0 until size} rage")
|
||||||
} else {
|
} else {
|
||||||
@ -100,7 +104,8 @@ public fun <T> Buffer<T>.slice(range: IntRange): BufferView<T> = if (this is Buf
|
|||||||
* Dynamically create a range from the initial range
|
* Dynamically create a range from the initial range
|
||||||
*/
|
*/
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public inline fun <T> Buffer<T>.slice(rangeBuilder: IntRange.() -> IntRange): BufferView<T> = slice(rangeBuilder(indices))
|
public inline fun <T> Buffer<T>.slice(rangeBuilder: IntRange.() -> IntRange): BufferView<T> =
|
||||||
|
slice(rangeBuilder(indices))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize original buffer to a given range using given [range], filling additional segments with [defaultValue].
|
* Resize original buffer to a given range using given [range], filling additional segments with [defaultValue].
|
||||||
|
@ -72,15 +72,21 @@ public interface MutableBuffer<T> : Buffer<T> {
|
|||||||
* The [size] is specified, and each element is calculated by calling the specified [initializer] function.
|
* 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> MutableBuffer(type: SafeType<T>, size: Int, initializer: (Int) -> T): MutableBuffer<T> =
|
public inline fun <T> MutableBuffer(
|
||||||
when (type.kType) {
|
type: SafeType<T>,
|
||||||
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer<T>
|
size: Int,
|
||||||
typeOf<Short>() -> MutableBuffer.short(size) { initializer(it) as Short } as MutableBuffer<T>
|
initializer: (Int) -> T,
|
||||||
typeOf<Int>() -> MutableBuffer.int(size) { initializer(it) as Int } as MutableBuffer<T>
|
): MutableBuffer<T> = when (type.kType) {
|
||||||
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as MutableBuffer<T>
|
typeOf<Boolean>() -> TODO()
|
||||||
typeOf<Long>() -> MutableBuffer.long(size) { initializer(it) as Long } as MutableBuffer<T>
|
typeOf<Int8>() -> Int8Buffer(size) { initializer(it) as Int8 } as MutableBuffer<T>
|
||||||
else -> MutableListBuffer(type, MutableList(size, initializer))
|
typeOf<Int16>() -> MutableBuffer.short(size) { initializer(it) as Int16 } as MutableBuffer<T>
|
||||||
}
|
typeOf<Int32>() -> MutableBuffer.int(size) { initializer(it) as Int32 } as MutableBuffer<T>
|
||||||
|
typeOf<Int64>() -> MutableBuffer.long(size) { initializer(it) as Int64 } as MutableBuffer<T>
|
||||||
|
typeOf<Float>() -> MutableBuffer.float(size) { initializer(it) as Float } as MutableBuffer<T>
|
||||||
|
typeOf<Double>() -> MutableBuffer.double(size) { initializer(it) as Double } as MutableBuffer<T>
|
||||||
|
//TODO add unsigned types
|
||||||
|
else -> MutableListBuffer(type, MutableList(size, initializer))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
|
* Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
|
||||||
|
@ -8,7 +8,6 @@ package space.kscience.kmath.linear
|
|||||||
import space.kscience.kmath.PerformancePitfall
|
import space.kscience.kmath.PerformancePitfall
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.StructureND
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.nd.as2D
|
|
||||||
import space.kscience.kmath.operations.algebra
|
import space.kscience.kmath.operations.algebra
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -22,7 +21,7 @@ class MatrixTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testTranspose() = Double.algebra.linearSpace.run {
|
fun testTranspose() = Double.algebra.linearSpace.run {
|
||||||
val matrix = one(3, 3)
|
val matrix = one(3, 3)
|
||||||
val transposed = matrix.transpose()
|
val transposed = matrix.transposed
|
||||||
assertTrue { StructureND.contentEquals(matrix, transposed) }
|
assertTrue { StructureND.contentEquals(matrix, transposed) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ class MatrixTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMatrixExtension() = Double.algebra.linearSpace.run {
|
fun testMatrixExtension() = Double.algebra.linearSpace.run {
|
||||||
val transitionMatrix: Matrix<Double> = VirtualMatrix(6, 6) { row, col ->
|
val transitionMatrix: Matrix<Double> = VirtualMatrix(type,6, 6) { row, col ->
|
||||||
when {
|
when {
|
||||||
col == 0 -> .50
|
col == 0 -> .50
|
||||||
row + 1 == col -> .50
|
row + 1 == col -> .50
|
||||||
@ -60,8 +59,8 @@ class MatrixTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test2DDot() = Double.algebra.linearSpace.run {
|
fun test2DDot() = Double.algebra.linearSpace.run {
|
||||||
val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D()
|
val firstMatrix = buildMatrix(2, 3) { i, j -> (i + j).toDouble() }
|
||||||
val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D()
|
val secondMatrix = buildMatrix(3, 2) { i, j -> (i + j).toDouble() }
|
||||||
|
|
||||||
// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
|
// val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() }
|
||||||
// val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() }
|
// val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() }
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.operations
|
package space.kscience.kmath.operations
|
||||||
|
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.math.MathContext
|
import java.math.MathContext
|
||||||
@ -13,6 +14,8 @@ import java.math.MathContext
|
|||||||
* A field over [BigInteger].
|
* A field over [BigInteger].
|
||||||
*/
|
*/
|
||||||
public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
|
public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
|
||||||
|
|
||||||
|
override val bufferFactory: MutableBufferFactory<BigInteger> = MutableBufferFactory()
|
||||||
override val zero: BigInteger get() = BigInteger.ZERO
|
override val zero: BigInteger get() = BigInteger.ZERO
|
||||||
|
|
||||||
override val one: BigInteger get() = BigInteger.ONE
|
override val one: BigInteger get() = BigInteger.ONE
|
||||||
@ -33,6 +36,7 @@ public object JBigIntegerField : Ring<BigInteger>, NumericAlgebra<BigInteger> {
|
|||||||
public abstract class JBigDecimalFieldBase internal constructor(
|
public abstract class JBigDecimalFieldBase internal constructor(
|
||||||
private val mathContext: MathContext = MathContext.DECIMAL64,
|
private val mathContext: MathContext = MathContext.DECIMAL64,
|
||||||
) : Field<BigDecimal>, PowerOperations<BigDecimal>, NumericAlgebra<BigDecimal>, ScaleOperations<BigDecimal> {
|
) : Field<BigDecimal>, PowerOperations<BigDecimal>, NumericAlgebra<BigDecimal>, ScaleOperations<BigDecimal> {
|
||||||
|
override val bufferFactory: MutableBufferFactory<BigDecimal> = MutableBufferFactory()
|
||||||
override val zero: BigDecimal
|
override val zero: BigDecimal
|
||||||
get() = BigDecimal.ZERO
|
get() = BigDecimal.ZERO
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public interface BlockingBufferChain<out T> : BlockingChain<T>, BufferChain<T> {
|
|||||||
public suspend inline fun <reified T : Any> Chain<T>.nextBuffer(size: Int): Buffer<T> = if (this is BufferChain) {
|
public suspend inline fun <reified T : Any> Chain<T>.nextBuffer(size: Int): Buffer<T> = if (this is BufferChain) {
|
||||||
nextBuffer(size)
|
nextBuffer(size)
|
||||||
} else {
|
} else {
|
||||||
Buffer.auto(size) { next() }
|
Buffer(size) { next() }
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
|
public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
|
||||||
@ -51,5 +51,5 @@ public inline fun <reified T : Any> BlockingChain<T>.nextBufferBlocking(
|
|||||||
): Buffer<T> = if (this is BlockingBufferChain) {
|
): Buffer<T> = if (this is BlockingBufferChain) {
|
||||||
nextBufferBlocking(size)
|
nextBufferBlocking(size)
|
||||||
} else {
|
} else {
|
||||||
Buffer.auto(size) { nextBlocking() }
|
Buffer(size) { nextBlocking() }
|
||||||
}
|
}
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.asFlow
|
|||||||
import kotlinx.coroutines.flow.flatMapConcat
|
import kotlinx.coroutines.flow.flatMapConcat
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import space.kscience.kmath.chains.BlockingDoubleChain
|
import space.kscience.kmath.chains.BlockingDoubleChain
|
||||||
|
import space.kscience.kmath.operations.Group
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.BufferFactory
|
import space.kscience.kmath.structures.BufferFactory
|
||||||
import space.kscience.kmath.structures.Float64Buffer
|
import space.kscience.kmath.structures.Float64Buffer
|
||||||
@ -84,9 +85,9 @@ public fun Flow<Double>.chunked(bufferSize: Int): Flow<Float64Buffer> = flow {
|
|||||||
* Map a flow to a moving window buffer. The window step is one.
|
* Map a flow to a moving window buffer. The window step is one.
|
||||||
* To get different steps, one could use skip operation.
|
* To get different steps, one could use skip operation.
|
||||||
*/
|
*/
|
||||||
public fun <T> Flow<T>.windowed(window: Int): Flow<Buffer<T>> = flow {
|
public fun <T> Flow<T>.windowed(window: Int, algebra: Group<T>): Flow<Buffer<T>> = flow {
|
||||||
require(window > 1) { "Window size must be more than one" }
|
require(window > 1) { "Window size must be more than one" }
|
||||||
val ringBuffer = RingBuffer.boxing<T>(window)
|
val ringBuffer = RingBuffer(window, algebra)
|
||||||
|
|
||||||
this@windowed.collect { element ->
|
this@windowed.collect { element ->
|
||||||
ringBuffer.push(element)
|
ringBuffer.push(element)
|
||||||
|
@ -7,6 +7,8 @@ package space.kscience.kmath.streaming
|
|||||||
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.kmath.operations.Group
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.MutableBuffer
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
import space.kscience.kmath.structures.VirtualBuffer
|
import space.kscience.kmath.structures.VirtualBuffer
|
||||||
@ -14,12 +16,14 @@ import space.kscience.kmath.structures.VirtualBuffer
|
|||||||
/**
|
/**
|
||||||
* Thread-safe ring buffer
|
* Thread-safe ring buffer
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
public class RingBuffer<T>(
|
public class RingBuffer<T>(
|
||||||
private val buffer: MutableBuffer<T?>,
|
private val buffer: MutableBuffer<T>,
|
||||||
private var startIndex: Int = 0,
|
private var startIndex: Int = 0,
|
||||||
size: Int = 0,
|
size: Int = 0,
|
||||||
) : Buffer<T> {
|
) : Buffer<T> {
|
||||||
|
|
||||||
|
override val type: SafeType<T> get() = buffer.type
|
||||||
|
|
||||||
private val mutex: Mutex = Mutex()
|
private val mutex: Mutex = Mutex()
|
||||||
|
|
||||||
override var size: Int = size
|
override var size: Int = size
|
||||||
@ -28,7 +32,7 @@ public class RingBuffer<T>(
|
|||||||
override operator fun get(index: Int): T {
|
override operator fun get(index: Int): T {
|
||||||
require(index >= 0) { "Index must be positive" }
|
require(index >= 0) { "Index must be positive" }
|
||||||
require(index < size) { "Index $index is out of circular buffer size $size" }
|
require(index < size) { "Index $index is out of circular buffer size $size" }
|
||||||
return buffer[startIndex.forward(index)] as T
|
return buffer[startIndex.forward(index)]
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun isFull(): Boolean = size == buffer.size
|
public fun isFull(): Boolean = size == buffer.size
|
||||||
@ -43,7 +47,7 @@ public class RingBuffer<T>(
|
|||||||
|
|
||||||
override fun computeNext() {
|
override fun computeNext() {
|
||||||
if (count == 0) done() else {
|
if (count == 0) done() else {
|
||||||
setNext(copy[index] as T)
|
setNext(copy[index])
|
||||||
index = index.forward(1)
|
index = index.forward(1)
|
||||||
count--
|
count--
|
||||||
}
|
}
|
||||||
@ -55,7 +59,7 @@ public class RingBuffer<T>(
|
|||||||
*/
|
*/
|
||||||
public suspend fun snapshot(): Buffer<T> = mutex.withLock {
|
public suspend fun snapshot(): Buffer<T> = mutex.withLock {
|
||||||
val copy = buffer.copy()
|
val copy = buffer.copy()
|
||||||
VirtualBuffer(size) { i -> copy[startIndex.forward(i)] as T }
|
VirtualBuffer(type, size) { i -> copy[startIndex.forward(i)] }
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun push(element: T) {
|
public suspend fun push(element: T) {
|
||||||
@ -68,19 +72,17 @@ public class RingBuffer<T>(
|
|||||||
private fun Int.forward(n: Int): Int = (this + n) % (buffer.size)
|
private fun Int.forward(n: Int): Int = (this + n) % (buffer.size)
|
||||||
|
|
||||||
override fun toString(): String = Buffer.toString(this)
|
override fun toString(): String = Buffer.toString(this)
|
||||||
|
}
|
||||||
public companion object {
|
|
||||||
public inline fun <reified T : Any> build(size: Int, empty: T): RingBuffer<T> {
|
public inline fun <reified T : Any> RingBuffer(size: Int, empty: T): RingBuffer<T> {
|
||||||
val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer<T?>
|
val buffer = MutableBuffer(size) { empty }
|
||||||
return RingBuffer(buffer)
|
return RingBuffer(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slow yet universal buffer
|
* Slow yet universal buffer
|
||||||
*/
|
*/
|
||||||
public fun <T> boxing(size: Int): RingBuffer<T> {
|
public fun <T> RingBuffer(size: Int, algebra: Group<T>): RingBuffer<T> {
|
||||||
val buffer: MutableBuffer<T?> = MutableBuffer.boxing(size) { null }
|
val buffer: MutableBuffer<T> = MutableBuffer(algebra.type, size) { algebra.zero }
|
||||||
return RingBuffer(buffer)
|
return RingBuffer(buffer)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.structures
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.safeTypeOf
|
||||||
import space.kscience.kmath.PerformancePitfall
|
import space.kscience.kmath.PerformancePitfall
|
||||||
import space.kscience.kmath.coroutines.Math
|
import space.kscience.kmath.coroutines.Math
|
||||||
import space.kscience.kmath.nd.ColumnStrides
|
import space.kscience.kmath.nd.ColumnStrides
|
||||||
@ -14,9 +16,11 @@ import space.kscience.kmath.nd.StructureND
|
|||||||
|
|
||||||
public class LazyStructureND<out T>(
|
public class LazyStructureND<out T>(
|
||||||
public val scope: CoroutineScope,
|
public val scope: CoroutineScope,
|
||||||
|
override val type: SafeType<T>,
|
||||||
override val shape: ShapeND,
|
override val shape: ShapeND,
|
||||||
public val function: suspend (IntArray) -> T,
|
public val function: suspend (IntArray) -> T,
|
||||||
) : StructureND<T> {
|
) : StructureND<T> {
|
||||||
|
|
||||||
private val cache: MutableMap<IntArray, Deferred<T>> = HashMap()
|
private val cache: MutableMap<IntArray, Deferred<T>> = HashMap()
|
||||||
|
|
||||||
public fun async(index: IntArray): Deferred<T> = cache.getOrPut(index) {
|
public fun async(index: IntArray): Deferred<T> = cache.getOrPut(index) {
|
||||||
@ -47,13 +51,13 @@ public suspend fun <T> StructureND<T>.await(index: IntArray): T =
|
|||||||
* PENDING would benefit from KEEP-176
|
* PENDING would benefit from KEEP-176
|
||||||
*/
|
*/
|
||||||
@OptIn(PerformancePitfall::class)
|
@OptIn(PerformancePitfall::class)
|
||||||
public inline fun <T, R> StructureND<T>.mapAsyncIndexed(
|
public inline fun <T, reified R> StructureND<T>.mapAsyncIndexed(
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
crossinline function: suspend (T, index: IntArray) -> R,
|
crossinline function: suspend (T, index: IntArray) -> R,
|
||||||
): LazyStructureND<R> = LazyStructureND(scope, shape) { index -> function(get(index), index) }
|
): LazyStructureND<R> = LazyStructureND(scope, safeTypeOf(), shape) { index -> function(get(index), index) }
|
||||||
|
|
||||||
@OptIn(PerformancePitfall::class)
|
@OptIn(PerformancePitfall::class)
|
||||||
public inline fun <T, R> StructureND<T>.mapAsync(
|
public inline fun <T, reified R> StructureND<T>.mapAsync(
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
crossinline function: suspend (T) -> R,
|
crossinline function: suspend (T) -> R,
|
||||||
): LazyStructureND<R> = LazyStructureND(scope, shape) { index -> function(get(index)) }
|
): LazyStructureND<R> = LazyStructureND(scope, safeTypeOf(), shape) { index -> function(get(index)) }
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.dimensions
|
package space.kscience.kmath.dimensions
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
import space.kscience.kmath.linear.*
|
import space.kscience.kmath.linear.*
|
||||||
import space.kscience.kmath.nd.ShapeND
|
import space.kscience.kmath.nd.ShapeND
|
||||||
import space.kscience.kmath.nd.Structure2D
|
import space.kscience.kmath.nd.Structure2D
|
||||||
@ -48,6 +49,9 @@ public interface DMatrix<out T, R : Dimension, C : Dimension> : Structure2D<T> {
|
|||||||
public value class DMatrixWrapper<out T, R : Dimension, C : Dimension>(
|
public value class DMatrixWrapper<out T, R : Dimension, C : Dimension>(
|
||||||
private val structure: Structure2D<T>,
|
private val structure: Structure2D<T>,
|
||||||
) : DMatrix<T, R, C> {
|
) : DMatrix<T, R, C> {
|
||||||
|
|
||||||
|
override val type: SafeType<T> get() = structure.type
|
||||||
|
|
||||||
override val shape: ShapeND get() = structure.shape
|
override val shape: ShapeND get() = structure.shape
|
||||||
override val rowNum: Int get() = shape[0]
|
override val rowNum: Int get() = shape[0]
|
||||||
override val colNum: Int get() = shape[1]
|
override val colNum: Int get() = shape[1]
|
||||||
@ -75,8 +79,10 @@ public interface DPoint<out T, D : Dimension> : Point<T> {
|
|||||||
* Dimension-safe point wrapper
|
* Dimension-safe point wrapper
|
||||||
*/
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class DPointWrapper<out T, D : Dimension>(public val point: Point<T>) :
|
public value class DPointWrapper<out T, D : Dimension>(public val point: Point<T>) : DPoint<T, D> {
|
||||||
DPoint<T, D> {
|
|
||||||
|
override val type: SafeType<T> get() = point.type
|
||||||
|
|
||||||
override val size: Int get() = point.size
|
override val size: Int get() = point.size
|
||||||
|
|
||||||
override operator fun get(index: Int): T = point[index]
|
override operator fun get(index: Int): T = point[index]
|
||||||
|
@ -6,14 +6,9 @@
|
|||||||
package space.kscience.kmath.ejml
|
package space.kscience.kmath.ejml
|
||||||
|
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.linear.InverseMatrixFeature
|
import space.kscience.kmath.linear.*
|
||||||
import space.kscience.kmath.linear.LinearSpace
|
import space.kscience.kmath.operations.Float64Field
|
||||||
import space.kscience.kmath.linear.Matrix
|
|
||||||
import space.kscience.kmath.linear.Point
|
|
||||||
import space.kscience.kmath.nd.Structure2D
|
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [LinearSpace] implementation specialized for a certain EJML type.
|
* [LinearSpace] implementation specialized for a certain EJML type.
|
||||||
@ -42,8 +37,7 @@ public abstract class EjmlLinearSpace<T : Any, out A : Ring<T>, out M : org.ejml
|
|||||||
|
|
||||||
public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector<T, M>
|
public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector<T, M>
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public fun EjmlMatrix<T, *>.inverse(): Structure2D<Double> =
|
public fun EjmlMatrix<T, *>.inverted(): Matrix<Double> =
|
||||||
attributeFor(this, InverseMatrixFeature::class)?.inverse as Structure2D<Double>
|
attributeFor(this, Float64Field.linearSpace.Inverted)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ internal class EjmlMatrixTest {
|
|||||||
val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 }
|
||||||
val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 }
|
||||||
val matrix = space { l dot u }
|
val matrix = space { l dot u }
|
||||||
val inverted = matrix.toEjml().inverse()
|
val inverted = matrix.toEjml().inverted()
|
||||||
|
|
||||||
val res = matrix dot inverted
|
val res = matrix dot inverted
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ public fun Sequence<DoubleArray>.toMatrix(): RealMatrix = toList().let {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix =
|
public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix =
|
||||||
VirtualMatrix(rowNum * n, colNum) { row, col ->
|
VirtualMatrix(type, rowNum * n, colNum) { row, col ->
|
||||||
get(if (row == 0) 0 else row % rowNum, col)
|
get(if (row == 0) 0 else row % rowNum, col)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,14 +7,12 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.functions
|
package space.kscience.kmath.functions
|
||||||
|
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
import space.kscience.kmath.operations.ScaleOperations
|
import space.kscience.kmath.operations.ScaleOperations
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,6 +65,7 @@ public data class Polynomial<out C>(
|
|||||||
public open class PolynomialSpace<C, A>(
|
public open class PolynomialSpace<C, A>(
|
||||||
public val ring: A,
|
public val ring: A,
|
||||||
) : Ring<Polynomial<C>>, ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
|
) : Ring<Polynomial<C>>, ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
|
||||||
|
override val bufferFactory: MutableBufferFactory<Polynomial<C>> get() = MutableBufferFactory()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of zero constant (zero of the underlying ring).
|
* Instance of zero constant (zero of the underlying ring).
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.integration
|
package space.kscience.kmath.integration
|
||||||
|
|
||||||
|
import space.kscience.kmath.operations.Float64Field
|
||||||
import space.kscience.kmath.operations.mapToBuffer
|
import space.kscience.kmath.operations.mapToBuffer
|
||||||
import space.kscience.kmath.structures.Buffer
|
import space.kscience.kmath.structures.Buffer
|
||||||
import space.kscience.kmath.structures.Float64Buffer
|
import space.kscience.kmath.structures.Float64Buffer
|
||||||
@ -32,11 +33,11 @@ public fun GaussIntegratorRuleFactory.build(
|
|||||||
val normalized: Pair<Buffer<Double>, Buffer<Double>> = build(numPoints)
|
val normalized: Pair<Buffer<Double>, Buffer<Double>> = build(numPoints)
|
||||||
val length = range.endInclusive - range.start
|
val length = range.endInclusive - range.start
|
||||||
|
|
||||||
val points = normalized.first.mapToBuffer(::Float64Buffer) {
|
val points = normalized.first.mapToBuffer(Float64Field.bufferFactory) {
|
||||||
range.start + length / 2 + length / 2 * it
|
range.start + length / 2 + length / 2 * it
|
||||||
}
|
}
|
||||||
|
|
||||||
val weights = normalized.second.mapToBuffer(::Float64Buffer) {
|
val weights = normalized.second.mapToBuffer(Float64Field.bufferFactory) {
|
||||||
it * length / 2
|
it * length / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ public class SplineIntegrator<T : Comparable<T>>(
|
|||||||
public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
|
public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
|
||||||
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
|
override fun integrate(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
|
||||||
val range = integrand[IntegrationRange] ?: 0.0..1.0
|
val range = integrand[IntegrationRange] ?: 0.0..1.0
|
||||||
val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(Float64Field, ::Float64Buffer)
|
val interpolator: PolynomialInterpolator<Double> = SplineInterpolator(Float64Field, Float64Field.bufferFactory)
|
||||||
|
|
||||||
val nodes: Buffer<Double> = integrand[UnivariateIntegrationNodes] ?: run {
|
val nodes: Buffer<Double> = integrand[UnivariateIntegrationNodes] ?: run {
|
||||||
val numPoints = integrand[IntegrandMaxCalls] ?: 100
|
val numPoints = integrand[IntegrandMaxCalls] ?: 100
|
||||||
@ -96,7 +96,7 @@ public object DoubleSplineIntegrator : UnivariateIntegrator<Double> {
|
|||||||
Float64Buffer(numPoints) { i -> range.start + i * step }
|
Float64Buffer(numPoints) { i -> range.start + i * step }
|
||||||
}
|
}
|
||||||
|
|
||||||
val values = nodes.mapToBuffer(::Float64Buffer) { integrand.function(it) }
|
val values = nodes.mapToBuffer(Float64Field.bufferFactory) { integrand.function(it) }
|
||||||
val polynomials = interpolator.interpolatePolynomials(nodes, values)
|
val polynomials = interpolator.interpolatePolynomials(nodes, values)
|
||||||
val res = polynomials.integrate(Float64Field, range)
|
val res = polynomials.integrate(Float64Field, range)
|
||||||
return integrand.withAttributes {
|
return integrand.withAttributes {
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.interpolation
|
package space.kscience.kmath.interpolation
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
import space.kscience.kmath.UnstableKMathAPI
|
import space.kscience.kmath.UnstableKMathAPI
|
||||||
import space.kscience.kmath.data.XYColumnarData
|
import space.kscience.kmath.data.XYColumnarData
|
||||||
import space.kscience.kmath.functions.PiecewisePolynomial
|
import space.kscience.kmath.functions.PiecewisePolynomial
|
||||||
@ -26,9 +28,11 @@ public fun interface Interpolator<T, in X : T, Y : T> {
|
|||||||
/**
|
/**
|
||||||
* And interpolator returning [PiecewisePolynomial] function
|
* And interpolator returning [PiecewisePolynomial] function
|
||||||
*/
|
*/
|
||||||
public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T> {
|
public interface PolynomialInterpolator<T : Comparable<T>> : Interpolator<T, T, T>, WithType<T> {
|
||||||
public val algebra: Ring<T>
|
public val algebra: Ring<T>
|
||||||
|
|
||||||
|
override val type: SafeType<T> get() = algebra.type
|
||||||
|
|
||||||
public fun getDefaultValue(): T = error("Out of bounds")
|
public fun getDefaultValue(): T = error("Out of bounds")
|
||||||
|
|
||||||
public fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T>
|
public fun interpolatePolynomials(points: XYColumnarData<T, T, T>): PiecewisePolynomial<T>
|
||||||
@ -50,14 +54,14 @@ public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
|
|||||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
|
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
|
||||||
data: Map<T, T>,
|
data: Map<T, T>,
|
||||||
): PiecewisePolynomial<T> {
|
): PiecewisePolynomial<T> {
|
||||||
val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer())
|
val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(type), data.values.toList().asBuffer(type))
|
||||||
return interpolatePolynomials(pointSet)
|
return interpolatePolynomials(pointSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
|
public fun <T : Comparable<T>> PolynomialInterpolator<T>.interpolatePolynomials(
|
||||||
data: List<Pair<T, T>>,
|
data: List<Pair<T, T>>,
|
||||||
): PiecewisePolynomial<T> {
|
): PiecewisePolynomial<T> {
|
||||||
val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer())
|
val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(type), data.map { it.second }.asBuffer(type))
|
||||||
return interpolatePolynomials(pointSet)
|
return interpolatePolynomials(pointSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import space.kscience.kmath.functions.Polynomial
|
|||||||
import space.kscience.kmath.operations.Field
|
import space.kscience.kmath.operations.Field
|
||||||
import space.kscience.kmath.operations.Float64Field
|
import space.kscience.kmath.operations.Float64Field
|
||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.structures.Float64Buffer
|
|
||||||
import space.kscience.kmath.structures.MutableBufferFactory
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,4 +79,4 @@ public fun <T : Comparable<T>> Field<T>.splineInterpolator(
|
|||||||
): SplineInterpolator<T> = SplineInterpolator(this, bufferFactory)
|
): SplineInterpolator<T> = SplineInterpolator(this, bufferFactory)
|
||||||
|
|
||||||
public val Float64Field.splineInterpolator: SplineInterpolator<Double>
|
public val Float64Field.splineInterpolator: SplineInterpolator<Double>
|
||||||
get() = SplineInterpolator(this, ::Float64Buffer)
|
get() = SplineInterpolator(this, bufferFactory)
|
@ -7,6 +7,10 @@ kscience {
|
|||||||
js()
|
js()
|
||||||
native()
|
native()
|
||||||
wasm()
|
wasm()
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(projects.kmathCore)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2022 KMath contributors.
|
* Copyright 2018-2023 KMath contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package space.kscience.kmath.structures
|
package space.kscience.kmath.memory
|
||||||
|
|
||||||
import space.kscience.kmath.memory.*
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.kmath.structures.Buffer
|
||||||
|
import space.kscience.kmath.structures.MutableBuffer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A non-boxing buffer over [Memory] object.
|
* A non-boxing buffer over [Memory] object.
|
||||||
@ -15,6 +17,9 @@ import space.kscience.kmath.memory.*
|
|||||||
* @property spec the spec of [T] type.
|
* @property spec the spec of [T] type.
|
||||||
*/
|
*/
|
||||||
public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
|
public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected val spec: MemorySpec<T>) : Buffer<T> {
|
||||||
|
|
||||||
|
override val type: SafeType<T> get() = spec.type
|
||||||
|
|
||||||
override val size: Int get() = memory.size / spec.objectSize
|
override val size: Int get() = memory.size / spec.objectSize
|
||||||
|
|
||||||
override operator fun get(index: Int): T = memory.read { read(spec, spec.objectSize * index) }
|
override operator fun get(index: Int): T = memory.read { read(spec, spec.objectSize * index) }
|
||||||
@ -43,8 +48,10 @@ public open class MemoryBuffer<T : Any>(protected val memory: Memory, protected
|
|||||||
* @property memory the underlying memory segment.
|
* @property memory the underlying memory segment.
|
||||||
* @property spec the spec of [T] type.
|
* @property spec the spec of [T] type.
|
||||||
*/
|
*/
|
||||||
public class MutableMemoryBuffer<T : Any>(memory: Memory, spec: MemorySpec<T>) : MemoryBuffer<T>(memory, spec),
|
public class MutableMemoryBuffer<T : Any>(
|
||||||
MutableBuffer<T> {
|
memory: Memory,
|
||||||
|
spec: MemorySpec<T>,
|
||||||
|
) : MemoryBuffer<T>(memory, spec), MutableBuffer<T> {
|
||||||
|
|
||||||
private val writer: MemoryWriter = memory.writer()
|
private val writer: MemoryWriter = memory.writer()
|
||||||
|
|
@ -5,12 +5,15 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.memory
|
package space.kscience.kmath.memory
|
||||||
|
|
||||||
|
import space.kscience.attributes.WithType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A specification to read or write custom objects with fixed size in bytes.
|
* A specification to read or write custom objects with fixed size in bytes.
|
||||||
*
|
*
|
||||||
* @param T the type of object this spec manages.
|
* @param T the type of object this spec manages.
|
||||||
*/
|
*/
|
||||||
public interface MemorySpec<T : Any> {
|
public interface MemorySpec<T : Any>: WithType<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of [T] in bytes after serialization.
|
* Size of [T] in bytes after serialization.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user