forked from kscience/kmath
0.4 WIP
This commit is contained in:
parent
2386ecba41
commit
2f2f552648
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
package space.kscience.attributes
|
package space.kscience.attributes
|
||||||
|
|
||||||
import kotlin.reflect.KType
|
|
||||||
|
|
||||||
public interface Attribute<T>
|
public interface Attribute<T>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,7 +8,7 @@ package space.kscience.attributes
|
|||||||
import kotlin.jvm.JvmInline
|
import kotlin.jvm.JvmInline
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
public value class Attributes internal constructor(public val content: Map<out Attribute<*>, Any>) {
|
public value class Attributes internal constructor(public val content: Map<out Attribute<*>, Any?>) {
|
||||||
|
|
||||||
public val keys: Set<Attribute<*>> get() = content.keys
|
public val keys: Set<Attribute<*>> get() = content.keys
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ public inline fun <reified A : FlagAttribute> Attributes.has(): Boolean =
|
|||||||
/**
|
/**
|
||||||
* Create [Attributes] with an added or replaced attribute key.
|
* Create [Attributes] with an added or replaced attribute key.
|
||||||
*/
|
*/
|
||||||
public fun <T : Any, A : Attribute<T>> Attributes.withAttribute(
|
public fun <T, A : Attribute<T>> Attributes.withAttribute(
|
||||||
attribute: A,
|
attribute: A,
|
||||||
attrValue: T,
|
attrValue: T,
|
||||||
): Attributes = Attributes(content + (attribute to attrValue))
|
): Attributes = Attributes(content + (attribute to attrValue))
|
||||||
@ -101,7 +101,7 @@ public fun <T, A : SetAttribute<T>> Attributes.withoutAttributeElement(
|
|||||||
/**
|
/**
|
||||||
* Create [Attributes] with a single key
|
* Create [Attributes] with a single key
|
||||||
*/
|
*/
|
||||||
public fun <T : Any, A : Attribute<T>> Attributes(
|
public fun <T, A : Attribute<T>> Attributes(
|
||||||
attribute: A,
|
attribute: A,
|
||||||
attrValue: T,
|
attrValue: T,
|
||||||
): Attributes = Attributes(mapOf(attribute to attrValue))
|
): Attributes = Attributes(mapOf(attribute to attrValue))
|
||||||
|
@ -10,7 +10,7 @@ package space.kscience.attributes
|
|||||||
*
|
*
|
||||||
* @param O type marker of an owner object, for which these attributes are made
|
* @param O type marker of an owner object, for which these attributes are made
|
||||||
*/
|
*/
|
||||||
public class TypedAttributesBuilder<in O> internal constructor(private val map: MutableMap<Attribute<*>, Any>) {
|
public class TypedAttributesBuilder<in O> internal constructor(private val map: MutableMap<Attribute<*>, Any?>) {
|
||||||
|
|
||||||
public constructor() : this(mutableMapOf())
|
public constructor() : this(mutableMapOf())
|
||||||
|
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.linear
|
package space.kscience.kmath.linear
|
||||||
|
|
||||||
|
import space.kscience.attributes.Attributes
|
||||||
import space.kscience.attributes.SafeType
|
import space.kscience.attributes.SafeType
|
||||||
import space.kscience.attributes.WithType
|
import space.kscience.attributes.WithType
|
||||||
|
import space.kscience.attributes.withAttribute
|
||||||
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
|
||||||
@ -173,15 +175,36 @@ 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 attributes are preferred to computed attributes.
|
* Compute an [attribute] value for given [structure]. Return null if the attribute could not be computed.
|
||||||
|
*/
|
||||||
|
public fun <V, A : StructureAttribute<V>> computeAttribute(structure: StructureND<*>, attribute: A): V? = null
|
||||||
|
|
||||||
|
@UnstableKMathAPI
|
||||||
|
public fun <V, A : StructureAttribute<V>> StructureND<*>.getOrComputeAttribute(attribute: A): V? {
|
||||||
|
return attributes[attribute] ?: computeAttribute(this, attribute)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the structure holds given [attribute] return itself. Otherwise, return a new [Matrix] that contains a computed attribute.
|
||||||
*
|
*
|
||||||
* @param structure the structure.
|
* This method is used to compute and cache attribute inside the structure. If one needs an attribute only once,
|
||||||
* @param attribute to be computed.
|
* better use [StructureND.getOrComputeAttribute].
|
||||||
* @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 <V : Any, A : StructureAttribute<V>> Matrix<T>.compute(
|
||||||
structure.attributes[attribute] ?: error("Can't compute attribute $attribute for $structure")
|
attribute: A,
|
||||||
|
): Matrix<T>? {
|
||||||
|
return if (attributes[attribute] != null) {
|
||||||
|
this
|
||||||
|
} else {
|
||||||
|
val value = computeAttribute(this, attribute) ?: return null
|
||||||
|
if (this is MatrixWrapper) {
|
||||||
|
MatrixWrapper(this, attributes.withAttribute(attribute, value))
|
||||||
|
} else {
|
||||||
|
MatrixWrapper(this, Attributes(attribute, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
|
@ -209,8 +209,8 @@ public fun <T : Comparable<T>, F : Field<T>> LinearSpace<T, F>.lupSolver(
|
|||||||
singularityCheck: (T) -> Boolean,
|
singularityCheck: (T) -> Boolean,
|
||||||
): LinearSolver<T> = object : LinearSolver<T> {
|
): LinearSolver<T> = object : LinearSolver<T> {
|
||||||
override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> {
|
override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> {
|
||||||
// Use existing decomposition if it is provided by matrix
|
// Use existing decomposition if it is provided by matrix or linear space itself
|
||||||
val decomposition = attributeFor(a, LUP) ?: lup(a, singularityCheck)
|
val decomposition = a.getOrComputeAttribute(LUP) ?: lup(a, singularityCheck)
|
||||||
return solve(decomposition, b)
|
return solve(decomposition, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,5 +39,5 @@ public abstract class EjmlLinearSpace<T : Any, out A : Ring<T>, out M : org.ejml
|
|||||||
|
|
||||||
@UnstableKMathAPI
|
@UnstableKMathAPI
|
||||||
public fun EjmlMatrix<T, *>.inverted(): Matrix<Double> =
|
public fun EjmlMatrix<T, *>.inverted(): Matrix<Double> =
|
||||||
attributeFor(this, Float64Field.linearSpace.Inverted)
|
attributeForOrNull(this, Float64Field.linearSpace.Inverted)
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,9 @@ internal class EjmlMatrixTest {
|
|||||||
fun features() {
|
fun features() {
|
||||||
val m = randomMatrix
|
val m = randomMatrix
|
||||||
val w = EjmlDoubleMatrix(m)
|
val w = EjmlDoubleMatrix(m)
|
||||||
val det: Determinant<Double> = EjmlLinearSpaceDDRM.attributeFor(w) ?: fail()
|
val det: Determinant<Double> = EjmlLinearSpaceDDRM.attributeForOrNull(w) ?: fail()
|
||||||
assertEquals(CommonOps_DDRM.det(m), det.determinant)
|
assertEquals(CommonOps_DDRM.det(m), det.determinant)
|
||||||
val lup: LupDecompositionAttribute<Double> = EjmlLinearSpaceDDRM.attributeFor(w) ?: fail()
|
val lup: LupDecompositionAttribute<Double> = EjmlLinearSpaceDDRM.attributeForOrNull(w) ?: fail()
|
||||||
|
|
||||||
val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols)
|
val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols)
|
||||||
.also { it.decompose(m.copy()) }
|
.also { it.decompose(m.copy()) }
|
||||||
|
@ -12,8 +12,6 @@ import space.kscience.kmath.chains.combine
|
|||||||
import space.kscience.kmath.random.RandomGenerator
|
import space.kscience.kmath.random.RandomGenerator
|
||||||
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.Int32Buffer
|
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,7 +34,7 @@ public fun interface Sampler<out T : Any> {
|
|||||||
public fun <T : Any> Sampler<T>.sampleBuffer(
|
public fun <T : Any> Sampler<T>.sampleBuffer(
|
||||||
generator: RandomGenerator,
|
generator: RandomGenerator,
|
||||||
size: Int,
|
size: Int,
|
||||||
bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
|
bufferFactory: BufferFactory<T>
|
||||||
): Chain<Buffer<T>> {
|
): Chain<Buffer<T>> {
|
||||||
require(size > 1)
|
require(size > 1)
|
||||||
//creating temporary storage once
|
//creating temporary storage once
|
||||||
@ -58,18 +56,11 @@ public fun <T : Any> Sampler<T>.sampleBuffer(
|
|||||||
public suspend fun <T : Any> Sampler<T>.next(generator: RandomGenerator): T = sample(generator).first()
|
public suspend fun <T : Any> Sampler<T>.next(generator: RandomGenerator): T = sample(generator).first()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates [size] real samples and chunks them into some buffers.
|
* Generates [size] samples and chunks them into some buffers.
|
||||||
*/
|
*/
|
||||||
@JvmName("sampleRealBuffer")
|
@JvmName("sampleRealBuffer")
|
||||||
public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> =
|
public inline fun <reified T:Any> Sampler<T>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<T>> =
|
||||||
sampleBuffer(generator, size, ::Float64Buffer)
|
sampleBuffer(generator, size, BufferFactory())
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates [size] integer samples and chunks them into some buffers.
|
|
||||||
*/
|
|
||||||
@JvmName("sampleIntBuffer")
|
|
||||||
public fun Sampler<Int>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Int>> =
|
|
||||||
sampleBuffer(generator, size, ::Int32Buffer)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,6 +14,7 @@ import space.kscience.kmath.operations.ScaleOperations
|
|||||||
import space.kscience.kmath.operations.invoke
|
import space.kscience.kmath.operations.invoke
|
||||||
import space.kscience.kmath.random.RandomGenerator
|
import space.kscience.kmath.random.RandomGenerator
|
||||||
import space.kscience.kmath.stat.Sampler
|
import space.kscience.kmath.stat.Sampler
|
||||||
|
import space.kscience.kmath.structures.MutableBufferFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements [Sampler] by sampling only certain [value].
|
* Implements [Sampler] by sampling only certain [value].
|
||||||
@ -41,6 +42,8 @@ public class BasicSampler<out T : Any>(public val chainBuilder: (RandomGenerator
|
|||||||
public class SamplerSpace<T : Any, out S>(public val algebra: S) : Group<Sampler<T>>,
|
public class SamplerSpace<T : Any, out S>(public val algebra: S) : Group<Sampler<T>>,
|
||||||
ScaleOperations<Sampler<T>> where S : Group<T>, S : ScaleOperations<T> {
|
ScaleOperations<Sampler<T>> where S : Group<T>, S : ScaleOperations<T> {
|
||||||
|
|
||||||
|
override val bufferFactory: MutableBufferFactory<Sampler<T>> = MutableBufferFactory()
|
||||||
|
|
||||||
override val zero: Sampler<T> = ConstantSampler(algebra.zero)
|
override val zero: Sampler<T> = ConstantSampler(algebra.zero)
|
||||||
|
|
||||||
override fun add(left: Sampler<T>, right: Sampler<T>): Sampler<T> = BasicSampler { generator ->
|
override fun add(left: Sampler<T>, right: Sampler<T>): Sampler<T> = BasicSampler { generator ->
|
||||||
|
@ -5,10 +5,14 @@
|
|||||||
|
|
||||||
package space.kscience.kmath.stat
|
package space.kscience.kmath.stat
|
||||||
|
|
||||||
|
import space.kscience.attributes.SafeType
|
||||||
|
import space.kscience.attributes.safeTypeOf
|
||||||
import space.kscience.kmath.operations.Field
|
import space.kscience.kmath.operations.Field
|
||||||
|
import space.kscience.kmath.structures.*
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A combination of a random [value] and its [dispersion].
|
* A combination of a random [value] and its [dispersion].
|
||||||
*
|
*
|
||||||
@ -53,4 +57,48 @@ public object ValueAndErrorField : Field<ValueAndError> {
|
|||||||
|
|
||||||
override fun scale(a: ValueAndError, value: Double): ValueAndError =
|
override fun scale(a: ValueAndError, value: Double): ValueAndError =
|
||||||
ValueAndError(a.value * value, a.dispersion * value.pow(2))
|
ValueAndError(a.value * value, a.dispersion * value.pow(2))
|
||||||
|
|
||||||
|
|
||||||
|
private class ValueAndErrorBuffer(val values: DoubleBuffer, val ds: DoubleBuffer) : MutableBuffer<ValueAndError> {
|
||||||
|
init {
|
||||||
|
require(values.size == ds.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val type: SafeType<ValueAndError> get() = safeTypeOf()
|
||||||
|
override val size: Int
|
||||||
|
get() = values.size
|
||||||
|
|
||||||
|
override fun get(index: Int): ValueAndError = ValueAndError(values[index], ds[index])
|
||||||
|
|
||||||
|
override fun toString(): String = Buffer.toString(this)
|
||||||
|
|
||||||
|
override fun set(index: Int, value: ValueAndError) {
|
||||||
|
values[index] = value.value
|
||||||
|
values[index] = value.dispersion
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copy(): MutableBuffer<ValueAndError> = ValueAndErrorBuffer(values.copy(), ds.copy())
|
||||||
|
}
|
||||||
|
|
||||||
|
override val bufferFactory: MutableBufferFactory<ValueAndError> = object : MutableBufferFactory<ValueAndError> {
|
||||||
|
override fun invoke(
|
||||||
|
size: Int,
|
||||||
|
builder: (Int) -> ValueAndError,
|
||||||
|
): MutableBuffer<ValueAndError> {
|
||||||
|
val values: DoubleArray = DoubleArray(size)
|
||||||
|
val ds = DoubleArray(size)
|
||||||
|
repeat(size){
|
||||||
|
val (v, d) = builder(it)
|
||||||
|
values[it] = v
|
||||||
|
ds[it] = d
|
||||||
|
}
|
||||||
|
return ValueAndErrorBuffer(
|
||||||
|
values.asBuffer(),
|
||||||
|
ds.asBuffer()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val type: SafeType<ValueAndError> get() = safeTypeOf()
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user