quad_rs/integrable.rs
1//! Integrand abstractions.
2//!
3//! This module defines the traits required for a function to be integrated by
4//! the numerical integration routines provided by this crate.
5//!
6//! An [`Integrable`] object maps an input value from the integration domain to
7//! an output value. The input domain may be real or complex, allowing both
8//! ordinary quadrature and contour integration to be expressed using the same
9//! interface.
10//!
11//! The output may be a scalar, vector, matrix, or other structure implementing
12//! [`IntegrationOutput`].
13//!
14//! # Real integration
15//!
16//! ```text
17//! f : ℝ → ℝ
18//! f : ℝ → ℂ
19//! f : ℝ → Vector
20//! ```
21//!
22//! # Contour integration
23//!
24//! ```text
25//! f : ℂ → ℂ
26//! f : ℂ → Vector
27//! ```
28//!
29//! The integrator operates entirely in terms of these abstractions and does not
30//! require any knowledge of the concrete output type beyond the operations
31//! provided by [`IntegrationOutput`].
32
33use nalgebra::ComplexField;
34use num_complex::Complex;
35use num_traits::{Float, FromPrimitive};
36use std::ops::Deref;
37use std::ops::{AddAssign, SubAssign};
38use trellis_runner::TrellisFloat;
39
40/// Function-like object that can be numerically integrated.
41///
42/// An `Integrable` defines:
43///
44/// - the scalar type used internally by the integrator (`Float`),
45/// - the input domain (`Input`),
46/// - the output type (`Output`),
47///
48/// together with a method for evaluating the integrand.
49///
50/// # Associated types
51///
52/// - [`Float`](Self::Float): underlying floating-point type.
53/// - [`Input`](Self::Input): integration domain. This may be real or complex.
54/// - [`Output`](Self::Output): value returned by the integrand.
55///
56/// # Examples
57///
58/// A real-valued function:
59///
60/// ```text
61/// f : ℝ → ℝ
62/// ```
63///
64/// A contour integrand:
65///
66/// ```text
67/// f : ℂ → ℂ
68/// ```
69///
70/// A vector-valued integrand:
71///
72/// ```text
73/// f : ℝ → ℝⁿ
74/// ```
75pub trait Integrable {
76 /// Underlying floating-point type used by the integrator.
77 type Float: IntegrableFloat;
78
79 /// Input domain of the integrand.
80 ///
81 /// This may be a real scalar such as `f64` or a complex scalar used for
82 /// contour integration.
83 type Input: ComplexField<RealField = Self::Float> + Copy;
84
85 /// Output of the integrand.
86 ///
87 /// This may be a scalar, complex scalar, vector, matrix, or other type
88 /// implementing [`IntegrationOutput`].
89 type Output: Clone; //: IntegrationOutput<Self::Input, Float = Self::Float>;
90
91 /// Evaluates the integrand at `input`.
92 ///
93 /// This method performs no validation and may return non-finite values.
94 /// Integrators should generally call
95 /// [`checked_integrand`](Self::checked_integrand) instead unless they
96 /// explicitly wish to handle invalid values themselves.
97 fn integrand(&self, input: &Self::Input) -> Self::Output;
98}
99
100/// Function-like object that can be numerically integrated.
101///
102/// An `Integrable` defines:
103///
104/// - the scalar type used internally by the integrator (`Float`),
105/// - the input domain (`Input`),
106/// - the output type (`Output`),
107///
108/// together with a method for evaluating the integrand.
109///
110/// # Associated types
111///
112/// - [`Float`](Self::Float): underlying floating-point type.
113/// - [`Input`](Self::Input): integration domain. This may be real or complex.
114/// - [`Output`](Self::Output): value returned by the integrand.
115/// - [`Error`](Self::Error): error returned by the integrand.
116///
117/// # Examples
118///
119/// A real-valued function:
120///
121/// ```text
122/// f : ℝ → ℝ
123/// ```
124///
125/// A contour integrand:
126///
127/// ```text
128/// f : ℂ → ℂ
129/// ```
130///
131/// A vector-valued integrand:
132///
133/// ```text
134/// f : ℝ → ℝⁿ
135/// ```
136pub trait FallibleIntegrable {
137 /// Underlying floating-point type used by the integrator.
138 type Float: IntegrableFloat;
139
140 /// Input domain of the integrand.
141 ///
142 /// This may be a real scalar such as `f64` or a complex scalar used for
143 /// contour integration.
144 type Input: ComplexField<RealField = Self::Float> + Copy;
145
146 /// Output of the integrand.
147 ///
148 /// This may be a scalar, complex scalar, vector, matrix, or other type
149 /// implementing [`IntegrationOutput`].
150 type Output: Clone; //: IntegrationOutput<Self::Input, Float = Self::Float>;
151
152 type Error: Send + Sync + std::fmt::Debug + 'static;
153
154 /// Evaluates the integrand at `input`.
155 ///
156 /// This method performs no validation and may return non-finite values.
157 /// Integrators should generally call
158 /// [`checked_integrand`](Self::checked_integrand) instead unless they
159 /// explicitly wish to handle invalid values themselves.
160 fn fallible_integrand(&self, input: &Self::Input) -> Result<Self::Output, Self::Error>;
161}
162
163pub struct Infallible<Integrator>(pub Integrator);
164
165impl<Proc> Deref for Infallible<Proc> {
166 type Target = Proc;
167 fn deref(&self) -> &Self::Target {
168 &self.0
169 }
170}
171
172impl<Integrator> FallibleIntegrable for Infallible<Integrator>
173where
174 Integrator: Integrable,
175{
176 type Float = Integrator::Float;
177 type Input = Integrator::Input;
178 type Output = Integrator::Output;
179 type Error = std::convert::Infallible;
180
181 fn fallible_integrand(&self, input: &Self::Input) -> Result<Self::Output, Self::Error> {
182 Ok(self.integrand(input))
183 }
184}
185
186/// Floating-point type supported by the integration routines.
187///
188/// This trait bundles together the numerical functionality required by the
189/// integration algorithms. It is primarily an implementation detail used to
190/// restrict the supported scalar types.
191///
192/// Currently the crate supports:
193///
194/// - `f32`
195/// - `f64`
196pub trait IntegrableFloat:
197 ComplexScalar + Float + FromPrimitive + AddAssign + SubAssign + TrellisFloat + Send + Sync + 'static
198{
199}
200
201impl IntegrableFloat for f32 {}
202impl IntegrableFloat for f64 {}
203
204/// Floating-point type with an associated complex scalar type.
205///
206/// This trait is used by complex contour pieces. It connects a real scalar
207/// type, such as `f64`, to the corresponding complex type,
208/// such as `Complex<f64>`.
209///
210/// It also provides a constructor for complex values from real and imaginary
211/// parts, avoiding repeated low-level bounds throughout the contour
212/// implementation.
213pub trait ComplexScalar: Float {
214 type Complex: ComplexField<RealField = Self> + Copy;
215
216 fn complex(re: Self, im: Self) -> Self::Complex;
217}
218
219impl ComplexScalar for f32 {
220 type Complex = Complex<f32>;
221
222 fn complex(re: Self, im: Self) -> Self::Complex {
223 num_complex::Complex::new(re, im)
224 }
225}
226
227impl ComplexScalar for f64 {
228 type Complex = Complex<f64>;
229
230 fn complex(re: Self, im: Self) -> Self::Complex {
231 Complex::new(re, im)
232 }
233}