Update integration to use Attributes

This commit is contained in:
Alexander Nozik 2023-08-14 10:06:23 +03:00
parent 5196322b7a
commit 9da14089e0
5 changed files with 62 additions and 44 deletions

View File

@ -13,26 +13,29 @@ import space.kscience.kmath.integration.*
*/ */
public class CMGaussRuleIntegrator( public class CMGaussRuleIntegrator(
private val numpoints: Int, private val numpoints: Int,
private var type: GaussRule = GaussRule.LEGANDRE, private var type: GaussRule = GaussRule.LEGENDRE,
) : UnivariateIntegrator<Double> { ) : UnivariateIntegrator<Double> {
override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> { override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
val range = integrand.getFeature<IntegrationRange>()?.range val range = integrand[IntegrationRange]
?: error("Integration range is not provided") ?: error("Integration range is not provided")
val integrator: GaussIntegrator = getIntegrator(range) val integrator: GaussIntegrator = getIntegrator(range)
//TODO check performance //TODO check performance
val res: Double = integrator.integrate(integrand.function) 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<Double>): GaussIntegrator { private fun getIntegrator(range: ClosedRange<Double>): GaussIntegrator {
return when (type) { return when (type) {
GaussRule.LEGANDRE -> factory.legendre( GaussRule.LEGENDRE -> factory.legendre(
numpoints, numpoints,
range.start, range.start,
range.endInclusive range.endInclusive
) )
GaussRule.LEGANDREHP -> factory.legendreHighPrecision( GaussRule.LEGENDREHP -> factory.legendreHighPrecision(
numpoints, numpoints,
range.start, range.start,
range.endInclusive range.endInclusive
@ -65,7 +68,7 @@ public class CMGaussRuleIntegrator(
} }
public enum class GaussRule { public enum class GaussRule {
UNIFORM, LEGANDRE, LEGANDREHP UNIFORM, LEGENDRE, LEGENDREHP
} }
public companion object { public companion object {
@ -74,10 +77,10 @@ public class CMGaussRuleIntegrator(
public fun integrate( public fun integrate(
range: ClosedRange<Double>, range: ClosedRange<Double>,
numPoints: Int = 100, numPoints: Int = 100,
type: GaussRule = GaussRule.LEGANDRE, type: GaussRule = GaussRule.LEGENDRE,
function: (Double) -> Double, function: (Double) -> Double,
): Double = CMGaussRuleIntegrator(numPoints, type).process( ): Double = CMGaussRuleIntegrator(numPoints, type).process(
UnivariateIntegrand(function, IntegrationRange(range)) UnivariateIntegrand({IntegrationRange(range)},function)
).value ).value
} }
} }

View File

@ -9,13 +9,14 @@ import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussInteg
import org.apache.commons.math3.analysis.integration.SimpsonIntegrator import org.apache.commons.math3.analysis.integration.SimpsonIntegrator
import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.integration.* import space.kscience.kmath.integration.*
import org.apache.commons.math3.analysis.integration.UnivariateIntegrator as CMUnivariateIntegrator
/** /**
* Integration wrapper for Common-maths UnivariateIntegrator * Integration wrapper for Common-maths UnivariateIntegrator
*/ */
public class CMIntegrator( public class CMIntegrator(
private val defaultMaxCalls: Int = 200, private val defaultMaxCalls: Int = 200,
public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator, public val integratorBuilder: (Integrand<Double>) -> CMUnivariateIntegrator,
) : UnivariateIntegrator<Double> { ) : UnivariateIntegrator<Double> {
override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> { override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
@ -25,12 +26,13 @@ public class CMIntegrator(
val range = integrand[IntegrationRange] ?: error("Integration range is not provided") val range = integrand[IntegrationRange] ?: error("Integration range is not provided")
val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive) val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive)
return integrand + return integrand.modify {
IntegrandValue(res) + value(res)
IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) + IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy)
IntegrandRelativeAccuracy(integrator.relativeAccuracy) + IntegrandRelativeAccuracy(integrator.relativeAccuracy)
IntegrandCallsPerformed(integrator.evaluations + integrand.calls) IntegrandCallsPerformed(integrator.evaluations + integrand.calls)
} }
}
public companion object { public companion object {

View File

@ -5,13 +5,17 @@
package space.kscience.kmath.integration package space.kscience.kmath.integration
import space.kscience.attributes.* import space.kscience.attributes.Attribute
import kotlin.reflect.typeOf import space.kscience.attributes.AttributeContainer
import space.kscience.attributes.AttributesBuilder
import space.kscience.attributes.SafeType
public interface IntegrandAttribute<T> : Attribute<T> public interface IntegrandAttribute<T> : Attribute<T>
public interface Integrand<T> : AttributeContainer { public interface Integrand<T> : AttributeContainer {
public val type: SafeType<T>
public fun modify(block: AttributesBuilder.() -> Unit): Integrand<T> public fun modify(block: AttributesBuilder.() -> Unit): Integrand<T>
public fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): Integrand<T> public fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): Integrand<T>
@ -21,19 +25,21 @@ public interface Integrand<T> : AttributeContainer {
public operator fun <T> Integrand<*>.get(attribute: Attribute<T>): T? = attributes[attribute] public operator fun <T> Integrand<*>.get(attribute: Attribute<T>): T? = attributes[attribute]
public class IntegrandValue<T>(type: SafeType<T>) : PolymorphicAttribute<T>(type), IntegrandAttribute<T> public sealed class IntegrandValue<T> private constructor(): IntegrandAttribute<T>{
public companion object: IntegrandValue<Any?>(){
public inline val <reified T : Any> Integrand<T>.Value: IntegrandValue<T> get() = IntegrandValue(safeTypeOf()) @Suppress("UNCHECKED_CAST")
public fun <T> forType(): IntegrandValue<T> = this as IntegrandValue<T>
}
}
public fun <T> AttributesBuilder.value(value: T) { public fun <T> AttributesBuilder.value(value: T) {
val type: SafeType<T> = typeOf<T>() IntegrandValue.forType<T>().invoke(value)
IntegrandValue(type).invoke(value)
} }
/** /**
* Value of the integrand if it is present or null * Value of the integrand if it is present or null
*/ */
public inline val <reified T : Any> Integrand<T>.valueOrNull: T? get() = attributes[Value] public inline val <reified T : Any> Integrand<T>.valueOrNull: T? get() = attributes[IntegrandValue.forType<T>()]
/** /**
* Value of the integrand or error * Value of the integrand or error

View File

@ -8,19 +8,20 @@ package space.kscience.kmath.integration
import space.kscience.attributes.* import space.kscience.attributes.*
import space.kscience.kmath.linear.Point import space.kscience.kmath.linear.Point
public class MultivariateIntegrand<T> internal constructor( public class MultivariateIntegrand<T>(
override val type: SafeType<T>,
override val attributes: Attributes, override val attributes: Attributes,
public val function: (Point<T>) -> T, public val function: (Point<T>) -> T,
) : Integrand<T> { ) : Integrand<T> {
override fun modify(block: AttributesBuilder.() -> Unit): MultivariateIntegrand<T> = override fun modify(block: AttributesBuilder.() -> Unit): MultivariateIntegrand<T> =
MultivariateIntegrand(attributes.modify(block), function) MultivariateIntegrand(type, attributes.modify(block), function)
override fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): MultivariateIntegrand<T> = override fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): MultivariateIntegrand<T> =
MultivariateIntegrand(attributes.withAttribute(attribute, value), function) MultivariateIntegrand(type, attributes.withAttribute(attribute, value), function)
} }
public fun <T : Any> MultivariateIntegrand( public inline fun <reified T : Any> MultivariateIntegrand(
attributeBuilder: AttributesBuilder.() -> Unit, attributeBuilder: AttributesBuilder.() -> Unit,
function: (Point<T>) -> T, noinline function: (Point<T>) -> T,
): MultivariateIntegrand<T> = MultivariateIntegrand(Attributes(attributeBuilder), function) ): MultivariateIntegrand<T> = MultivariateIntegrand(safeTypeOf<T>(), Attributes(attributeBuilder), function)

View File

@ -10,22 +10,23 @@ import space.kscience.kmath.UnstableKMathAPI
import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.Float64Buffer import space.kscience.kmath.structures.Float64Buffer
public class UnivariateIntegrand<T> internal constructor( public class UnivariateIntegrand<T>(
override val type: SafeType<T>,
override val attributes: Attributes, override val attributes: Attributes,
public val function: (Double) -> T, public val function: (Double) -> T,
) : Integrand<T> { ) : Integrand<T> {
override fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): UnivariateIntegrand<T> = override fun <A : Any> withAttribute(attribute: Attribute<A>, value: A): UnivariateIntegrand<T> =
UnivariateIntegrand(attributes.withAttribute(attribute, value), function) UnivariateIntegrand(type, attributes.withAttribute(attribute, value), function)
override fun modify(block: AttributesBuilder.() -> Unit): UnivariateIntegrand<T> = override fun modify(block: AttributesBuilder.() -> Unit): UnivariateIntegrand<T> =
UnivariateIntegrand(attributes.modify(block), function) UnivariateIntegrand(type, attributes.modify(block), function)
} }
public fun <T : Any> UnivariateIntegrand( public inline fun <reified T : Any> UnivariateIntegrand(
attributeBuilder: AttributesBuilder.() -> Unit, attributeBuilder: AttributesBuilder.() -> Unit,
function: (Double) -> T, noinline function: (Double) -> T,
): UnivariateIntegrand<T> = UnivariateIntegrand(Attributes(attributeBuilder), function) ): UnivariateIntegrand<T> = UnivariateIntegrand(safeTypeOf(), Attributes(attributeBuilder), function)
public typealias UnivariateIntegrator<T> = Integrator<UnivariateIntegrand<T>> public typealias UnivariateIntegrator<T> = Integrator<UnivariateIntegrand<T>>
@ -60,9 +61,9 @@ public fun AttributesBuilder.integrationNodes(vararg nodes: Double) {
* The [function] is placed in the end position to allow passing a lambda. * The [function] is placed in the end position to allow passing a lambda.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <T : Any> UnivariateIntegrator<T>.integrate( public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
attributesBuilder: AttributesBuilder.() -> Unit, attributesBuilder: AttributesBuilder.() -> Unit,
function: (Double) -> T, noinline function: (Double) -> T,
): UnivariateIntegrand<T> = process(UnivariateIntegrand(attributesBuilder, function)) ): UnivariateIntegrand<T> = process(UnivariateIntegrand(attributesBuilder, function))
/** /**
@ -70,14 +71,19 @@ public fun <T : Any> UnivariateIntegrator<T>.integrate(
* The [function] is placed in the end position to allow passing a lambda. * The [function] is placed in the end position to allow passing a lambda.
*/ */
@UnstableKMathAPI @UnstableKMathAPI
public fun <T : Any> UnivariateIntegrator<T>.integrate( public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
range: ClosedRange<Double>, range: ClosedRange<Double>,
attributeBuilder: AttributesBuilder.() -> Unit = {}, attributeBuilder: AttributesBuilder.() -> Unit = {},
function: (Double) -> T, noinline function: (Double) -> T,
): UnivariateIntegrand<T> { ): UnivariateIntegrand<T> {
val attributes = Attributes {
return process(
UnivariateIntegrand(
attributeBuilder = {
IntegrationRange(range) IntegrationRange(range)
attributeBuilder() attributeBuilder()
} },
return process(UnivariateIntegrand(attributes, function)) function = function
)
)
} }