1pub use crate::extrapolation_modules::*;
55
56pub fn create_simple_extrapolator<T: scirs2_core::numeric::Float + std::fmt::Display>(
60 lower_bound: T,
61 upper_bound: T,
62 lower_value: T,
63 upper_value: T,
64 method: ExtrapolationMethod,
65) -> Extrapolator<T> {
66 Extrapolator::new(
67 lower_bound,
68 upper_bound,
69 lower_value,
70 upper_value,
71 method,
72 method,
73 )
74}
75
76pub fn create_asymmetric_extrapolator<T: scirs2_core::numeric::Float + std::fmt::Display>(
78 lower_bound: T,
79 upper_bound: T,
80 lower_value: T,
81 upper_value: T,
82 lower_method: ExtrapolationMethod,
83 upper_method: ExtrapolationMethod,
84) -> Extrapolator<T> {
85 Extrapolator::new(
86 lower_bound,
87 upper_bound,
88 lower_value,
89 upper_value,
90 lower_method,
91 upper_method,
92 )
93}
94
95pub fn create_production_extrapolator<T: scirs2_core::numeric::Float + std::fmt::Display>(
97 lower_bound: T,
98 upper_bound: T,
99 lower_value: T,
100 upper_value: T,
101 lower_derivative: T,
102 upper_derivative: T,
103) -> Extrapolator<T> {
104 make_conservative_extrapolator(
105 lower_bound,
106 upper_bound,
107 lower_value,
108 upper_value,
109 lower_derivative,
110 upper_derivative,
111 (upper_bound - lower_bound) * T::from(2.0).expect("Operation failed"), )
113}
114
115pub fn create_optimized_extrapolator<
117 T: scirs2_core::numeric::Float
118 + scirs2_core::numeric::FromPrimitive
119 + std::fmt::Display
120 + std::default::Default
121 + std::ops::AddAssign,
122>(
123 lower_bound: T,
124 upper_bound: T,
125 lower_value: T,
126 upper_value: T,
127 lower_derivative: T,
128 upper_derivative: T,
129 values: &[T],
130 gradients: Option<&[T]>,
131) -> AdvancedExtrapolator<T> {
132 let characteristics = analyze_data_for_extrapolation(values, gradients);
133 create_smart_extrapolator(
134 lower_bound,
135 upper_bound,
136 lower_value,
137 upper_value,
138 lower_derivative,
139 upper_derivative,
140 &characteristics,
141 )
142}
143
144pub fn extrapolate_value<T: scirs2_core::numeric::Float + std::fmt::Display>(
146 x: T,
147 domain: (T, T),
148 boundary_values: (T, T),
149 method: ExtrapolationMethod,
150) -> crate::error::InterpolateResult<T> {
151 let (lower_bound, upper_bound) = domain;
152 let (lower_value, upper_value) = boundary_values;
153
154 let extrapolator =
155 create_simple_extrapolator(lower_bound, upper_bound, lower_value, upper_value, method);
156
157 extrapolator.extrapolate(x)
158}
159
160pub fn extrapolate_batch<T: scirs2_core::numeric::Float + std::fmt::Display>(
162 x_values: &[T],
163 domain: (T, T),
164 boundary_values: (T, T),
165 method: ExtrapolationMethod,
166) -> Vec<crate::error::InterpolateResult<T>> {
167 let (lower_bound, upper_bound) = domain;
168 let (lower_value, upper_value) = boundary_values;
169
170 let extrapolator =
171 create_simple_extrapolator(lower_bound, upper_bound, lower_value, upper_value, method);
172
173 x_values
174 .iter()
175 .map(|&x| extrapolator.extrapolate(x))
176 .collect()
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use approx::assert_abs_diff_eq;
183
184 #[test]
185 fn test_simple_extrapolator() {
186 let extrapolator =
187 create_simple_extrapolator(0.0, 10.0, 0.0, 10.0, ExtrapolationMethod::Linear);
188
189 let result = extrapolator.extrapolate(-5.0).expect("Operation failed");
190 assert_abs_diff_eq!(result, -5.0, epsilon = 1e-10);
191 }
192
193 #[test]
194 fn test_asymmetric_extrapolator() {
195 let extrapolator = create_asymmetric_extrapolator(
196 0.0,
197 10.0,
198 0.0,
199 10.0,
200 ExtrapolationMethod::Linear,
201 ExtrapolationMethod::Constant,
202 );
203
204 let result = extrapolator.extrapolate(-5.0).expect("Operation failed");
206 assert!(result != 0.0); let result = extrapolator.extrapolate(15.0).expect("Operation failed");
210 assert_abs_diff_eq!(result, 10.0, epsilon = 1e-10); }
212
213 #[test]
214 fn test_production_extrapolator() {
215 let extrapolator = create_production_extrapolator(0.0, 10.0, 0.0, 10.0, 1.0, 1.0);
216
217 let result = extrapolator.extrapolate(-5.0).expect("Operation failed");
218 assert_abs_diff_eq!(result, -5.0, epsilon = 1e-10);
219 }
220
221 #[test]
222 fn test_quick_extrapolation() {
223 let result = extrapolate_value(-5.0, (0.0, 10.0), (0.0, 10.0), ExtrapolationMethod::Linear)
224 .expect("Operation failed");
225
226 assert_abs_diff_eq!(result, -5.0, epsilon = 1e-10);
227 }
228
229 #[test]
230 fn test_batch_extrapolation() {
231 let x_values = vec![-5.0, -2.0, 12.0, 15.0];
232 let results = extrapolate_batch(
233 &x_values,
234 (0.0, 10.0),
235 (0.0, 10.0),
236 ExtrapolationMethod::Linear,
237 );
238
239 assert_eq!(results.len(), 4);
240 assert!(results.iter().all(|r| r.is_ok()));
241
242 assert_abs_diff_eq!(
243 results[0].as_ref().expect("Operation failed"),
244 &-5.0,
245 epsilon = 1e-10
246 );
247 assert_abs_diff_eq!(
248 results[1].as_ref().expect("Operation failed"),
249 &-2.0,
250 epsilon = 1e-10
251 );
252 assert_abs_diff_eq!(
253 results[2].as_ref().expect("Operation failed"),
254 &12.0,
255 epsilon = 1e-10
256 );
257 assert_abs_diff_eq!(
258 results[3].as_ref().expect("Operation failed"),
259 &15.0,
260 epsilon = 1e-10
261 );
262 }
263
264 #[test]
265 fn test_optimized_extrapolator() {
266 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
267 let gradient_vec = vec![1.0, 1.0, 1.0, 1.0];
268 let gradients = Some(gradient_vec.as_slice());
269
270 let extrapolator =
271 create_optimized_extrapolator(0.0, 4.0, 1.0, 5.0, 1.0, 1.0, &values, gradients);
272
273 let result = extrapolator.extrapolate_advanced(-1.0);
274 assert!(result.is_ok());
275 }
276
277 #[test]
278 fn test_zeros_method() {
279 let result = extrapolate_value(-5.0, (0.0, 10.0), (5.0, 15.0), ExtrapolationMethod::Zeros)
280 .expect("Operation failed");
281
282 assert_abs_diff_eq!(result, 0.0, epsilon = 1e-10);
283 }
284
285 #[test]
286 fn test_nearest_method() {
287 let extrapolator =
288 create_simple_extrapolator(0.0, 10.0, 5.0, 15.0, ExtrapolationMethod::Nearest);
289
290 let result = extrapolator.extrapolate(-5.0).expect("Operation failed");
292 assert_abs_diff_eq!(result, 5.0, epsilon = 1e-10);
293
294 let result = extrapolator.extrapolate(15.0).expect("Operation failed");
296 assert_abs_diff_eq!(result, 15.0, epsilon = 1e-10);
297 }
298
299 #[test]
300 fn test_error_for_in_domain_points() {
301 let extrapolator =
302 create_simple_extrapolator(0.0, 10.0, 0.0, 10.0, ExtrapolationMethod::Linear);
303
304 let result = extrapolator.extrapolate(5.0);
306 assert!(result.is_err());
307 }
308}