diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cf0d92f4..114d452b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased ### Added +- Fit accessors with Attribute ### Changed - Upgrade tensorflow version to 1.0.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt index 5df519c19..3df21df5a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -14,7 +14,10 @@ import space.kscience.kmath.expressions.autodiff import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.asIterable import space.kscience.kmath.operations.toList -import space.kscience.kmath.optimization.* +import space.kscience.kmath.optimization.minimize +import space.kscience.kmath.optimization.optimizeWith +import space.kscience.kmath.optimization.result +import space.kscience.kmath.optimization.resultValue import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map @@ -79,9 +82,10 @@ suspend fun main() { val result = chi2.optimizeWith( CMOptimizer, mapOf(a to 1.5, b to 0.9, c to 1.0), - ) { - FunctionOptimizationTarget(OptimizationDirection.MINIMIZE) - } + attributesBuilder = { + minimize() + } + ) //display a page with plot and numerical results val page = Plotly.page { diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt index 4f3ce5443..fc9abd9cc 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.fit import kotlinx.html.br import kotlinx.html.h3 -import space.kscience.attributes.Attributes import space.kscience.kmath.data.XYErrorColumnarData import space.kscience.kmath.distributions.NormalDistribution import space.kscience.kmath.expressions.Symbol @@ -65,7 +64,9 @@ suspend fun main() { QowOptimizer, Double.autodiff, mapOf(a to 0.9, b to 1.2, c to 2.0, e to 1.0, d to 1.0, e to 0.0), - attributes = Attributes(OptimizationParameters, listOf(a, b, c, d)) + attributesBuilder = { + freeParameters(a, b, c, d) + }, ) { arg -> //bind variables to autodiff context val a by binding diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt index e881c4c7c..ebd39fc2d 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -22,6 +22,15 @@ public enum class OptimizationDirection { public object FunctionOptimizationTarget : OptimizationAttribute<OptimizationDirection> +public fun AttributesBuilder<FunctionOptimization<*>>.maximize() { + FunctionOptimizationTarget(OptimizationDirection.MAXIMIZE) +} + +public fun AttributesBuilder<FunctionOptimization<*>>.minimize() { + FunctionOptimizationTarget(OptimizationDirection.MINIMIZE) +} + + public class FunctionOptimization<T>( public val expression: DifferentiableExpression<T>, override val attributes: Attributes, @@ -74,11 +83,11 @@ public fun <T> FunctionOptimization<T>.withAttributes( public suspend fun <T> DifferentiableExpression<T>.optimizeWith( optimizer: Optimizer<T, FunctionOptimization<T>>, startingPoint: Map<Symbol, T>, - modifier: AttributesBuilder<FunctionOptimization<T>>.() -> Unit = {}, + attributesBuilder: AttributesBuilder<FunctionOptimization<T>>.() -> Unit = {}, ): FunctionOptimization<T> { val problem = FunctionOptimization(this) { startAt(startingPoint) - modifier() + attributesBuilder() } return optimizer.optimize(problem) } @@ -93,11 +102,11 @@ public val <T> FunctionOptimization<T>.resultValue: T public suspend fun <T> DifferentiableExpression<T>.optimizeWith( optimizer: Optimizer<T, FunctionOptimization<T>>, vararg startingPoint: Pair<Symbol, T>, - builder: AttributesBuilder<FunctionOptimization<T>>.() -> Unit = {}, + attributesBuilder: AttributesBuilder<FunctionOptimization<T>>.() -> Unit = {}, ): FunctionOptimization<T> { val problem = FunctionOptimization<T>(this) { startAt(mapOf(*startingPoint)) - builder() + attributesBuilder() } return optimizer.optimize(problem) } diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index d0567a505..0cfaf95e1 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -58,9 +58,15 @@ public object OptimizationLog : OptimizationAttribute<Loggable> */ public object OptimizationParameters : OptimizationAttribute<List<Symbol>> +public fun AttributesBuilder<OptimizationProblem<*>>.freeParameters(vararg symbols: Symbol) { + OptimizationParameters(symbols.asList()) +} + /** * Maximum allowed number of iterations */ public object OptimizationIterations : OptimizationAttribute<Int> - +public fun AttributesBuilder<OptimizationProblem<*>>.iterations(iterations: Int) { + OptimizationIterations(iterations) +} diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt index d45dcc35a..dbfdf370a 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -137,6 +137,24 @@ public suspend fun XYColumnarData<Double, Double, Double>.fitWith( return optimizer.optimize(problem) } +public suspend fun XYColumnarData<Double, Double, Double>.fitWith( + optimizer: Optimizer<Double, XYFit>, + modelExpression: DifferentiableExpression<Float64>, + startingPoint: Map<Symbol, Double>, + attributesBuilder: AttributesBuilder<XYFit>.() -> Unit, + xSymbol: Symbol = Symbol.x, + pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, + pointWeight: PointWeight = PointWeight.byYSigma, +): XYFit = fitWith( + optimizer = optimizer, + modelExpression = modelExpression, + startingPoint = startingPoint, + attributes = Attributes<XYFit>(attributesBuilder), + xSymbol = xSymbol, + pointToCurveDistance = pointToCurveDistance, + pointWeight = pointWeight +) + /** * Fit given data with a model provided as an expression */ @@ -166,6 +184,26 @@ public suspend fun <I : Any, A> XYColumnarData<Double, Double, Double>.fitWith( ) } +public suspend fun <I : Any, A> XYColumnarData<Double, Double, Double>.fitWith( + optimizer: Optimizer<Double, XYFit>, + processor: AutoDiffProcessor<Double, I, A>, + startingPoint: Map<Symbol, Double>, + attributesBuilder: AttributesBuilder<XYFit>.() -> Unit, + xSymbol: Symbol = Symbol.x, + pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, + pointWeight: PointWeight = PointWeight.byYSigma, + model: A.(I) -> I, +): XYFit where A : ExtendedField<I>, A : ExpressionAlgebra<Double, I> = fitWith( + optimizer = optimizer, + processor = processor, + startingPoint = startingPoint, + attributes = Attributes<XYFit>(attributesBuilder), + xSymbol = xSymbol, + pointToCurveDistance = pointToCurveDistance, + pointWeight = pointWeight, + model = model +) + /** * Compute chi squared value for completed fit. Return null for incomplete fit */