1use nalgebra::{ComplexField, RealField};
2use num_traits::FromPrimitive;
3
4use std::ops::Range;
5use trellis_runner::{Calculation, Problem};
6
7use crate::{
8 contour::split_range_around_singularities, AccumulateError, Contour, GaussKronrod,
9 GaussKronrodCore, Integrable, IntegrableFloat, IntegrationError, IntegrationOutput,
10 IntegrationResult, IntegrationState, RescaleError,
11};
12
13#[derive(Debug)]
14pub struct AdaptiveIntegrator<F: ComplexField> {
15 limits: Range<F>,
16 max_elements: usize,
17 minimum_element_size: <F as ComplexField>::RealField,
18 singularities: Vec<F>,
19 integrator: GaussKronrod<<F as ComplexField>::RealField>,
20 relative_tolerance: <F as ComplexField>::RealField,
21 absolute_tolerance: <F as ComplexField>::RealField,
22}
23
24impl<F: ComplexField> AdaptiveIntegrator<F> {
25 pub fn new_real(
26 Range { start, end }: Range<<F as ComplexField>::RealField>,
27 max_elements: usize,
28 minimum_element_size: <F as ComplexField>::RealField,
29 singularities: Vec<F>,
30 relative_tolerance: <F as ComplexField>::RealField,
31 absolute_tolerance: <F as ComplexField>::RealField,
32 ) -> Self {
33 Self {
34 limits: Range {
35 start: F::from_real(start),
36 end: F::from_real(end),
37 },
38 max_elements,
39 minimum_element_size,
40 singularities,
41 integrator: GaussKronrod::default(),
42 relative_tolerance,
43 absolute_tolerance,
44 }
45 }
46
47 pub fn new(
48 limits: Range<F>,
49 max_elements: usize,
50 minimum_element_size: <F as ComplexField>::RealField,
51 singularities: Vec<F>,
52 relative_tolerance: <F as ComplexField>::RealField,
53 absolute_tolerance: <F as ComplexField>::RealField,
54 ) -> Self {
55 Self {
56 limits,
57 max_elements,
58 minimum_element_size,
59 singularities,
60 integrator: GaussKronrod::default(),
61 relative_tolerance,
62 absolute_tolerance,
63 }
64 }
65}
66
67impl<P> Integrable for Problem<P>
68where
69 P: Integrable,
70{
71 type Input = P::Input;
72 type Output = P::Output;
73
74 fn integrand(
75 &self,
76 input: &Self::Input,
77 ) -> Result<Self::Output, crate::EvaluationError<Self::Input>> {
78 self.as_ref().integrand(input)
79 }
80}
81
82impl<I, O, F, P> Calculation<P, IntegrationState<I, O, F>> for AdaptiveIntegrator<I>
83where
84 P: Integrable<Input = I, Output = O> + Send + Sync,
85 I: ComplexField<RealField = F> + FromPrimitive + Copy,
86 O: IntegrationOutput<Float = F, Scalar = I>,
87 F: IntegrableFloat + RealField + FromPrimitive + AccumulateError<F> + RescaleError,
88{
89 const NAME: &'static str = "Adaptive Integrator";
90 type Error = IntegrationError<I>;
91 type Output = IntegrationResult<I, O>;
92
93 fn initialise(
94 &mut self,
95 problem: &mut Problem<P>,
96 state: IntegrationState<I, O, F>,
97 ) -> Result<IntegrationState<I, O, F>, Self::Error> {
98 let initial_segments = match self.singularities.len() {
99 0 => self
100 .integrator
101 .gauss_kronrod(&*problem, self.limits.clone())?,
103 _ => split_range_around_singularities(self.limits.clone(), self.singularities.clone())
104 .into_iter()
105 .map(|range| {
106 self.integrator
107 .gauss_kronrod(&*problem, range)
109 })
110 .collect::<Result<Vec<_>, _>>()?
111 .into_iter()
112 .flatten()
113 .collect(),
114 };
115
116 Ok(state.segments(initial_segments))
117 }
118
119 fn next(
120 &mut self,
121 problem: &mut Problem<P>,
122 mut state: IntegrationState<I, O, F>,
123 ) -> Result<IntegrationState<I, O, F>, Self::Error> {
124 let worst_segment = state.pop_worst_segment().unwrap();
125 let new_segments = self.integrator.split_segment(&*problem, worst_segment)?;
126 Ok(state.segments(new_segments))
127 }
128
129 fn finalise(
130 &mut self,
131 _problem: &mut Problem<P>,
132 state: IntegrationState<I, O, F>,
133 ) -> Result<Self::Output, Self::Error> {
134 Ok(state.into())
135 }
136}
137
138#[derive(Debug)]
139pub struct AdaptiveRectangularContourIntegrator<F: ComplexField> {
140 pub(crate) contour: Contour<F>,
141 pub(crate) max_elements: usize,
142 pub(crate) minimum_element_size: <F as ComplexField>::RealField,
143 pub(crate) integrator: GaussKronrod<<F as ComplexField>::RealField>,
144 pub(crate) relative_tolerance: <F as ComplexField>::RealField,
145 pub(crate) absolute_tolerance: <F as ComplexField>::RealField,
146}
147
148impl<F> AdaptiveRectangularContourIntegrator<F>
149where
150 F: ComplexField + Copy,
151 <F as ComplexField>::RealField: Copy,
152{
153 pub fn new(
154 contour: Contour<F>,
155 max_elements: usize,
156 minimum_element_size: <F as ComplexField>::RealField,
157 relative_tolerance: <F as ComplexField>::RealField,
158 absolute_tolerance: <F as ComplexField>::RealField,
159 ) -> Self {
160 Self {
161 contour,
162 max_elements,
163 minimum_element_size,
164 integrator: GaussKronrod::default(),
165 relative_tolerance,
166 absolute_tolerance,
167 }
168 }
169 pub fn initialise<I: Into<Contour<F>>>(
170 input: I,
171 max_elements: usize,
172 minimum_element_size: <F as ComplexField>::RealField,
173 relative_tolerance: <F as ComplexField>::RealField,
174 absolute_tolerance: <F as ComplexField>::RealField,
175 ) -> Self {
176 Self {
177 contour: input.into(),
178 max_elements,
179 minimum_element_size,
180 integrator: GaussKronrod::default(),
181 relative_tolerance,
182 absolute_tolerance,
183 }
184 }
185}
186
187impl<I, O, F, P> Calculation<P, IntegrationState<I, O, F>>
188 for AdaptiveRectangularContourIntegrator<I>
189where
190 P: Integrable<Input = I, Output = O> + Send + Sync,
191 I: ComplexField<RealField = F> + FromPrimitive + Copy,
192 O: IntegrationOutput<Float = F, Scalar = I>,
193 F: IntegrableFloat + RealField + FromPrimitive + AccumulateError<F> + RescaleError,
194{
195 const NAME: &'static str = "Adaptive Contour Integrator";
196 type Error = IntegrationError<I>;
197 type Output = IntegrationResult<I, O>;
198
199 fn initialise(
200 &mut self,
201 problem: &mut Problem<P>,
202 state: IntegrationState<I, O, F>,
203 ) -> Result<IntegrationState<I, O, F>, Self::Error> {
204 let initial_segments = self
205 .contour
206 .range
207 .iter()
208 .map(|range| {
209 self.integrator
210 .gauss_kronrod(&*problem, range.clone())
212 })
213 .collect::<Result<Vec<_>, _>>()?
214 .into_iter()
215 .flatten()
216 .collect();
217 Ok(state.segments(initial_segments))
218 }
219
220 fn next(
221 &mut self,
222 problem: &mut Problem<P>,
223 mut state: IntegrationState<I, O, F>,
224 ) -> Result<IntegrationState<I, O, F>, Self::Error> {
225 let worst_segment = state.pop_worst_segment().unwrap();
226 let new_segments = self
227 .integrator
228 .split_segment(&*problem, worst_segment)?;
230 Ok(state.segments(new_segments))
231 }
232
233 fn finalise(
234 &mut self,
235 _problem: &mut Problem<P>,
236 state: IntegrationState<I, O, F>,
237 ) -> Result<Self::Output, Self::Error> {
238 Ok(state.into())
239 }
240}