1use num_complex::Complex64;
7use std::f64::consts::PI;
8
9use crate::freq::MatsubaraFreq;
10use crate::poly::{PiecewiseLegendrePoly, PiecewiseLegendrePolyVector};
11use crate::special_functions::spherical_bessel_j;
12use crate::traits::{Bosonic, Fermionic, Statistics, StatisticsType};
13
14#[derive(Debug, Clone)]
16pub struct PowerModel {
17 pub moments: Vec<f64>,
18}
19
20impl PowerModel {
21 pub fn new(moments: Vec<f64>) -> Self {
23 Self { moments }
24 }
25}
26
27#[derive(Debug, Clone)]
32pub struct PiecewiseLegendreFT<S: StatisticsType> {
33 pub poly: PiecewiseLegendrePoly,
35 pub n_asymp: f64,
37 pub model: PowerModel,
39 _phantom: std::marker::PhantomData<S>,
40}
41
42pub type FermionicPiecewiseLegendreFT = PiecewiseLegendreFT<Fermionic>;
44pub type BosonicPiecewiseLegendreFT = PiecewiseLegendreFT<Bosonic>;
45
46impl<S: StatisticsType> PiecewiseLegendreFT<S> {
47 pub fn new(poly: PiecewiseLegendrePoly, _stat: S, n_asymp: Option<f64>) -> Self {
57 if (poly.xmin - (-1.0)).abs() > 1e-12 || (poly.xmax - 1.0).abs() > 1e-12 {
59 panic!("Only interval [-1, 1] is supported for Fourier transform");
60 }
61
62 let n_asymp = n_asymp.unwrap_or(f64::INFINITY);
63 let model = Self::power_model(&poly);
64
65 Self {
66 poly,
67 n_asymp,
68 model,
69 _phantom: std::marker::PhantomData,
70 }
71 }
72
73 pub fn get_n_asymp(&self) -> f64 {
75 self.n_asymp
76 }
77
78 pub fn get_statistics(&self) -> Statistics {
80 S::STATISTICS
81 }
82
83 pub fn zeta(&self) -> i64 {
85 match S::STATISTICS {
86 Statistics::Fermionic => 1,
87 Statistics::Bosonic => 0,
88 }
89 }
90
91 pub fn get_poly(&self) -> &PiecewiseLegendrePoly {
93 &self.poly
94 }
95
96 pub fn evaluate(&self, omega: &MatsubaraFreq<S>) -> Complex64 {
104 let n = omega.get_n();
105 if (n as f64).abs() < self.n_asymp {
106 self.compute_unl_inner(&self.poly, n)
107 } else {
108 self.giw(n)
109 }
110 }
111
112 pub fn evaluate_at_n(&self, n: i64) -> Complex64 {
114 match MatsubaraFreq::<S>::new(n) {
115 Ok(omega) => self.evaluate(&omega),
116 Err(_) => Complex64::new(0.0, 0.0), }
118 }
119
120 pub fn evaluate_at_ns(&self, ns: &[i64]) -> Vec<Complex64> {
122 ns.iter().map(|&n| self.evaluate_at_n(n)).collect()
123 }
124
125 fn power_model(poly: &PiecewiseLegendrePoly) -> PowerModel {
127 let deriv_x1 = poly.derivs(1.0);
128 let moments = Self::power_moments(&deriv_x1, poly.l);
129 PowerModel::new(moments)
130 }
131
132 fn power_moments(deriv_x1: &[f64], l: i32) -> Vec<f64> {
134 let statsign = match S::STATISTICS {
135 Statistics::Fermionic => -1.0,
136 Statistics::Bosonic => 1.0,
137 };
138
139 let mut moments = deriv_x1.to_vec();
140 for (m, moment) in moments.iter_mut().enumerate() {
141 let m_f64 = (m + 1) as f64; *moment *=
143 -(statsign * (-1.0_f64).powi(m_f64 as i32) + (-1.0_f64).powi(l)) / 2.0_f64.sqrt();
144 }
145 moments
146 }
147
148 fn compute_unl_inner(&self, poly: &PiecewiseLegendrePoly, wn: i64) -> Complex64 {
150 let wred = PI / 4.0 * wn as f64;
151 let phase_wi = Self::phase_stable(poly, wn);
152 let mut res = Complex64::new(0.0, 0.0);
153
154 let order_max = poly.polyorder;
155 let segment_count = poly.knots.len() - 1;
156
157 for order in 0..order_max {
158 for j in 0..segment_count {
159 let data_oj = poly.data[[order, j]];
160 let tnl = Self::get_tnl(order as i32, wred * poly.delta_x[j]);
161 res += data_oj * tnl * phase_wi[j] / poly.norms[j];
162 }
163 }
164
165 res / 2.0_f64.sqrt()
166 }
167
168 fn giw(&self, wn: i64) -> Complex64 {
170 let iw = Complex64::new(0.0, PI / 2.0 * wn as f64);
171 if wn == 0 {
172 return Complex64::new(0.0, 0.0);
173 }
174
175 let inv_iw = 1.0 / iw;
176
177 inv_iw * Self::evalpoly(inv_iw, &self.model.moments)
178 }
179
180 fn evalpoly(x: Complex64, coeffs: &[f64]) -> Complex64 {
182 let mut result = Complex64::new(0.0, 0.0);
183 for i in (0..coeffs.len()).rev() {
184 result = result * x + Complex64::new(coeffs[i], 0.0);
185 }
186 result
187 }
188
189 fn shift_xmid(knots: &[f64], delta_x: &[f64]) -> (Vec<f64>, Vec<i32>) {
195 let n_segments = delta_x.len();
196 let delta_x_half: Vec<f64> = delta_x.iter().map(|&dx| dx / 2.0).collect();
197
198 let mut xmid_m1 = Vec::with_capacity(n_segments);
200 let mut cumsum = 0.0;
201 for i in 0..n_segments {
202 cumsum += delta_x[i];
203 xmid_m1.push(cumsum - delta_x_half[i]);
204 }
205
206 let mut xmid_p1 = Vec::with_capacity(n_segments);
208 let mut cumsum_rev = 0.0;
209 for i in (0..n_segments).rev() {
210 cumsum_rev += delta_x[i];
211 xmid_p1.insert(0, -cumsum_rev + delta_x_half[i]);
212 }
213
214 let xmid_0: Vec<f64> = (0..n_segments)
216 .map(|i| knots[i + 1] - delta_x_half[i])
217 .collect();
218
219 let mut xmid_diff = Vec::with_capacity(n_segments);
221 let mut extra_shift = Vec::with_capacity(n_segments);
222
223 for i in 0..n_segments {
224 let shift = xmid_0[i].round() as i32;
225 extra_shift.push(shift);
226
227 let diff = match shift {
229 -1 => xmid_m1[i],
230 0 => xmid_0[i],
231 1 => xmid_p1[i],
232 _ => xmid_0[i], };
234 xmid_diff.push(diff);
235 }
236
237 (xmid_diff, extra_shift)
238 }
239
240 fn phase_stable(poly: &PiecewiseLegendrePoly, wn: i64) -> Vec<Complex64> {
245 let (xmid_diff, extra_shift) = Self::shift_xmid(&poly.knots, &poly.delta_x);
246 let mut phase_wi = Vec::with_capacity(xmid_diff.len());
247
248 let im_unit = Complex64::new(0.0, 1.0);
249
250 for j in 0..xmid_diff.len() {
251 let power = ((wn * (extra_shift[j] as i64 + 1)) % 4 + 4) % 4; let im_power = im_unit.powi(power as i32);
254
255 let arg = PI * wn as f64 * xmid_diff[j] / 2.0;
257 let cispi = Complex64::new(arg.cos(), arg.sin());
258
259 phase_wi.push(im_power * cispi);
260 }
261
262 phase_wi
263 }
264
265 pub fn sign_changes(&self, positive_only: bool) -> Vec<MatsubaraFreq<S>> {
273 let f = Self::func_for_part(self);
274 let x0 = Self::find_all_roots(&f, DEFAULT_GRID);
275
276 let mut matsubara_indices: Vec<i64> = x0.into_iter().map(|x| 2 * x + self.zeta()).collect();
278
279 if !positive_only {
280 symmetrize_matsubara_inplace(&mut matsubara_indices);
281 }
282
283 matsubara_indices
284 .into_iter()
285 .filter_map(|n| MatsubaraFreq::<S>::new(n).ok())
286 .collect()
287 }
288
289 pub fn find_extrema(&self, positive_only: bool) -> Vec<MatsubaraFreq<S>> {
297 let f = Self::func_for_part(self);
298 let x0 = Self::discrete_extrema(&f, DEFAULT_GRID);
299
300 let mut matsubara_indices: Vec<i64> = x0.into_iter().map(|x| 2 * x + self.zeta()).collect();
302
303 if !positive_only {
304 symmetrize_matsubara_inplace(&mut matsubara_indices);
305 }
306
307 matsubara_indices
308 .into_iter()
309 .filter_map(|n| MatsubaraFreq::<S>::new(n).ok())
310 .collect()
311 }
312
313 fn func_for_part(&self) -> impl Fn(i64) -> f64 + '_ {
318 let parity = self.poly.symm;
319 let poly_ft = self.clone();
320 let zeta = self.zeta();
321
322 move |n| {
323 let matsubara_n = 2 * n + zeta;
325 let omega = match MatsubaraFreq::<S>::new(matsubara_n) {
326 Ok(omega) => omega,
327 Err(_) => return 0.0,
328 };
329 let value = poly_ft.evaluate(&omega);
330
331 match parity {
332 1 => match S::STATISTICS {
333 Statistics::Fermionic => value.im,
334 Statistics::Bosonic => value.re,
335 },
336 -1 => match S::STATISTICS {
337 Statistics::Fermionic => value.re,
338 Statistics::Bosonic => value.im,
339 },
340 0 => {
341 value.re
343 }
344 _ => panic!("Cannot detect parity for symm = {}", parity),
345 }
346 }
347 }
348
349 fn find_all_roots<F>(f: &F, xgrid: &[i64]) -> Vec<i64>
351 where
352 F: Fn(i64) -> f64,
353 {
354 if xgrid.is_empty() {
355 return Vec::new();
356 }
357
358 let fx: Vec<f64> = xgrid.iter().map(|&x| f(x)).collect();
360
361 let mut x_hit = Vec::new();
363 for i in 0..fx.len() {
364 if fx[i] == 0.0 {
365 x_hit.push(xgrid[i]);
366 }
367 }
368
369 let mut sign_change = Vec::new();
371 for i in 0..fx.len() - 1 {
372 let has_sign_change = fx[i].signum() != fx[i + 1].signum();
373 let not_hit = fx[i] != 0.0 && fx[i + 1] != 0.0;
374 let both_nonzero = fx[i].abs() > 1e-12 && fx[i + 1].abs() > 1e-12;
375 sign_change.push(has_sign_change && not_hit && both_nonzero);
376 }
377
378 if sign_change.iter().all(|&sc| !sc) {
380 x_hit.sort();
381 return x_hit;
382 }
383
384 let mut a_intervals = Vec::new();
386 let mut b_intervals = Vec::new();
387 let mut fa_values = Vec::new();
388
389 for i in 0..sign_change.len() {
390 if sign_change[i] {
391 a_intervals.push(xgrid[i]);
392 b_intervals.push(xgrid[i + 1]);
393 fa_values.push(fx[i]);
394 }
395 }
396
397 for i in 0..a_intervals.len() {
399 let root = Self::bisect(&f, a_intervals[i], b_intervals[i], fa_values[i]);
400 x_hit.push(root);
401 }
402
403 x_hit.sort();
405 x_hit
406 }
407
408 fn bisect<F>(f: &F, a: i64, b: i64, fa: f64) -> i64
410 where
411 F: Fn(i64) -> f64,
412 {
413 let mut a = a;
414 let mut b = b;
415 let mut fa = fa;
416
417 loop {
418 if (b - a).abs() <= 1 {
419 return a;
420 }
421
422 let mid = (a + b) / 2;
423 let fmid = f(mid);
424
425 if fa.signum() != fmid.signum() {
426 b = mid;
427 } else {
428 a = mid;
429 fa = fmid;
430 }
431 }
432 }
433
434 fn discrete_extrema<F>(f: &F, xgrid: &[i64]) -> Vec<i64>
436 where
437 F: Fn(i64) -> f64,
438 {
439 discrete_extrema(f, xgrid)
440 }
441
442 pub fn get_tnl(l: i32, w: f64) -> Complex64 {
448 let abs_w = w.abs();
449
450 let sph_bessel = spherical_bessel_j(l, abs_w);
452
453 let im_unit = Complex64::new(0.0, 1.0);
455 let im_power = im_unit.powi(l);
456 let result = 2.0 * im_power * sph_bessel;
457
458 if w < 0.0 { result.conj() } else { result }
460 }
461}
462
463#[derive(Debug, Clone)]
465pub struct PiecewiseLegendreFTVector<S: StatisticsType> {
466 pub polyvec: Vec<PiecewiseLegendreFT<S>>,
467 _phantom: std::marker::PhantomData<S>,
468}
469
470pub type FermionicPiecewiseLegendreFTVector = PiecewiseLegendreFTVector<Fermionic>;
472pub type BosonicPiecewiseLegendreFTVector = PiecewiseLegendreFTVector<Bosonic>;
473
474impl<S: StatisticsType> PiecewiseLegendreFTVector<S> {
475 pub fn new() -> Self {
477 Self {
478 polyvec: Vec::new(),
479 _phantom: std::marker::PhantomData,
480 }
481 }
482
483 pub fn from_vector(polyvec: Vec<PiecewiseLegendreFT<S>>) -> Self {
485 Self {
486 polyvec,
487 _phantom: std::marker::PhantomData,
488 }
489 }
490
491 pub fn len(&self) -> usize {
493 self.polyvec.len()
494 }
495
496 pub fn is_empty(&self) -> bool {
498 self.polyvec.is_empty()
499 }
500
501 pub fn from_poly_vector(
503 polys: &PiecewiseLegendrePolyVector,
504 _stat: S,
505 n_asymp: Option<f64>,
506 ) -> Self {
507 let mut polyvec = Vec::with_capacity(polys.size());
508
509 for i in 0..polys.size() {
510 let poly = polys.get(i).unwrap().clone();
511 let ft_poly = PiecewiseLegendreFT::new(poly, _stat, n_asymp);
512 polyvec.push(ft_poly);
513 }
514
515 Self {
516 polyvec,
517 _phantom: std::marker::PhantomData,
518 }
519 }
520
521 pub fn size(&self) -> usize {
523 self.polyvec.len()
524 }
525
526 pub fn get(&self, index: usize) -> Option<&PiecewiseLegendreFT<S>> {
528 self.polyvec.get(index)
529 }
530
531 pub fn get_mut(&mut self, index: usize) -> Option<&mut PiecewiseLegendreFT<S>> {
533 self.polyvec.get_mut(index)
534 }
535
536 pub fn set(&mut self, index: usize, poly: PiecewiseLegendreFT<S>) -> Result<(), String> {
538 if index >= self.polyvec.len() {
539 return Err(format!("Index {} out of range", index));
540 }
541 self.polyvec[index] = poly;
542 Ok(())
543 }
544
545 pub fn similar(&self) -> Self {
547 Self::new()
548 }
549
550 pub fn n_asymp(&self) -> f64 {
552 self.polyvec.first().map_or(f64::INFINITY, |p| p.n_asymp)
553 }
554
555 pub fn evaluate_at(&self, omega: &MatsubaraFreq<S>) -> Vec<Complex64> {
557 self.polyvec
558 .iter()
559 .map(|poly| poly.evaluate(omega))
560 .collect()
561 }
562
563 pub fn evaluate_at_many(&self, omegas: &[MatsubaraFreq<S>]) -> Vec<Vec<Complex64>> {
565 omegas.iter().map(|omega| self.evaluate_at(omega)).collect()
566 }
567}
568
569impl<S: StatisticsType> std::ops::Index<usize> for PiecewiseLegendreFTVector<S> {
571 type Output = PiecewiseLegendreFT<S>;
572
573 fn index(&self, index: usize) -> &Self::Output {
574 &self.polyvec[index]
575 }
576}
577
578impl<S: StatisticsType> std::ops::IndexMut<usize> for PiecewiseLegendreFTVector<S> {
579 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
580 &mut self.polyvec[index]
581 }
582}
583
584impl<S: StatisticsType> Default for PiecewiseLegendreFTVector<S> {
586 fn default() -> Self {
587 Self::new()
588 }
589}
590
591const DEFAULT_GRID: &[i64] = &[
597 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
598 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
599 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 71, 72, 74, 76, 77,
600 79, 81, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 103, 105, 107, 109, 112, 114, 117, 119, 122,
601 125, 128, 130, 133, 136, 139, 142, 145, 148, 152, 155, 158, 162, 165, 169, 173, 177, 181, 184,
602 189, 193, 197, 201, 206, 210, 215, 219, 224, 229, 234, 239, 245, 250, 256, 261, 267, 273, 279,
603 285, 291, 297, 304, 311, 317, 324, 331, 339, 346, 354, 362, 369, 378, 386, 394, 403, 412, 421,
604 430, 439, 449, 459, 469, 479, 490, 501, 512, 523, 534, 546, 558, 570, 583, 595, 608, 622, 635,
605 649, 663, 678, 693, 708, 724, 739, 756, 772, 789, 806, 824, 842, 861, 879, 899, 918, 939, 959,
606 980, 1002, 1024, 1046, 1069, 1092, 1116, 1141, 1166, 1191, 1217, 1244, 1271, 1299, 1327, 1357,
607 1386, 1417, 1448, 1479, 1512, 1545, 1579, 1613, 1649, 1685, 1722, 1759, 1798, 1837, 1878, 1919,
608 1961, 2004, 2048, 2092, 2138, 2185, 2233, 2282, 2332, 2383, 2435, 2488, 2543, 2599, 2655, 2714,
609 2773, 2834, 2896, 2959, 3024, 3090, 3158, 3227, 3298, 3370, 3444, 3519, 3596, 3675, 3756, 3838,
610 3922, 4008, 4096, 4185, 4277, 4371, 4466, 4564, 4664, 4766, 4870, 4977, 5086, 5198, 5311, 5428,
611 5547, 5668, 5792, 5919, 6049, 6181, 6316, 6455, 6596, 6741, 6888, 7039, 7193, 7351, 7512, 7676,
612 7844, 8016, 8192, 8371, 8554, 8742, 8933, 9129, 9328, 9533, 9741, 9955, 10173, 10396, 10623,
613 10856, 11094, 11336, 11585, 11838, 12098, 12363, 12633, 12910, 13193, 13482, 13777, 14078,
614 14387, 14702, 15024, 15353, 15689, 16032, 16384, 16742, 17109, 17484, 17866, 18258, 18657,
615 19066, 19483, 19910, 20346, 20792, 21247, 21712, 22188, 22673, 23170, 23677, 24196, 24726,
616 25267, 25820, 26386, 26964, 27554, 28157, 28774, 29404, 30048, 30706, 31378, 32065, 32768,
617 33485, 34218, 34968, 35733, 36516, 37315, 38132, 38967, 39821, 40693, 41584, 42494, 43425,
618 44376, 45347, 46340, 47355, 48392, 49452, 50535, 51641, 52772, 53928, 55108, 56315, 57548,
619 58809, 60096, 61412, 62757, 64131, 65536, 66971, 68437, 69936, 71467, 73032, 74631, 76265,
620 77935, 79642, 81386, 83168, 84989, 86850, 88752, 90695, 92681, 94711, 96785, 98904, 101070,
621 103283, 105545, 107856, 110217, 112631, 115097, 117618, 120193, 122825, 125514, 128263, 131072,
622 133942, 136875, 139872, 142935, 146064, 149263, 152531, 155871, 159284, 162772, 166337, 169979,
623 173701, 177504, 181391, 185363, 189422, 193570, 197809, 202140, 206566, 211090, 215712, 220435,
624 225262, 230195, 235236, 240387, 245650, 251029, 256526, 262144, 267884, 273750, 279744, 285870,
625 292129, 298526, 305063, 311743, 318569, 325545, 332674, 339958, 347402, 355009, 362783, 370727,
626 378845, 387141, 395618, 404281, 413133, 422180, 431424, 440871, 450525, 460390, 470472, 480774,
627 491301, 502059, 513053, 524288, 535768, 547500, 559488, 571740, 584259, 597053, 610126, 623487,
628 637139, 651091, 665348, 679917, 694805, 710019, 725567, 741455, 757690, 774282, 791236, 808562,
629 826267, 844360, 862849, 881743, 901051, 920781, 940944, 961548, 982603, 1004119, 1026107,
630 1048576, 1071536, 1095000, 1118977, 1143480, 1168519, 1194106, 1220253, 1246974, 1274279,
631 1302182, 1330696, 1359834, 1389611, 1420039, 1451134, 1482910, 1515381, 1548564, 1582473,
632 1617125, 1652535, 1688721, 1725699, 1763487, 1802102, 1841563, 1881888, 1923096, 1965207,
633 2008239, 2052214, 2097152, 2143073, 2190000, 2237955, 2286960, 2337038, 2388212, 2440507,
634 2493948, 2548558, 2604364, 2661392, 2719669, 2779222, 2840079, 2902269, 2965820, 3030763,
635 3097128, 3164947, 3234250, 3305071, 3377443, 3451399, 3526975, 3604205, 3683127, 3763777,
636 3846193, 3930414, 4016479, 4104428, 4194304, 4286147, 4380001, 4475911, 4573920, 4674076,
637 4776425, 4881015, 4987896, 5097116, 5208729, 5322785, 5439339, 5558445, 5680159, 5804538,
638 5931641, 6061527, 6194257, 6329894, 6468501, 6610142, 6754886, 6902798, 7053950, 7208411,
639 7366255, 7527555, 7692387, 7860828, 8032958, 8208857, 8388608, 8572294, 8760003, 8951822,
640 9147841, 9348153, 9552851, 9762031, 9975792, 10194233, 10417458, 10645571, 10878678, 11116890,
641 11360318, 11609077, 11863283, 12123055, 12388515, 12659788, 12937002, 13220285, 13509772,
642 13805597, 14107900, 14416823, 14732510, 15055110, 15384774, 15721657, 16065917, 16417714,
643 16777216, 17144589, 17520006, 17903645, 18295683, 18696307, 19105702, 19524063, 19951584,
644 20388467, 20834916, 21291142, 21757357, 22233781, 22720637, 23218155, 23726566, 24246110,
645 24777031, 25319577, 25874004, 26440571, 27019544, 27611195, 28215801, 28833647, 29465021,
646 30110221, 30769549, 31443315, 32131834, 32835429, 33554432,
647];
648
649pub fn sign_changes<S: StatisticsType + 'static>(
653 u_hat: &PiecewiseLegendreFT<S>,
654 positive_only: bool,
655) -> Vec<MatsubaraFreq<S>> {
656 let f = func_for_part(u_hat);
657 let x0 = find_all(&f, DEFAULT_GRID);
658
659 let mut indices: Vec<i64> = x0.iter().map(|&x| 2 * x + u_hat.zeta()).collect();
661
662 if !positive_only {
663 symmetrize_matsubara_inplace(&mut indices);
664 }
665
666 indices
667 .iter()
668 .filter_map(|&n| MatsubaraFreq::<S>::new(n).ok())
669 .collect()
670}
671
672pub fn find_extrema<S: StatisticsType + 'static>(
676 u_hat: &PiecewiseLegendreFT<S>,
677 positive_only: bool,
678) -> Vec<MatsubaraFreq<S>> {
679 let f = func_for_part(u_hat);
680 let x0 = discrete_extrema(&f, DEFAULT_GRID);
681
682 let mut indices: Vec<i64> = x0.iter().map(|&x| 2 * x + u_hat.zeta()).collect();
684
685 if !positive_only {
686 symmetrize_matsubara_inplace(&mut indices);
687 }
688
689 indices
690 .iter()
691 .filter_map(|&n| MatsubaraFreq::<S>::new(n).ok())
692 .collect()
693}
694
695fn func_for_part<S: StatisticsType + 'static>(
697 poly_ft: &PiecewiseLegendreFT<S>,
698) -> Box<dyn Fn(i64) -> f64> {
699 let parity = poly_ft.poly.symm();
700 let zeta = poly_ft.zeta();
701
702 let poly_ft_clone = poly_ft.clone();
704
705 Box::new(move |n: i64| {
706 let omega = MatsubaraFreq::<S>::new(2 * n + zeta).unwrap();
707 let value = poly_ft_clone.evaluate(&omega);
708
709 if parity == 1 {
711 if S::STATISTICS == Statistics::Bosonic {
713 value.re
714 } else {
715 value.im
716 }
717 } else if parity == -1 {
718 if S::STATISTICS == Statistics::Bosonic {
720 value.im
721 } else {
722 value.re
723 }
724 } else {
725 panic!("Cannot detect parity");
726 }
727 })
728}
729
730fn bisect(f: &dyn Fn(i64) -> f64, a: i64, b: i64, fa: f64) -> i64 {
734 let mut lo = a;
735 let mut hi = b;
736 let mut flo = fa;
737
738 while (hi - lo).abs() > 1 {
739 let mid = lo + (hi - lo) / 2;
740 let fmid = f(mid);
741 if flo.signum() != fmid.signum() {
742 hi = mid;
743 } else {
744 lo = mid;
745 flo = fmid;
746 }
747 }
748 lo
749}
750
751fn bisect_discr_extremum(f: &dyn Fn(i64) -> f64, a: i64, b: i64) -> i64 {
755 let mut lo = a;
756 let mut hi = b;
757
758 while hi - lo > 2 {
759 let mid1 = lo + (hi - lo) / 3;
760 let mid2 = hi - (hi - lo) / 3;
761 if f(mid1).abs() < f(mid2).abs() {
762 lo = mid1;
763 } else {
764 hi = mid2;
765 }
766 }
767
768 let mut best = lo;
770 let mut best_val = f(lo).abs();
771 for x in (lo + 1)..=hi {
772 let val = f(x).abs();
773 if val > best_val {
774 best = x;
775 best_val = val;
776 }
777 }
778 best
779}
780
781fn find_all(f: &dyn Fn(i64) -> f64, xgrid: &[i64]) -> Vec<i64> {
785 if xgrid.is_empty() {
786 return Vec::new();
787 }
788
789 let mut results = Vec::new();
790 let mut prev_val = f(xgrid[0]);
791
792 for i in 1..xgrid.len() {
793 let val = f(xgrid[i]);
794 if prev_val.signum() != val.signum() && prev_val != 0.0 && val != 0.0 {
796 let root = bisect(f, xgrid[i - 1], xgrid[i], prev_val);
798 results.push(root);
799 }
800 prev_val = val;
801 }
802
803 results
804}
805
806fn discrete_extrema(f: &dyn Fn(i64) -> f64, xgrid: &[i64]) -> Vec<i64> {
810 if xgrid.len() < 3 {
811 return Vec::new();
812 }
813
814 let fx: Vec<f64> = xgrid.iter().map(|&x| f(x)).collect();
815 let absfx: Vec<f64> = fx.iter().map(|v| v.abs()).collect();
816
817 let signdfdx: Vec<bool> = fx
822 .windows(2)
823 .map(|w| (w[1] - w[0]).is_sign_negative())
824 .collect();
825
826 let mut results = Vec::new();
827
828 for i in 0..signdfdx.len() - 1 {
829 if signdfdx[i] != signdfdx[i + 1] {
830 let refined = bisect_discr_extremum(f, xgrid[i], xgrid[i + 2]);
832 results.push(refined);
833 }
834 }
835
836 let sfx: Vec<bool> = fx.iter().map(|v| v.is_sign_negative()).collect();
838 if absfx[0] > absfx[1] || sfx[0] != sfx[1] {
839 results.insert(0, xgrid[0]);
840 }
841
842 let n = fx.len();
844 if absfx[n - 1] > absfx[n - 2] || sfx[n - 1] != sfx[n - 2] {
845 results.push(xgrid[n - 1]);
846 }
847
848 results
849}
850
851fn symmetrize_matsubara_inplace(xs: &mut Vec<i64>) {
853 if xs.is_empty() {
854 return;
855 }
856
857 xs.retain(|&x| x != 0);
859
860 let positives: Vec<i64> = xs.iter().filter(|&&x| x > 0).copied().collect();
862 let mut negatives: Vec<i64> = positives.iter().map(|&x| -x).collect();
863
864 xs.append(&mut negatives);
865 xs.sort();
866 xs.dedup();
867}
868
869#[cfg(test)]
870#[path = "polyfourier_tests.rs"]
871mod polyfourier_tests;