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(
private val numpoints: Int,
private var type: GaussRule = GaussRule.LEGANDRE,
private var type: GaussRule = GaussRule.LEGENDRE,
) : UnivariateIntegrator<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")
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<Double>): 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<Double>,
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
}
}

View File

@ -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<Double>) -> CMUnivariateIntegrator,
) : UnivariateIntegrator<Double> {
override fun process(integrand: UnivariateIntegrand<Double>): UnivariateIntegrand<Double> {
@ -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)
}
}

View File

@ -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<T> : Attribute<T>
public interface Integrand<T> : AttributeContainer {
public val type: SafeType<T>
public fun modify(block: AttributesBuilder.() -> Unit): 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 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?>(){
@Suppress("UNCHECKED_CAST")
public fun <T> forType(): IntegrandValue<T> = this as IntegrandValue<T>
}
}
public inline val <reified T : Any> Integrand<T>.Value: IntegrandValue<T> get() = IntegrandValue(safeTypeOf())
public fun <T> AttributesBuilder.value(value: T){
val type: SafeType<T> = typeOf<T>()
IntegrandValue(type).invoke(value)
public fun <T> AttributesBuilder.value(value: T) {
IntegrandValue.forType<T>().invoke(value)
}
/**
* 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

View File

@ -8,19 +8,20 @@ package space.kscience.kmath.integration
import space.kscience.attributes.*
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,
public val function: (Point<T>) -> T,
) : Integrand<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> =
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,
function: (Point<T>) -> T,
): MultivariateIntegrand<T> = MultivariateIntegrand(Attributes(attributeBuilder), function)
noinline function: (Point<T>) -> T,
): 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.Float64Buffer
public class UnivariateIntegrand<T> internal constructor(
public class UnivariateIntegrand<T>(
override val type: SafeType<T>,
override val attributes: Attributes,
public val function: (Double) -> T,
) : Integrand<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> =
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,
function: (Double) -> T,
): UnivariateIntegrand<T> = UnivariateIntegrand(Attributes(attributeBuilder), function)
noinline function: (Double) -> T,
): UnivariateIntegrand<T> = UnivariateIntegrand(safeTypeOf(), Attributes(attributeBuilder), function)
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.
*/
@UnstableKMathAPI
public fun <T : Any> UnivariateIntegrator<T>.integrate(
public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
attributesBuilder: AttributesBuilder.() -> Unit,
function: (Double) -> T,
noinline function: (Double) -> T,
): 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.
*/
@UnstableKMathAPI
public fun <T : Any> UnivariateIntegrator<T>.integrate(
public inline fun <reified T : Any> UnivariateIntegrator<T>.integrate(
range: ClosedRange<Double>,
attributeBuilder: AttributesBuilder.() -> Unit = {},
function: (Double) -> T,
noinline function: (Double) -> T,
): UnivariateIntegrand<T> {
val attributes = Attributes {
IntegrationRange(range)
attributeBuilder()
}
return process(UnivariateIntegrand(attributes, function))
return process(
UnivariateIntegrand(
attributeBuilder = {
IntegrationRange(range)
attributeBuilder()
},
function = function
)
)
}