Skip to main content

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}