forked from kscience/kmath
0.4 WIP
This commit is contained in:
parent
2386ecba41
commit
2f2f552648
@ -5,8 +5,6 @@
|
||||
|
||||
package space.kscience.attributes
|
||||
|
||||
import kotlin.reflect.KType
|
||||
|
||||
public interface Attribute<T>
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,7 @@ package space.kscience.attributes
|
||||
import kotlin.jvm.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
|
||||
|
||||
@ -51,7 +51,7 @@ public inline fun <reified A : FlagAttribute> Attributes.has(): Boolean =
|
||||
/**
|
||||
* 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,
|
||||
attrValue: T,
|
||||
): Attributes = Attributes(content + (attribute to attrValue))
|
||||
@ -101,7 +101,7 @@ public fun <T, A : SetAttribute<T>> Attributes.withoutAttributeElement(
|
||||
/**
|
||||
* Create [Attributes] with a single key
|
||||
*/
|
||||
public fun <T : Any, A : Attribute<T>> Attributes(
|
||||
public fun <T, A : Attribute<T>> Attributes(
|
||||
attribute: A,
|
||||
attrValue: T,
|
||||
): 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
|
||||
*/
|
||||
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())
|
||||
|
||||
|
@ -5,8 +5,10 @@
|
||||
|
||||
package space.kscience.kmath.linear
|
||||
|
||||
import space.kscience.attributes.Attributes
|
||||
import space.kscience.attributes.SafeType
|
||||
import space.kscience.attributes.WithType
|
||||
import space.kscience.attributes.withAttribute
|
||||
import space.kscience.kmath.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.*
|
||||
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
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param attribute to be computed.
|
||||
* @return a feature object or `null` if it isn't present.
|
||||
* This method is used to compute and cache attribute inside the structure. If one needs an attribute only once,
|
||||
* better use [StructureND.getOrComputeAttribute].
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T =
|
||||
structure.attributes[attribute] ?: error("Can't compute attribute $attribute for $structure")
|
||||
public fun <V : Any, A : StructureAttribute<V>> Matrix<T>.compute(
|
||||
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 {
|
||||
|
||||
|
@ -209,8 +209,8 @@ public fun <T : Comparable<T>, F : Field<T>> LinearSpace<T, F>.lupSolver(
|
||||
singularityCheck: (T) -> Boolean,
|
||||
): LinearSolver<T> = object : LinearSolver<T> {
|
||||
override fun solve(a: Matrix<T>, b: Matrix<T>): Matrix<T> {
|
||||
// Use existing decomposition if it is provided by matrix
|
||||
val decomposition = attributeFor(a, LUP) ?: lup(a, singularityCheck)
|
||||
// Use existing decomposition if it is provided by matrix or linear space itself
|
||||
val decomposition = a.getOrComputeAttribute(LUP) ?: lup(a, singularityCheck)
|
||||
return solve(decomposition, b)
|
||||
}
|
||||
|
||||
|
@ -39,5 +39,5 @@ public abstract class EjmlLinearSpace<T : Any, out A : Ring<T>, out M : org.ejml
|
||||
|
||||
@UnstableKMathAPI
|
||||
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() {
|
||||
val m = randomMatrix
|
||||
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)
|
||||
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)
|
||||
.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.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import space.kscience.kmath.structures.Float64Buffer
|
||||
import space.kscience.kmath.structures.Int32Buffer
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
@ -36,7 +34,7 @@ public fun interface Sampler<out T : Any> {
|
||||
public fun <T : Any> Sampler<T>.sampleBuffer(
|
||||
generator: RandomGenerator,
|
||||
size: Int,
|
||||
bufferFactory: BufferFactory<T> = BufferFactory.boxing(),
|
||||
bufferFactory: BufferFactory<T>
|
||||
): Chain<Buffer<T>> {
|
||||
require(size > 1)
|
||||
//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()
|
||||
|
||||
/**
|
||||
* Generates [size] real samples and chunks them into some buffers.
|
||||
* Generates [size] samples and chunks them into some buffers.
|
||||
*/
|
||||
@JvmName("sampleRealBuffer")
|
||||
public fun Sampler<Double>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<Double>> =
|
||||
sampleBuffer(generator, size, ::Float64Buffer)
|
||||
|
||||
/**
|
||||
* 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)
|
||||
public inline fun <reified T:Any> Sampler<T>.sampleBuffer(generator: RandomGenerator, size: Int): Chain<Buffer<T>> =
|
||||
sampleBuffer(generator, size, BufferFactory())
|
||||
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,7 @@ import space.kscience.kmath.operations.ScaleOperations
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.random.RandomGenerator
|
||||
import space.kscience.kmath.stat.Sampler
|
||||
import space.kscience.kmath.structures.MutableBufferFactory
|
||||
|
||||
/**
|
||||
* 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>>,
|
||||
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 fun add(left: Sampler<T>, right: Sampler<T>): Sampler<T> = BasicSampler { generator ->
|
||||
|
@ -5,10 +5,14 @@
|
||||
|
||||
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.structures.*
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
|
||||
/**
|
||||
* 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 =
|
||||
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