From 9da14089e03939d940000df5a9628101be5dc01a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 14 Aug 2023 10:06:23 +0300 Subject: [PATCH] Update integration to use Attributes --- .../integration/CMGaussRuleIntegrator.kt | 19 +++++----- .../kmath/commons/integration/CMIntegrator.kt | 14 ++++---- .../kscience/kmath/integration/Integrand.kt | 24 ++++++++----- .../integration/MultivariateIntegrand.kt | 13 +++---- .../kmath/integration/UnivariateIntegrand.kt | 36 +++++++++++-------- 5 files changed, 62 insertions(+), 44 deletions(-) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt index 263463d37..7befc60a3 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt @@ -13,26 +13,29 @@ import space.kscience.kmath.integration.* */ public class CMGaussRuleIntegrator( private val numpoints: Int, - private var type: GaussRule = GaussRule.LEGANDRE, + private var type: GaussRule = GaussRule.LEGENDRE, ) : UnivariateIntegrator { override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range + val range = integrand[IntegrationRange] ?: error("Integration range is not provided") val integrator: GaussIntegrator = getIntegrator(range) //TODO check performance val res: Double = integrator.integrate(integrand.function) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numpoints) + return integrand.modify { + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numpoints) + } } private fun getIntegrator(range: ClosedRange): GaussIntegrator { return when (type) { - GaussRule.LEGANDRE -> factory.legendre( + GaussRule.LEGENDRE -> factory.legendre( numpoints, range.start, range.endInclusive ) - GaussRule.LEGANDREHP -> factory.legendreHighPrecision( + GaussRule.LEGENDREHP -> factory.legendreHighPrecision( numpoints, range.start, range.endInclusive @@ -65,7 +68,7 @@ public class CMGaussRuleIntegrator( } public enum class GaussRule { - UNIFORM, LEGANDRE, LEGANDREHP + UNIFORM, LEGENDRE, LEGENDREHP } public companion object { @@ -74,10 +77,10 @@ public class CMGaussRuleIntegrator( public fun integrate( range: ClosedRange, numPoints: Int = 100, - type: GaussRule = GaussRule.LEGANDRE, + type: GaussRule = GaussRule.LEGENDRE, function: (Double) -> Double, ): Double = CMGaussRuleIntegrator(numPoints, type).process( - UnivariateIntegrand(function, IntegrationRange(range)) + UnivariateIntegrand({IntegrationRange(range)},function) ).value } } \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt index 82a371100..7a807c25f 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt @@ -9,13 +9,14 @@ import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussInteg import org.apache.commons.math3.analysis.integration.SimpsonIntegrator import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.integration.* +import org.apache.commons.math3.analysis.integration.UnivariateIntegrator as CMUnivariateIntegrator /** * Integration wrapper for Common-maths UnivariateIntegrator */ public class CMIntegrator( private val defaultMaxCalls: Int = 200, - public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator, + public val integratorBuilder: (Integrand) -> CMUnivariateIntegrator, ) : UnivariateIntegrator { override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { @@ -25,11 +26,12 @@ public class CMIntegrator( val range = integrand[IntegrationRange] ?: error("Integration range is not provided") val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive) - return integrand + - IntegrandValue(res) + - IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) + - IntegrandRelativeAccuracy(integrator.relativeAccuracy) + - IntegrandCallsPerformed(integrator.evaluations + integrand.calls) + return integrand.modify { + value(res) + IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) + IntegrandRelativeAccuracy(integrator.relativeAccuracy) + IntegrandCallsPerformed(integrator.evaluations + integrand.calls) + } } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index 09c32aeff..9e2b8d0d7 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -5,13 +5,17 @@ package space.kscience.kmath.integration -import space.kscience.attributes.* -import kotlin.reflect.typeOf +import space.kscience.attributes.Attribute +import space.kscience.attributes.AttributeContainer +import space.kscience.attributes.AttributesBuilder +import space.kscience.attributes.SafeType public interface IntegrandAttribute : Attribute public interface Integrand : AttributeContainer { + public val type: SafeType + public fun modify(block: AttributesBuilder.() -> Unit): Integrand public fun withAttribute(attribute: Attribute, value: A): Integrand @@ -21,19 +25,21 @@ public interface Integrand : AttributeContainer { public operator fun Integrand<*>.get(attribute: Attribute): T? = attributes[attribute] -public class IntegrandValue(type: SafeType) : PolymorphicAttribute(type), IntegrandAttribute +public sealed class IntegrandValue private constructor(): IntegrandAttribute{ + public companion object: IntegrandValue(){ + @Suppress("UNCHECKED_CAST") + public fun forType(): IntegrandValue = this as IntegrandValue + } +} -public inline val Integrand.Value: IntegrandValue get() = IntegrandValue(safeTypeOf()) - -public fun AttributesBuilder.value(value: T){ - val type: SafeType = typeOf() - IntegrandValue(type).invoke(value) +public fun AttributesBuilder.value(value: T) { + IntegrandValue.forType().invoke(value) } /** * Value of the integrand if it is present or null */ -public inline val Integrand.valueOrNull: T? get() = attributes[Value] +public inline val Integrand.valueOrNull: T? get() = attributes[IntegrandValue.forType()] /** * Value of the integrand or error diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index a3b2ed44f..f8937efd2 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -8,19 +8,20 @@ package space.kscience.kmath.integration import space.kscience.attributes.* import space.kscience.kmath.linear.Point -public class MultivariateIntegrand internal constructor( +public class MultivariateIntegrand( + override val type: SafeType, override val attributes: Attributes, public val function: (Point) -> T, ) : Integrand { override fun modify(block: AttributesBuilder.() -> Unit): MultivariateIntegrand = - MultivariateIntegrand(attributes.modify(block), function) + MultivariateIntegrand(type, attributes.modify(block), function) override fun withAttribute(attribute: Attribute, value: A): MultivariateIntegrand = - MultivariateIntegrand(attributes.withAttribute(attribute, value), function) + MultivariateIntegrand(type, attributes.withAttribute(attribute, value), function) } -public fun MultivariateIntegrand( +public inline fun MultivariateIntegrand( attributeBuilder: AttributesBuilder.() -> Unit, - function: (Point) -> T, -): MultivariateIntegrand = MultivariateIntegrand(Attributes(attributeBuilder), function) + noinline function: (Point) -> T, +): MultivariateIntegrand = MultivariateIntegrand(safeTypeOf(), Attributes(attributeBuilder), function) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt index 3c30f303e..a5291152a 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt @@ -10,22 +10,23 @@ import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Float64Buffer -public class UnivariateIntegrand internal constructor( +public class UnivariateIntegrand( + override val type: SafeType, override val attributes: Attributes, public val function: (Double) -> T, ) : Integrand { override fun withAttribute(attribute: Attribute, value: A): UnivariateIntegrand = - UnivariateIntegrand(attributes.withAttribute(attribute, value), function) + UnivariateIntegrand(type, attributes.withAttribute(attribute, value), function) override fun modify(block: AttributesBuilder.() -> Unit): UnivariateIntegrand = - UnivariateIntegrand(attributes.modify(block), function) + UnivariateIntegrand(type, attributes.modify(block), function) } -public fun UnivariateIntegrand( +public inline fun UnivariateIntegrand( attributeBuilder: AttributesBuilder.() -> Unit, - function: (Double) -> T, -): UnivariateIntegrand = UnivariateIntegrand(Attributes(attributeBuilder), function) + noinline function: (Double) -> T, +): UnivariateIntegrand = UnivariateIntegrand(safeTypeOf(), Attributes(attributeBuilder), function) public typealias UnivariateIntegrator = Integrator> @@ -60,9 +61,9 @@ public fun AttributesBuilder.integrationNodes(vararg nodes: Double) { * The [function] is placed in the end position to allow passing a lambda. */ @UnstableKMathAPI -public fun UnivariateIntegrator.integrate( +public inline fun UnivariateIntegrator.integrate( attributesBuilder: AttributesBuilder.() -> Unit, - function: (Double) -> T, + noinline function: (Double) -> T, ): UnivariateIntegrand = process(UnivariateIntegrand(attributesBuilder, function)) /** @@ -70,14 +71,19 @@ public fun UnivariateIntegrator.integrate( * The [function] is placed in the end position to allow passing a lambda. */ @UnstableKMathAPI -public fun UnivariateIntegrator.integrate( +public inline fun UnivariateIntegrator.integrate( range: ClosedRange, attributeBuilder: AttributesBuilder.() -> Unit = {}, - function: (Double) -> T, + noinline function: (Double) -> T, ): UnivariateIntegrand { - val attributes = Attributes { - IntegrationRange(range) - attributeBuilder() - } - return process(UnivariateIntegrand(attributes, function)) + + return process( + UnivariateIntegrand( + attributeBuilder = { + IntegrationRange(range) + attributeBuilder() + }, + function = function + ) + ) }