forked from kscience/kmath
[WIP] Features to Attributes refactoring
This commit is contained in:
parent
6da51b7794
commit
4abe25c188
@ -8,6 +8,7 @@
|
||||
|
||||
### Changed
|
||||
- Features replaced with Attributes.
|
||||
- Transposed refactored.
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
package space.kscience.attributes
|
||||
|
||||
import kotlin.jvm.JvmInline
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
@ -14,7 +15,8 @@ import kotlin.reflect.typeOf
|
||||
*
|
||||
* @param kType raw [KType]
|
||||
*/
|
||||
public class SafeType<T> @PublishedApi internal constructor(public val kType: KType)
|
||||
@JvmInline
|
||||
public value class SafeType<T> @PublishedApi internal constructor(public val kType: KType)
|
||||
|
||||
public inline fun <reified T> safeTypeOf(): SafeType<T> = SafeType(typeOf<T>())
|
||||
|
||||
|
@ -15,7 +15,7 @@ private fun DMatrixContext<Double, *>.simple() {
|
||||
val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
|
||||
|
||||
//Dimension-safe addition
|
||||
m1.transpose() + m2
|
||||
m1.transposed() + m2
|
||||
}
|
||||
|
||||
private object D5 : Dimension {
|
||||
|
@ -125,7 +125,7 @@ public object CMOptimizer : Optimizer<Double, FunctionOptimization<Double>> {
|
||||
|
||||
val logger = problem.getFeature<OptimizationLog>()
|
||||
|
||||
for (feature in problem.features) {
|
||||
for (feature in problem.attributes) {
|
||||
when (feature) {
|
||||
is CMOptimizerData -> feature.data.forEach { dataBuilder ->
|
||||
addOptimizationData(dataBuilder())
|
||||
|
@ -174,9 +174,8 @@ public interface LinearSpace<T, out A : Ring<T>> : MatrixOperations<T> {
|
||||
/**
|
||||
* Get an attribute value for the structure in this scope. Structure features take precedence other context features.
|
||||
*
|
||||
* @param A the type of feature.
|
||||
* @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.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
|
@ -21,12 +21,11 @@ import space.kscience.kmath.structures.*
|
||||
* @param T the type of matrices' items.
|
||||
* @param l The lower triangular matrix in this decomposition. It may have [LowerTriangular].
|
||||
* @param u The upper triangular matrix in this decomposition. It may have [UpperTriangular].
|
||||
* @param p he permutation matrix in this decomposition. May have [Determinant] attribute
|
||||
*/
|
||||
public data class LupDecomposition<T>(
|
||||
public val l: Matrix<T>,
|
||||
public val u: Matrix<T>,
|
||||
public val p: Matrix<T>,
|
||||
public val pivot: IntBuffer,
|
||||
)
|
||||
|
||||
|
||||
@ -180,12 +179,12 @@ public fun <T : Comparable<T>> LinearSpace<T, Field<T>>.lup(
|
||||
val u = VirtualMatrix(rowNum, colNum) { i, j ->
|
||||
if (j >= i) lu[i, j] else zero
|
||||
}.withAttribute(UpperTriangular)
|
||||
//
|
||||
// val p = VirtualMatrix(rowNum, colNum) { i, j ->
|
||||
// if (j == pivot[i]) one else zero
|
||||
// }.withAttribute(Determinant, if (even) one else -one)
|
||||
|
||||
val p = VirtualMatrix(rowNum, colNum) { i, j ->
|
||||
if (j == pivot[i]) one else zero
|
||||
}.withAttribute(Determinant, if (even) one else -one)
|
||||
|
||||
return LupDecomposition(l, u, p)
|
||||
return LupDecomposition(l, u, pivot.asBuffer())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,7 +208,7 @@ internal fun <T : Any, A : Field<T>> LinearSpace<T, A>.solve(
|
||||
|
||||
for (row in 0 until rowNum) {
|
||||
val bpRow = bp.row(row)
|
||||
val pRow = pivot[row]
|
||||
val pRow = lup.pivot[row]
|
||||
for (col in 0 until matrix.colNum) bpRow[col] = matrix[pRow, col]
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,6 @@ package space.kscience.kmath.linear
|
||||
import space.kscience.attributes.*
|
||||
import space.kscience.kmath.UnstableKMathAPI
|
||||
import space.kscience.kmath.nd.StructureAttribute
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* A marker interface representing some properties of matrices or additional transformations of them. Features are used
|
||||
@ -53,11 +51,9 @@ public val <T> MatrixOperations<T>.Inverted: Inverted<T> get() = Inverted(safeTy
|
||||
*
|
||||
* @param T the type of matrices' items.
|
||||
*/
|
||||
public class Determinant<T>(type: SafeType<T>) :
|
||||
PolymorphicAttribute<T>(type),
|
||||
MatrixAttribute<T>
|
||||
public class Determinant<T> : MatrixAttribute<T>
|
||||
|
||||
public inline val <reified T> MatrixOperations<T>.Determinant: Determinant<T> get() = Determinant(safeTypeOf())
|
||||
public val <T> MatrixOperations<T>.Determinant: Determinant<T> get() = Determinant()
|
||||
|
||||
/**
|
||||
* Matrices with this feature are lower triangular ones.
|
||||
@ -174,4 +170,5 @@ public class SingularValueDecompositionAttribute<T>(type: SafeType<SingularValue
|
||||
public val <T> MatrixOperations<T>.SVD: SingularValueDecompositionAttribute<T>
|
||||
get() = SingularValueDecompositionAttribute(safeTypeOf())
|
||||
|
||||
|
||||
//TODO add sparse matrix feature
|
||||
|
@ -82,13 +82,3 @@ public fun <T : Any> LinearSpace<T, Ring<T>>.zero(
|
||||
): MatrixWrapper<T> = VirtualMatrix(rows, columns) { _, _ ->
|
||||
elementAlgebra.zero
|
||||
}.withAttribute(IsZero)
|
||||
|
||||
public class TransposedAttribute<out T : Any>(public val original: Matrix<T>) : MatrixAttribute
|
||||
|
||||
/**
|
||||
* Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@OptIn(UnstableKMathAPI::class)
|
||||
public fun <T : Any> Matrix<T>.transpose(): Matrix<T> = getFeature(TransposedAttribute::class)?.original as? Matrix<T>
|
||||
?: VirtualMatrix(colNum, rowNum) { i, j -> get(j, i) }.withAttribute(TransposedAttribute(this))
|
||||
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package space.kscience.kmath.linear
|
||||
|
||||
import space.kscience.attributes.Attributes
|
||||
|
||||
|
||||
public class TransposedMatrix<T>(public val origin: Matrix<T>) : Matrix<T> {
|
||||
override val rowNum: Int get() = origin.colNum
|
||||
override val colNum: Int get() = origin.rowNum
|
||||
|
||||
override fun get(i: Int, j: Int): T = origin[j, i]
|
||||
|
||||
override val attributes: Attributes get() = Attributes.EMPTY
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A`
|
||||
*/
|
||||
public val <T> Matrix<T>.transposed: Matrix<T>
|
||||
get() = (this as? TransposedMatrix<T>)?.origin ?: TransposedMatrix(this)
|
@ -29,5 +29,4 @@ public class VirtualMatrix<out T : Any>(
|
||||
public fun <T : Any> MatrixBuilder<T, *>.virtual(
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
generator: (i: Int, j: Int) -> T,
|
||||
): VirtualMatrix<T> =
|
||||
VirtualMatrix(rows, columns, attributes, generator)
|
||||
): VirtualMatrix<T> = VirtualMatrix(rows, columns, attributes, generator)
|
||||
|
@ -71,31 +71,19 @@ public interface AlgebraND<T, out C : Algebra<T>> : Algebra<StructureND<T>> {
|
||||
structure.map { value -> this@invoke(value) }
|
||||
|
||||
/**
|
||||
* Get a feature of the structure in this scope. Structure features take precedence other context features.
|
||||
* Get an attribute value for the structure in this scope. Structure features take precedence other context features.
|
||||
*
|
||||
* @param F the type of feature.
|
||||
* @param structure the structure.
|
||||
* @param type the [KClass] instance of [F].
|
||||
* @param attribute to be computed.
|
||||
* @return a feature object or `null` if it isn't present.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public fun <F : StructureAttribute> getFeature(structure: StructureND<T>, type: KClass<out F>): F? =
|
||||
structure.getFeature(type)
|
||||
public fun <T, A : StructureAttribute<T>> attributeFor(structure: StructureND<*>, attribute: A): T? =
|
||||
structure.attributes[attribute]
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a feature of the structure in this scope. Structure features take precedence other context features.
|
||||
*
|
||||
* @param T the type of items in the matrices.
|
||||
* @param F the type of feature.
|
||||
* @return a feature object or `null` if it isn't present.
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public inline fun <T : Any, reified F : StructureAttribute> AlgebraND<T, *>.getFeature(structure: StructureND<T>): F? =
|
||||
getFeature(structure, F::class)
|
||||
|
||||
/**
|
||||
* Space of [StructureND].
|
||||
*
|
||||
|
@ -36,8 +36,8 @@ public open class BufferND<out T>(
|
||||
*/
|
||||
public inline fun <reified T> BufferND(
|
||||
shape: ShapeND,
|
||||
bufferFactory: BufferFactory<T> = BufferFactory.auto(),
|
||||
initializer: (IntArray) -> T,
|
||||
bufferFactory: BufferFactory<T> = BufferFactory.auto<T>(),
|
||||
crossinline initializer: (IntArray) -> T,
|
||||
): BufferND<T> {
|
||||
val strides = Strides(shape)
|
||||
return BufferND(strides, bufferFactory(strides.linearSize) { initializer(strides.index(it)) })
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
package space.kscience.kmath.nd
|
||||
|
||||
import space.kscience.attributes.Attributes
|
||||
import space.kscience.kmath.PerformancePitfall
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.MutableBuffer
|
||||
@ -110,7 +111,8 @@ private value class Structure2DWrapper<out T>(val structure: StructureND<T>) : S
|
||||
@PerformancePitfall
|
||||
override operator fun get(i: Int, j: Int): T = structure[i, j]
|
||||
|
||||
override fun <F : StructureAttribute> getFeature(type: KClass<out F>): F? = structure.getFeature(type)
|
||||
override val attributes: Attributes
|
||||
get() = structure.attributes
|
||||
|
||||
@PerformancePitfall
|
||||
override fun elements(): Sequence<Pair<IntArray, T>> = structure.elements()
|
||||
|
@ -7,13 +7,13 @@ package space.kscience.kmath.nd
|
||||
|
||||
import space.kscience.attributes.Attribute
|
||||
import space.kscience.attributes.AttributeContainer
|
||||
import space.kscience.attributes.Attributes
|
||||
import space.kscience.attributes.SafeType
|
||||
import space.kscience.kmath.PerformancePitfall
|
||||
import space.kscience.kmath.linear.LinearSpace
|
||||
import space.kscience.kmath.operations.Ring
|
||||
import space.kscience.kmath.operations.invoke
|
||||
import space.kscience.kmath.structures.Buffer
|
||||
import space.kscience.kmath.structures.BufferFactory
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.math.abs
|
||||
|
||||
@ -57,6 +57,8 @@ public interface StructureND<out T> : AttributeContainer, WithShape {
|
||||
@PerformancePitfall
|
||||
public fun elements(): Sequence<Pair<IntArray, T>> = indices.asSequence().map { it to get(it) }
|
||||
|
||||
override val attributes: Attributes get() = Attributes.EMPTY
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
* Indicates whether some [StructureND] is equal to another one.
|
||||
|
@ -20,8 +20,6 @@ public interface WithSize {
|
||||
public interface BufferAlgebra<T, out A : Algebra<T>> : Algebra<Buffer<T>> {
|
||||
public val elementAlgebra: A
|
||||
|
||||
public val elementType: KType
|
||||
|
||||
public val elementBufferFactory: MutableBufferFactory<T> get() = elementAlgebra.bufferFactory
|
||||
|
||||
public fun buffer(size: Int, vararg elements: T): Buffer<T> {
|
||||
|
@ -21,7 +21,7 @@ public fun interface BufferFactory<T> {
|
||||
public operator fun invoke(size: Int, builder: (Int) -> T): Buffer<T>
|
||||
|
||||
public companion object{
|
||||
public inline fun <reified T : Any> auto(): BufferFactory<T> =
|
||||
public inline fun <reified T> auto(): BufferFactory<T> =
|
||||
BufferFactory(Buffer.Companion::auto)
|
||||
|
||||
public fun <T> boxing(): BufferFactory<T> =
|
||||
|
@ -146,8 +146,8 @@ public value class DMatrixContext<T : Any, out A : Ring<T>>(public val context:
|
||||
public inline operator fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.unaryMinus(): DMatrix<T, C, R> =
|
||||
context.run { this@unaryMinus.unaryMinus() }.coerce()
|
||||
|
||||
public inline fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.transpose(): DMatrix<T, R, C> =
|
||||
context.run { (this@transpose as Matrix<T>).transpose() }.coerce()
|
||||
public inline fun <reified R : Dimension, reified C : Dimension> DMatrix<T, C, R>.transposed(): DMatrix<T, R, C> =
|
||||
context.run { (this@transposed as Matrix<T>).transposed }.coerce()
|
||||
|
||||
public companion object {
|
||||
public val real: DMatrixContext<Double, DoubleField> = DMatrixContext(Double.algebra.linearSpace)
|
||||
|
@ -30,7 +30,7 @@ internal class DMatrixContextTest {
|
||||
val m2 = produce<D3, D2> { i, j -> (i + j).toDouble() }
|
||||
|
||||
//Dimension-safe addition
|
||||
m1.transpose() + m2
|
||||
m1.transposed() + m2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ kscience{
|
||||
|
||||
wasm()
|
||||
|
||||
|
||||
|
||||
dependencies {
|
||||
api(projects.kmathCore)
|
||||
}
|
||||
|
@ -68,9 +68,6 @@ public open class PolynomialSpace<C, A>(
|
||||
public val ring: A,
|
||||
) : Ring<Polynomial<C>>, ScaleOperations<Polynomial<C>> where A : Ring<C>, A : ScaleOperations<C> {
|
||||
|
||||
@UnstableKMathAPI
|
||||
override val elementType: KType get() = typeOf<Polynomial<C>>()
|
||||
|
||||
/**
|
||||
* Instance of zero constant (zero of the underlying ring).
|
||||
*/
|
||||
|
@ -5,21 +5,21 @@
|
||||
|
||||
package space.kscience.kmath.optimization
|
||||
|
||||
import space.kscience.attributes.*
|
||||
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.FeatureSet
|
||||
|
||||
public class OptimizationValue<T>(public val value: T) : OptimizationFeature {
|
||||
override fun toString(): String = "Value($value)"
|
||||
}
|
||||
|
||||
public enum class FunctionOptimizationTarget : OptimizationFeature {
|
||||
public enum class FunctionOptimizationTarget {
|
||||
MAXIMIZE,
|
||||
MINIMIZE
|
||||
}
|
||||
|
||||
public class FunctionOptimization<T>(
|
||||
override val features: FeatureSet<OptimizationFeature>,
|
||||
override val attributes: Attributes,
|
||||
public val expression: DifferentiableExpression<T>,
|
||||
) : OptimizationProblem<T> {
|
||||
|
||||
@ -30,25 +30,36 @@ public class FunctionOptimization<T>(
|
||||
|
||||
other as FunctionOptimization<*>
|
||||
|
||||
if (features != other.features) return false
|
||||
if (attributes != other.attributes) return false
|
||||
if (expression != other.expression) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = features.hashCode()
|
||||
var result = attributes.hashCode()
|
||||
result = 31 * result + expression.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String = "FunctionOptimization(features=$features)"
|
||||
override fun toString(): String = "FunctionOptimization(features=$attributes)"
|
||||
|
||||
public companion object
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class OptimizationPrior<T>(type: SafeType<T>):
|
||||
PolymorphicAttribute<DifferentiableExpression<T>>(safeTypeOf()),
|
||||
Attribute<DifferentiableExpression<T>>
|
||||
|
||||
public val <T> FunctionOptimization.Companion.Optimization get() =
|
||||
|
||||
|
||||
public fun <T> FunctionOptimization<T>.withFeatures(
|
||||
vararg newFeature: OptimizationFeature,
|
||||
): FunctionOptimization<T> = FunctionOptimization(
|
||||
features.with(*newFeature),
|
||||
attributes.with(*newFeature),
|
||||
expression,
|
||||
)
|
||||
|
||||
|
@ -5,21 +5,16 @@
|
||||
|
||||
package space.kscience.kmath.optimization
|
||||
|
||||
import space.kscience.attributes.*
|
||||
import space.kscience.kmath.expressions.DifferentiableExpression
|
||||
import space.kscience.kmath.expressions.NamedMatrix
|
||||
import space.kscience.kmath.expressions.Symbol
|
||||
import space.kscience.kmath.misc.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public interface OptimizationFeature : Feature<OptimizationFeature> {
|
||||
// enforce toString override
|
||||
override fun toString(): String
|
||||
}
|
||||
public interface OptimizationAttribute<T>: Attribute<T>
|
||||
|
||||
public interface OptimizationProblem<T> : Featured<OptimizationFeature> {
|
||||
public val features: FeatureSet<OptimizationFeature>
|
||||
override fun <F : OptimizationFeature> getFeature(type: KClass<out F>): F? = features.getFeature(type)
|
||||
}
|
||||
public interface OptimizationProblem<T> : AttributeContainer
|
||||
|
||||
public inline fun <reified F : OptimizationFeature> OptimizationProblem<*>.getFeature(): F? = getFeature(F::class)
|
||||
|
||||
@ -27,11 +22,6 @@ public open class OptimizationStartPoint<T>(public val point: Map<Symbol, T>) :
|
||||
override fun toString(): String = "StartPoint($point)"
|
||||
}
|
||||
|
||||
|
||||
public interface OptimizationPrior<T> : OptimizationFeature, DifferentiableExpression<T> {
|
||||
override val key: FeatureKey<OptimizationFeature> get() = OptimizationPrior::class
|
||||
}
|
||||
|
||||
/**
|
||||
* Covariance matrix for
|
||||
*/
|
||||
|
@ -79,7 +79,7 @@ public interface PointWeight : OptimizationFeature {
|
||||
public class XYFit(
|
||||
public val data: XYColumnarData<Double, Double, Double>,
|
||||
public val model: DifferentiableExpression<Double>,
|
||||
override val features: FeatureSet<OptimizationFeature>,
|
||||
override val attributes: FeatureSet<OptimizationFeature>,
|
||||
internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY,
|
||||
internal val pointWeight: PointWeight = PointWeight.byYSigma,
|
||||
public val xSymbol: Symbol = Symbol.x,
|
||||
@ -90,7 +90,7 @@ public class XYFit(
|
||||
}
|
||||
|
||||
public fun XYFit.withFeature(vararg features: OptimizationFeature): XYFit {
|
||||
return XYFit(data, model, this.features.with(*features), pointToCurveDistance, pointWeight)
|
||||
return XYFit(data, model, this.attributes.with(*features), pointToCurveDistance, pointWeight)
|
||||
}
|
||||
|
||||
public suspend fun XYColumnarData<Double, Double, Double>.fitWith(
|
||||
|
@ -53,9 +53,9 @@ internal fun XYFit.logLikelihood(): DifferentiableExpression<Double> = object :
|
||||
*/
|
||||
@UnstableKMathAPI
|
||||
public suspend fun Optimizer<Double, FunctionOptimization<Double>>.maximumLogLikelihood(problem: XYFit): XYFit {
|
||||
val functionOptimization = FunctionOptimization(problem.features, problem.logLikelihood())
|
||||
val functionOptimization = FunctionOptimization(problem.attributes, problem.logLikelihood())
|
||||
val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE))
|
||||
return XYFit(problem.data, problem.model, result.features)
|
||||
return XYFit(problem.data, problem.model, result.attributes)
|
||||
}
|
||||
|
||||
@UnstableKMathAPI
|
||||
|
Loading…
Reference in New Issue
Block a user