1use crate::{SPIR_STATISTICS_BOSONIC, SPIR_STATISTICS_FERMIONIC};
7use mdarray::{DynRank, Slice, ViewMut};
8use num_complex::Complex;
9use sparse_ir::basis::FiniteTempBasis;
10use sparse_ir::fitters::InplaceFitter;
11use sparse_ir::freq::MatsubaraFreq;
12use sparse_ir::gemm::GemmBackendHandle;
13use sparse_ir::kernel::{AbstractKernel, CentrosymmKernel, LogisticKernel, RegularizedBoseKernel};
14use sparse_ir::poly::PiecewiseLegendrePolyVector;
15use sparse_ir::polyfourier::PiecewiseLegendreFTVector;
16use sparse_ir::sve::SVEResult;
17use sparse_ir::taufuncs::normalize_tau;
18use sparse_ir::traits::Statistics;
19use sparse_ir::{Bosonic, Fermionic};
20use std::sync::Arc;
21
22#[inline]
24#[allow(dead_code)]
25pub(crate) fn statistics_to_c(stats: Statistics) -> i32 {
26 match stats {
27 Statistics::Fermionic => SPIR_STATISTICS_FERMIONIC,
28 Statistics::Bosonic => SPIR_STATISTICS_BOSONIC,
29 }
30}
31
32#[inline]
34#[allow(dead_code)]
35pub(crate) fn statistics_from_c(value: i32) -> Result<Statistics, i32> {
36 match value {
37 SPIR_STATISTICS_FERMIONIC => Ok(Statistics::Fermionic),
38 SPIR_STATISTICS_BOSONIC => Ok(Statistics::Bosonic),
39 _ => Err(value),
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub(crate) enum FunctionDomain {
46 Tau(Statistics),
48 Omega,
50}
51
52impl FunctionDomain {
53 #[allow(dead_code)]
55 pub(crate) fn is_tau_with_statistics(&self, stats: Statistics) -> bool {
56 matches!(self, FunctionDomain::Tau(s) if *s == stats)
57 }
58
59 #[allow(dead_code)]
61 pub(crate) fn is_omega(&self) -> bool {
62 matches!(self, FunctionDomain::Omega)
63 }
64}
65
66#[repr(C)]
74pub struct spir_kernel {
75 pub(crate) _private: *const std::ffi::c_void,
76}
77
78#[repr(C)]
85pub struct spir_sve_result {
86 pub(crate) _private: *const std::ffi::c_void,
87}
88
89#[repr(C)]
96pub struct spir_basis {
97 pub(crate) _private: *const std::ffi::c_void,
98}
99
100#[derive(Clone)]
102pub(crate) enum BasisType {
103 LogisticFermionic(Arc<FiniteTempBasis<LogisticKernel, Fermionic>>),
104 LogisticBosonic(Arc<FiniteTempBasis<LogisticKernel, Bosonic>>),
105 RegularizedBoseFermionic(Arc<FiniteTempBasis<RegularizedBoseKernel, Fermionic>>),
106 RegularizedBoseBosonic(Arc<FiniteTempBasis<RegularizedBoseKernel, Bosonic>>),
107 DLRFermionic(Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Fermionic>>),
110 DLRBosonic(Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Bosonic>>),
111}
112
113#[derive(Clone)]
115pub(crate) enum KernelType {
116 Logistic(Arc<LogisticKernel>),
117 RegularizedBose(Arc<RegularizedBoseKernel>),
118}
119
120impl spir_kernel {
121 pub(crate) fn inner(&self) -> &KernelType {
123 unsafe { &*(self._private as *const KernelType) }
124 }
125
126 pub(crate) fn new_logistic(lambda: f64) -> Self {
127 let inner = KernelType::Logistic(Arc::new(LogisticKernel::new(lambda)));
128 Self {
129 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
130 }
131 }
132
133 pub(crate) fn new_regularized_bose(lambda: f64) -> Self {
134 let inner = KernelType::RegularizedBose(Arc::new(RegularizedBoseKernel::new(lambda)));
135 Self {
136 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
137 }
138 }
139
140 pub(crate) fn lambda(&self) -> f64 {
141 match self.inner() {
142 KernelType::Logistic(k) => k.lambda(),
143 KernelType::RegularizedBose(k) => k.lambda(),
144 }
145 }
146
147 pub(crate) fn compute(&self, x: f64, y: f64) -> f64 {
148 match self.inner() {
149 KernelType::Logistic(k) => k.compute(x, y),
150 KernelType::RegularizedBose(k) => k.compute(x, y),
151 }
152 }
153
154 pub(crate) fn as_logistic(&self) -> Option<&Arc<LogisticKernel>> {
156 match self.inner() {
157 KernelType::Logistic(k) => Some(k),
158 _ => None,
159 }
160 }
161
162 pub(crate) fn as_regularized_bose(&self) -> Option<&Arc<RegularizedBoseKernel>> {
163 match self.inner() {
164 KernelType::RegularizedBose(k) => Some(k),
165 _ => None,
166 }
167 }
168
169 pub(crate) fn domain(&self) -> (f64, f64, f64, f64) {
171 (-1.0, 1.0, -1.0, 1.0)
173 }
174}
175
176impl Clone for spir_kernel {
177 fn clone(&self) -> Self {
178 let inner = self.inner().clone();
180 Self {
181 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
182 }
183 }
184}
185
186impl Drop for spir_kernel {
187 fn drop(&mut self) {
188 unsafe {
189 if !self._private.is_null() {
190 let _ = Box::from_raw(self._private as *const KernelType as *mut KernelType);
191 }
192 }
193 }
194}
195
196impl spir_sve_result {
197 fn inner_arc(&self) -> &Arc<SVEResult> {
199 unsafe { &*(self._private as *const Arc<SVEResult>) }
200 }
201
202 pub(crate) fn new(sve_result: SVEResult) -> Self {
203 let inner = Arc::new(sve_result);
204 Self {
205 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
206 }
207 }
208
209 pub(crate) fn size(&self) -> usize {
210 self.inner_arc().s.len()
211 }
212
213 pub(crate) fn svals(&self) -> &[f64] {
214 &self.inner_arc().s
215 }
216
217 #[allow(dead_code)]
218 pub(crate) fn epsilon(&self) -> f64 {
219 self.inner_arc().epsilon
220 }
221
222 #[allow(dead_code)]
223 pub(crate) fn truncate(&self, epsilon: f64, max_size: Option<usize>) -> Self {
224 let (u_part, s_part, v_part) = self.inner_arc().part(Some(epsilon), max_size);
225 let truncated = SVEResult::new(u_part, s_part, v_part, epsilon);
226 Self::new(truncated)
227 }
228
229 pub(crate) fn inner(&self) -> &Arc<SVEResult> {
231 self.inner_arc()
232 }
233}
234
235impl Clone for spir_sve_result {
236 fn clone(&self) -> Self {
237 let inner = self.inner_arc().clone();
239 Self {
240 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
241 }
242 }
243}
244
245impl Drop for spir_sve_result {
246 fn drop(&mut self) {
247 unsafe {
248 if !self._private.is_null() {
249 let _ =
250 Box::from_raw(self._private as *const Arc<SVEResult> as *mut Arc<SVEResult>);
251 }
252 }
253 }
254}
255
256impl spir_basis {
257 pub(crate) fn inner(&self) -> &BasisType {
259 unsafe { &*(self._private as *const BasisType) }
260 }
261
262 fn inner_type(&self) -> &BasisType {
263 self.inner()
264 }
265
266 pub(crate) fn new_logistic_fermionic(
267 basis: FiniteTempBasis<LogisticKernel, Fermionic>,
268 ) -> Self {
269 let inner = BasisType::LogisticFermionic(Arc::new(basis));
270 Self {
271 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
272 }
273 }
274
275 pub(crate) fn new_logistic_bosonic(basis: FiniteTempBasis<LogisticKernel, Bosonic>) -> Self {
276 let inner = BasisType::LogisticBosonic(Arc::new(basis));
277 Self {
278 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
279 }
280 }
281
282 pub(crate) fn new_regularized_bose_fermionic(
283 basis: FiniteTempBasis<RegularizedBoseKernel, Fermionic>,
284 ) -> Self {
285 let inner = BasisType::RegularizedBoseFermionic(Arc::new(basis));
286 Self {
287 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
288 }
289 }
290
291 pub(crate) fn new_regularized_bose_bosonic(
292 basis: FiniteTempBasis<RegularizedBoseKernel, Bosonic>,
293 ) -> Self {
294 let inner = BasisType::RegularizedBoseBosonic(Arc::new(basis));
295 Self {
296 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
297 }
298 }
299
300 pub(crate) fn new_dlr_fermionic(
301 dlr: Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Fermionic>>,
302 ) -> Self {
303 let inner = BasisType::DLRFermionic(dlr);
304 Self {
305 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
306 }
307 }
308
309 pub(crate) fn new_dlr_bosonic(
310 dlr: Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Bosonic>>,
311 ) -> Self {
312 let inner = BasisType::DLRBosonic(dlr);
313 Self {
314 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
315 }
316 }
317
318 pub(crate) fn size(&self) -> usize {
319 match self.inner_type() {
320 BasisType::LogisticFermionic(b) => b.size(),
321 BasisType::LogisticBosonic(b) => b.size(),
322 BasisType::RegularizedBoseFermionic(b) => b.size(),
323 BasisType::RegularizedBoseBosonic(b) => b.size(),
324 BasisType::DLRFermionic(dlr) => dlr.poles.len(),
325 BasisType::DLRBosonic(dlr) => dlr.poles.len(),
326 }
327 }
328
329 pub(crate) fn svals(&self) -> Vec<f64> {
330 match self.inner_type() {
331 BasisType::LogisticFermionic(b) => b.s().to_vec(),
332 BasisType::LogisticBosonic(b) => b.s().to_vec(),
333 BasisType::RegularizedBoseFermionic(b) => b.s().to_vec(),
334 BasisType::RegularizedBoseBosonic(b) => b.s().to_vec(),
335 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
337 }
338 }
339
340 pub(crate) fn statistics(&self) -> i32 {
341 match self.inner_type() {
343 BasisType::LogisticFermionic(_) => 1,
344 BasisType::LogisticBosonic(_) => 0,
345 BasisType::RegularizedBoseFermionic(_) => 1,
346 BasisType::RegularizedBoseBosonic(_) => 0,
347 BasisType::DLRFermionic(_) => 1,
348 BasisType::DLRBosonic(_) => 0,
349 }
350 }
351
352 pub(crate) fn beta(&self) -> f64 {
353 match self.inner_type() {
354 BasisType::LogisticFermionic(b) => b.beta(),
355 BasisType::LogisticBosonic(b) => b.beta(),
356 BasisType::RegularizedBoseFermionic(b) => b.beta(),
357 BasisType::RegularizedBoseBosonic(b) => b.beta(),
358 BasisType::DLRFermionic(dlr) => dlr.beta,
359 BasisType::DLRBosonic(dlr) => dlr.beta,
360 }
361 }
362
363 #[allow(dead_code)]
364 pub(crate) fn wmax(&self) -> f64 {
365 match self.inner_type() {
366 BasisType::LogisticFermionic(b) => b.wmax(),
367 BasisType::LogisticBosonic(b) => b.wmax(),
368 BasisType::RegularizedBoseFermionic(b) => b.wmax(),
369 BasisType::RegularizedBoseBosonic(b) => b.wmax(),
370 BasisType::DLRFermionic(dlr) => dlr.wmax,
371 BasisType::DLRBosonic(dlr) => dlr.wmax,
372 }
373 }
374
375 pub(crate) fn default_tau_sampling_points(&self) -> Vec<f64> {
376 match self.inner_type() {
377 BasisType::LogisticFermionic(b) => b.default_tau_sampling_points(),
378 BasisType::LogisticBosonic(b) => b.default_tau_sampling_points(),
379 BasisType::RegularizedBoseFermionic(b) => b.default_tau_sampling_points(),
380 BasisType::RegularizedBoseBosonic(b) => b.default_tau_sampling_points(),
381 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
383 }
384 }
385
386 pub(crate) fn default_tau_sampling_points_size_requested(
387 &self,
388 size_requested: usize,
389 ) -> Vec<f64> {
390 match self.inner_type() {
391 BasisType::LogisticFermionic(b) => {
392 b.default_tau_sampling_points_size_requested(size_requested)
393 }
394 BasisType::LogisticBosonic(b) => {
395 b.default_tau_sampling_points_size_requested(size_requested)
396 }
397 BasisType::RegularizedBoseFermionic(b) => {
398 b.default_tau_sampling_points_size_requested(size_requested)
399 }
400 BasisType::RegularizedBoseBosonic(b) => {
401 b.default_tau_sampling_points_size_requested(size_requested)
402 }
403 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
405 }
406 }
407
408 pub(crate) fn default_matsubara_sampling_points(&self, positive_only: bool) -> Vec<i64> {
409 match self.inner_type() {
410 BasisType::LogisticFermionic(b) => {
411 b.default_matsubara_sampling_points_i64(positive_only)
412 }
413 BasisType::LogisticBosonic(b) => b.default_matsubara_sampling_points_i64(positive_only),
414 BasisType::RegularizedBoseFermionic(b) => {
415 b.default_matsubara_sampling_points_i64(positive_only)
416 }
417 BasisType::RegularizedBoseBosonic(b) => {
418 b.default_matsubara_sampling_points_i64(positive_only)
419 }
420 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
422 }
423 }
424
425 pub(crate) fn default_matsubara_sampling_points_with_mitigate(
426 &self,
427 positive_only: bool,
428 mitigate: bool,
429 n_points: usize,
430 ) -> Vec<i64> {
431 match self.inner_type() {
432 BasisType::LogisticFermionic(b) => b
433 .default_matsubara_sampling_points_i64_with_mitigate(
434 positive_only,
435 mitigate,
436 n_points,
437 ),
438 BasisType::LogisticBosonic(b) => b.default_matsubara_sampling_points_i64_with_mitigate(
439 positive_only,
440 mitigate,
441 n_points,
442 ),
443 BasisType::RegularizedBoseFermionic(b) => b
444 .default_matsubara_sampling_points_i64_with_mitigate(
445 positive_only,
446 mitigate,
447 n_points,
448 ),
449 BasisType::RegularizedBoseBosonic(b) => b
450 .default_matsubara_sampling_points_i64_with_mitigate(
451 positive_only,
452 mitigate,
453 n_points,
454 ),
455 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
457 }
458 }
459
460 pub(crate) fn default_omega_sampling_points(&self) -> Vec<f64> {
461 match self.inner_type() {
462 BasisType::LogisticFermionic(b) => b.default_omega_sampling_points(),
463 BasisType::LogisticBosonic(b) => b.default_omega_sampling_points(),
464 BasisType::RegularizedBoseFermionic(b) => b.default_omega_sampling_points(),
465 BasisType::RegularizedBoseBosonic(b) => b.default_omega_sampling_points(),
466 BasisType::DLRFermionic(dlr) => dlr.poles.clone(),
468 BasisType::DLRBosonic(dlr) => dlr.poles.clone(),
469 }
470 }
471}
472
473impl Clone for spir_basis {
474 fn clone(&self) -> Self {
475 let inner = self.inner_type().clone();
477 Self {
478 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
479 }
480 }
481}
482
483impl Drop for spir_basis {
484 fn drop(&mut self) {
485 unsafe {
486 if !self._private.is_null() {
487 let _ = Box::from_raw(self._private as *const BasisType as *mut BasisType);
488 }
489 }
490 }
491}
492
493#[derive(Clone)]
499pub(crate) struct PolyVectorFuncs {
500 pub poly: Arc<PiecewiseLegendrePolyVector>,
501 pub domain: FunctionDomain,
502}
503
504impl PolyVectorFuncs {
505 pub fn evaluate_at(&self, x: f64, beta: f64) -> Vec<f64> {
507 let (x_reg, sign) = match self.domain {
509 FunctionDomain::Tau(Statistics::Fermionic) => {
510 normalize_tau::<Fermionic>(x, beta)
512 }
513 FunctionDomain::Tau(Statistics::Bosonic) => {
514 normalize_tau::<Bosonic>(x, beta)
516 }
517 FunctionDomain::Omega => {
518 (x, 1.0)
520 }
521 };
522
523 self.poly
525 .polyvec
526 .iter()
527 .map(|p| sign * p.evaluate(x_reg))
528 .collect()
529 }
530
531 pub fn batch_evaluate_at(&self, xs: &[f64], beta: f64) -> Vec<Vec<f64>> {
534 let n_funcs = self.poly.polyvec.len();
535 let n_points = xs.len();
536 let mut result = vec![vec![0.0; n_points]; n_funcs];
537
538 let normalized: Vec<(f64, f64)> = xs
540 .iter()
541 .map(|&x| match self.domain {
542 FunctionDomain::Tau(Statistics::Fermionic) => normalize_tau::<Fermionic>(x, beta),
543 FunctionDomain::Tau(Statistics::Bosonic) => normalize_tau::<Bosonic>(x, beta),
544 FunctionDomain::Omega => (x, 1.0),
545 })
546 .collect();
547
548 let xs_reg: Vec<f64> = normalized.iter().map(|(x, _)| *x).collect();
550 let signs: Vec<f64> = normalized.iter().map(|(_, s)| *s).collect();
551
552 for (i, p) in self.poly.polyvec.iter().enumerate() {
554 let values = p.evaluate_many(&xs_reg);
555 for (j, &val) in values.iter().enumerate() {
556 result[i][j] = signs[j] * val;
557 }
558 }
559
560 result
561 }
562}
563
564#[derive(Clone)]
566pub(crate) struct FTVectorFuncs {
567 pub ft_fermionic: Option<Arc<PiecewiseLegendreFTVector<Fermionic>>>,
568 pub ft_bosonic: Option<Arc<PiecewiseLegendreFTVector<Bosonic>>>,
569 pub statistics: Statistics,
570}
571
572#[derive(Clone)]
574pub(crate) struct DLRTauFuncs {
575 pub poles: Vec<f64>,
576 pub beta: f64,
577 pub wmax: f64,
578 pub pole_weights: Vec<f64>,
579 pub kernel_ypower: i32,
580 pub statistics: Statistics,
581}
582
583impl DLRTauFuncs {
584 fn zero_pole_tau_limit(&self) -> f64 {
585 match self.kernel_ypower {
586 0 => -0.5,
587 1 => -1.0 / (self.beta * self.wmax * self.wmax),
588 _ => panic!(
589 "DLR tau evaluation does not support kernel ypower = {}",
590 self.kernel_ypower
591 ),
592 }
593 }
594
595 fn evaluate_single(&self, tau: f64, pole: f64, pole_weight: f64) -> f64 {
596 match self.statistics {
597 Statistics::Fermionic => {
598 let (tau_reg, sign) = normalize_tau::<Fermionic>(tau, self.beta);
599 let value = if pole >= 0.0 {
600 -(-pole * tau_reg).exp() / (1.0 + (-self.beta * pole).exp())
601 } else {
602 -(pole * (self.beta - tau_reg)).exp() / (1.0 + (self.beta * pole).exp())
603 };
604 sign * value * pole_weight
605 }
606 Statistics::Bosonic => {
607 let (tau_reg, sign) = normalize_tau::<Bosonic>(tau, self.beta);
608 if pole == 0.0 {
609 sign * self.zero_pole_tau_limit()
610 } else if pole > 0.0 {
611 let denominator = -(-self.beta * pole).exp_m1();
612 sign * (-(-tau_reg * pole).exp() * pole_weight / denominator)
613 } else {
614 let denominator = -(self.beta * pole).exp_m1();
615 sign * ((pole * (self.beta - tau_reg)).exp() * pole_weight / denominator)
616 }
617 }
618 }
619 }
620
621 pub fn evaluate_at(&self, tau: f64) -> Vec<f64> {
623 self.poles
624 .iter()
625 .zip(self.pole_weights.iter())
626 .map(|(&pole, &pole_weight)| self.evaluate_single(tau, pole, pole_weight))
627 .collect()
628 }
629
630 pub fn batch_evaluate_at(&self, taus: &[f64]) -> Vec<Vec<f64>> {
633 let n_funcs = self.poles.len();
634 let n_points = taus.len();
635 let mut result = vec![vec![0.0; n_points]; n_funcs];
636
637 for (j, &tau) in taus.iter().enumerate() {
639 for (i, (&pole, &pole_weight)) in
640 self.poles.iter().zip(self.pole_weights.iter()).enumerate()
641 {
642 result[i][j] = self.evaluate_single(tau, pole, pole_weight);
643 }
644 }
645
646 result
647 }
648}
649
650#[derive(Clone)]
652pub(crate) struct DLRMatsubaraFuncs {
653 pub poles: Vec<f64>,
654 pub beta: f64,
655 pub wmax: f64,
656 pub pole_weights: Vec<f64>,
657 pub kernel_ypower: i32,
658 pub statistics: Statistics,
659}
660
661impl DLRMatsubaraFuncs {
662 fn zero_pole_matsubara_limit(&self) -> f64 {
663 match self.kernel_ypower {
664 0 => -0.5 * self.beta,
665 1 => -1.0 / (self.wmax * self.wmax),
666 _ => panic!(
667 "DLR Matsubara evaluation does not support kernel ypower = {}",
668 self.kernel_ypower
669 ),
670 }
671 }
672}
673
674#[derive(Clone)]
680pub(crate) enum FuncsType {
681 PolyVector(PolyVectorFuncs),
683
684 FTVector(FTVectorFuncs),
686
687 DLRTau(DLRTauFuncs),
689
690 DLRMatsubara(DLRMatsubaraFuncs),
692}
693
694#[repr(C)]
703pub struct spir_funcs {
704 pub(crate) _private: *const std::ffi::c_void,
705 pub(crate) beta: f64,
706}
707
708impl spir_funcs {
709 pub(crate) fn inner_type(&self) -> &FuncsType {
711 unsafe { &*(self._private as *const FuncsType) }
712 }
713
714 pub(crate) fn from_u_fermionic(poly: Arc<PiecewiseLegendrePolyVector>, beta: f64) -> Self {
716 let inner = FuncsType::PolyVector(PolyVectorFuncs {
717 poly,
718 domain: FunctionDomain::Tau(Statistics::Fermionic),
719 });
720 Self {
721 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
722 beta,
723 }
724 }
725
726 pub(crate) fn from_u_bosonic(poly: Arc<PiecewiseLegendrePolyVector>, beta: f64) -> Self {
728 let inner = FuncsType::PolyVector(PolyVectorFuncs {
729 poly,
730 domain: FunctionDomain::Tau(Statistics::Bosonic),
731 });
732 Self {
733 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
734 beta,
735 }
736 }
737
738 pub(crate) fn from_v(poly: Arc<PiecewiseLegendrePolyVector>, beta: f64) -> Self {
740 let inner = FuncsType::PolyVector(PolyVectorFuncs {
741 poly,
742 domain: FunctionDomain::Omega,
743 });
744 Self {
745 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
746 beta,
747 }
748 }
749
750 pub(crate) fn from_uhat_fermionic(
752 ft: Arc<PiecewiseLegendreFTVector<Fermionic>>,
753 beta: f64,
754 ) -> Self {
755 let inner = FuncsType::FTVector(FTVectorFuncs {
756 ft_fermionic: Some(ft),
757 ft_bosonic: None,
758 statistics: Statistics::Fermionic,
759 });
760 Self {
761 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
762 beta,
763 }
764 }
765
766 pub(crate) fn from_uhat_bosonic(
768 ft: Arc<PiecewiseLegendreFTVector<Bosonic>>,
769 beta: f64,
770 ) -> Self {
771 let inner = FuncsType::FTVector(FTVectorFuncs {
772 ft_fermionic: None,
773 ft_bosonic: Some(ft),
774 statistics: Statistics::Bosonic,
775 });
776 Self {
777 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
778 beta,
779 }
780 }
781
782 pub(crate) fn from_uhat_full_fermionic(
788 ft: Arc<PiecewiseLegendreFTVector<Fermionic>>,
789 beta: f64,
790 ) -> Self {
791 let inner = FuncsType::FTVector(FTVectorFuncs {
792 ft_fermionic: Some(ft),
793 ft_bosonic: None,
794 statistics: Statistics::Fermionic,
795 });
796 Self {
797 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
798 beta,
799 }
800 }
801
802 pub(crate) fn from_uhat_full_bosonic(
808 ft: Arc<PiecewiseLegendreFTVector<Bosonic>>,
809 beta: f64,
810 ) -> Self {
811 let inner = FuncsType::FTVector(FTVectorFuncs {
812 ft_fermionic: None,
813 ft_bosonic: Some(ft),
814 statistics: Statistics::Bosonic,
815 });
816 Self {
817 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
818 beta,
819 }
820 }
821
822 pub(crate) fn from_dlr_tau_fermionic(
825 poles: Vec<f64>,
826 beta: f64,
827 wmax: f64,
828 pole_weights: Vec<f64>,
829 kernel_ypower: i32,
830 ) -> Self {
831 let inner = FuncsType::DLRTau(DLRTauFuncs {
832 poles,
833 beta,
834 wmax,
835 pole_weights,
836 kernel_ypower,
837 statistics: Statistics::Fermionic,
838 });
839 Self {
840 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
841 beta,
842 }
843 }
844
845 pub(crate) fn from_dlr_tau_bosonic(
848 poles: Vec<f64>,
849 beta: f64,
850 wmax: f64,
851 pole_weights: Vec<f64>,
852 kernel_ypower: i32,
853 ) -> Self {
854 let inner = FuncsType::DLRTau(DLRTauFuncs {
855 poles,
856 beta,
857 wmax,
858 pole_weights,
859 kernel_ypower,
860 statistics: Statistics::Bosonic,
861 });
862 Self {
863 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
864 beta,
865 }
866 }
867
868 pub(crate) fn from_dlr_matsubara_fermionic(
870 poles: Vec<f64>,
871 beta: f64,
872 wmax: f64,
873 pole_weights: Vec<f64>,
874 kernel_ypower: i32,
875 ) -> Self {
876 let inner = FuncsType::DLRMatsubara(DLRMatsubaraFuncs {
877 poles,
878 beta,
879 wmax,
880 pole_weights,
881 kernel_ypower,
882 statistics: Statistics::Fermionic,
883 });
884 Self {
885 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
886 beta,
887 }
888 }
889
890 pub(crate) fn from_dlr_matsubara_bosonic(
892 poles: Vec<f64>,
893 beta: f64,
894 wmax: f64,
895 pole_weights: Vec<f64>,
896 kernel_ypower: i32,
897 ) -> Self {
898 let inner = FuncsType::DLRMatsubara(DLRMatsubaraFuncs {
899 poles,
900 beta,
901 wmax,
902 pole_weights,
903 kernel_ypower,
904 statistics: Statistics::Bosonic,
905 });
906 Self {
907 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
908 beta,
909 }
910 }
911
912 pub(crate) fn size(&self) -> usize {
914 match self.inner_type() {
915 FuncsType::PolyVector(pv) => pv.poly.polyvec.len(),
916 FuncsType::FTVector(ftv) => {
917 if let Some(ft) = &ftv.ft_fermionic {
918 ft.polyvec.len()
919 } else if let Some(ft) = &ftv.ft_bosonic {
920 ft.polyvec.len()
921 } else {
922 0
923 }
924 }
925 FuncsType::DLRTau(dlr) => dlr.poles.len(),
926 FuncsType::DLRMatsubara(dlr) => dlr.poles.len(),
927 }
928 }
929
930 pub(crate) fn knots(&self) -> Option<Vec<f64>> {
932 match self.inner_type() {
933 FuncsType::PolyVector(pv) => {
934 let mut all_knots = Vec::new();
936 for p in &pv.poly.polyvec {
937 for &knot in &p.knots {
938 if !all_knots.iter().any(|&k: &f64| (k - knot).abs() < 1e-14) {
939 all_knots.push(knot);
940 }
941 }
942 }
943 all_knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
944 Some(all_knots)
945 }
946 _ => None, }
948 }
949
950 pub(crate) fn eval_continuous(&self, x: f64) -> Option<Vec<f64>> {
958 match self.inner_type() {
959 FuncsType::PolyVector(pv) => Some(pv.evaluate_at(x, self.beta)),
960 FuncsType::DLRTau(dlr) => Some(dlr.evaluate_at(x)),
961 _ => None,
962 }
963 }
964
965 pub(crate) fn eval_matsubara(&self, n: i64) -> Option<Vec<num_complex::Complex64>> {
973 match self.inner_type() {
974 FuncsType::FTVector(ftv) => {
975 if ftv.statistics == Statistics::Fermionic {
976 let ft = ftv.ft_fermionic.as_ref()?;
978 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
979 let mut result = Vec::with_capacity(ft.polyvec.len());
980 for p in &ft.polyvec {
981 result.push(p.evaluate(&freq));
982 }
983 Some(result)
984 } else {
985 let ft = ftv.ft_bosonic.as_ref()?;
987 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
988 let mut result = Vec::with_capacity(ft.polyvec.len());
989 for p in &ft.polyvec {
990 result.push(p.evaluate(&freq));
991 }
992 Some(result)
993 }
994 }
995 FuncsType::DLRMatsubara(dlr) => {
996 use num_complex::Complex;
998
999 let mut result = Vec::with_capacity(dlr.poles.len());
1000 if dlr.statistics == Statistics::Fermionic {
1001 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
1002 let iv = freq.value_imaginary(dlr.beta);
1003 for (i, &pole) in dlr.poles.iter().enumerate() {
1004 let pole_weight = dlr.pole_weights[i];
1005 result
1006 .push(Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0)));
1007 }
1008 } else {
1009 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
1010 let iv = freq.value_imaginary(dlr.beta);
1011 for (i, &pole) in dlr.poles.iter().enumerate() {
1012 if pole == 0.0 {
1013 if freq.n() == 0 {
1014 result.push(Complex::new(dlr.zero_pole_matsubara_limit(), 0.0));
1015 } else {
1016 result.push(Complex::new(0.0, 0.0));
1017 }
1018 } else {
1019 let pole_weight = dlr.pole_weights[i];
1020 result.push(
1021 Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0)),
1022 );
1023 }
1024 }
1025 }
1026 Some(result)
1027 }
1028 _ => None,
1029 }
1030 }
1031
1032 pub(crate) fn batch_eval_continuous(&self, xs: &[f64]) -> Option<Vec<Vec<f64>>> {
1034 match self.inner_type() {
1035 FuncsType::PolyVector(pv) => Some(pv.batch_evaluate_at(xs, self.beta)),
1036 FuncsType::DLRTau(dlr) => Some(dlr.batch_evaluate_at(xs)),
1037 _ => None,
1038 }
1039 }
1040
1041 pub(crate) fn batch_eval_matsubara(
1049 &self,
1050 ns: &[i64],
1051 ) -> Option<Vec<Vec<num_complex::Complex64>>> {
1052 match self.inner_type() {
1053 FuncsType::FTVector(ftv) => {
1054 if ftv.statistics == Statistics::Fermionic {
1055 let ft = ftv.ft_fermionic.as_ref()?;
1057 let n_funcs = ft.polyvec.len();
1058 let n_points = ns.len();
1059 let mut result =
1060 vec![vec![num_complex::Complex64::new(0.0, 0.0); n_points]; n_funcs];
1061
1062 for (j, &n) in ns.iter().enumerate() {
1063 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
1064 for (i, p) in ft.polyvec.iter().enumerate() {
1065 result[i][j] = p.evaluate(&freq);
1066 }
1067 }
1068 Some(result)
1069 } else {
1070 let ft = ftv.ft_bosonic.as_ref()?;
1072 let n_funcs = ft.polyvec.len();
1073 let n_points = ns.len();
1074 let mut result =
1075 vec![vec![num_complex::Complex64::new(0.0, 0.0); n_points]; n_funcs];
1076
1077 for (j, &n) in ns.iter().enumerate() {
1078 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
1079 for (i, p) in ft.polyvec.iter().enumerate() {
1080 result[i][j] = p.evaluate(&freq);
1081 }
1082 }
1083 Some(result)
1084 }
1085 }
1086 FuncsType::DLRMatsubara(dlr) => {
1087 use num_complex::Complex;
1089
1090 let n_funcs = dlr.poles.len();
1091 let n_points = ns.len();
1092 let mut result = vec![vec![Complex::new(0.0, 0.0); n_points]; n_funcs];
1093
1094 for (j, &n) in ns.iter().enumerate() {
1095 if dlr.statistics == Statistics::Fermionic {
1096 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
1097 let iv = freq.value_imaginary(dlr.beta);
1098 for (i, &pole) in dlr.poles.iter().enumerate() {
1099 let pole_weight = dlr.pole_weights[i];
1100 result[i][j] =
1101 Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0));
1102 }
1103 } else {
1104 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
1105 let iv = freq.value_imaginary(dlr.beta);
1106 for (i, &pole) in dlr.poles.iter().enumerate() {
1107 if pole == 0.0 {
1108 if freq.n() == 0 {
1109 result[i][j] =
1110 Complex::new(dlr.zero_pole_matsubara_limit(), 0.0);
1111 } else {
1112 result[i][j] = Complex::new(0.0, 0.0);
1113 }
1114 } else {
1115 let pole_weight = dlr.pole_weights[i];
1116 result[i][j] =
1117 Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0));
1118 }
1119 }
1120 }
1121 }
1122
1123 Some(result)
1124 }
1125 FuncsType::DLRTau(_) => {
1126 None
1128 }
1129 _ => None,
1130 }
1131 }
1132
1133 pub(crate) fn get_slice(&self, indices: &[usize]) -> Option<Self> {
1141 match self.inner_type() {
1142 FuncsType::PolyVector(pv) => {
1143 let mut new_polys = Vec::with_capacity(indices.len());
1144 for &idx in indices {
1145 if idx >= pv.poly.polyvec.len() {
1146 return None;
1147 }
1148 new_polys.push(pv.poly.polyvec[idx].clone());
1149 }
1150 let new_poly_vec = PiecewiseLegendrePolyVector::new(new_polys);
1151 Some(Self {
1152 _private: Box::into_raw(Box::new(FuncsType::PolyVector(PolyVectorFuncs {
1153 poly: Arc::new(new_poly_vec),
1154 domain: pv.domain,
1155 }))) as *mut std::ffi::c_void,
1156 beta: self.beta,
1157 })
1158 }
1159 FuncsType::FTVector(ftv) => {
1160 if ftv.statistics == Statistics::Fermionic {
1162 let ft = ftv.ft_fermionic.as_ref()?;
1163 let mut new_polyvec = Vec::with_capacity(indices.len());
1164 for &idx in indices {
1165 if idx >= ft.polyvec.len() {
1166 return None;
1167 }
1168 new_polyvec.push(ft.polyvec[idx].clone());
1169 }
1170 let new_ft_vector =
1171 Arc::new(PiecewiseLegendreFTVector::from_vector(new_polyvec));
1172 Some(Self {
1173 _private: Box::into_raw(Box::new(FuncsType::FTVector(FTVectorFuncs {
1174 ft_fermionic: Some(new_ft_vector),
1175 ft_bosonic: None,
1176 statistics: ftv.statistics,
1177 }))) as *mut std::ffi::c_void,
1178 beta: self.beta,
1179 })
1180 } else {
1181 let ft = ftv.ft_bosonic.as_ref()?;
1182 let mut new_polyvec = Vec::with_capacity(indices.len());
1183 for &idx in indices {
1184 if idx >= ft.polyvec.len() {
1185 return None;
1186 }
1187 new_polyvec.push(ft.polyvec[idx].clone());
1188 }
1189 let new_ft_vector =
1190 Arc::new(PiecewiseLegendreFTVector::from_vector(new_polyvec));
1191 Some(Self {
1192 _private: Box::into_raw(Box::new(FuncsType::FTVector(FTVectorFuncs {
1193 ft_fermionic: None,
1194 ft_bosonic: Some(new_ft_vector),
1195 statistics: ftv.statistics,
1196 }))) as *mut std::ffi::c_void,
1197 beta: self.beta,
1198 })
1199 }
1200 }
1201 FuncsType::DLRTau(dlr) => {
1202 let mut new_poles = Vec::with_capacity(indices.len());
1204 let mut new_pole_weights = Vec::with_capacity(indices.len());
1205 for &idx in indices {
1206 if idx >= dlr.poles.len() {
1207 return None;
1208 }
1209 new_poles.push(dlr.poles[idx]);
1210 new_pole_weights.push(dlr.pole_weights[idx]);
1211 }
1212 Some(Self {
1213 _private: Box::into_raw(Box::new(FuncsType::DLRTau(DLRTauFuncs {
1214 poles: new_poles,
1215 beta: dlr.beta,
1216 wmax: dlr.wmax,
1217 pole_weights: new_pole_weights,
1218 kernel_ypower: dlr.kernel_ypower,
1219 statistics: dlr.statistics,
1220 }))) as *mut std::ffi::c_void,
1221 beta: dlr.beta,
1222 })
1223 }
1224 FuncsType::DLRMatsubara(dlr) => {
1225 let mut new_poles = Vec::with_capacity(indices.len());
1227 let mut new_pole_weights = Vec::with_capacity(indices.len());
1228 for &idx in indices {
1229 if idx >= dlr.poles.len() {
1230 return None;
1231 }
1232 new_poles.push(dlr.poles[idx]);
1233 new_pole_weights.push(dlr.pole_weights[idx]);
1234 }
1235 Some(Self {
1236 _private: Box::into_raw(Box::new(FuncsType::DLRMatsubara(DLRMatsubaraFuncs {
1237 poles: new_poles,
1238 beta: dlr.beta,
1239 wmax: dlr.wmax,
1240 pole_weights: new_pole_weights,
1241 kernel_ypower: dlr.kernel_ypower,
1242 statistics: dlr.statistics,
1243 }))) as *mut std::ffi::c_void,
1244 beta: dlr.beta,
1245 })
1246 }
1247 }
1248 }
1249}
1250
1251impl Clone for spir_funcs {
1252 fn clone(&self) -> Self {
1253 let inner = self.inner_type().clone();
1255 Self {
1256 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
1257 beta: self.beta,
1258 }
1259 }
1260}
1261
1262impl Drop for spir_funcs {
1263 fn drop(&mut self) {
1264 unsafe {
1265 if !self._private.is_null() {
1266 let _ = Box::from_raw(self._private as *const FuncsType as *mut FuncsType);
1267 }
1268 }
1269 }
1270}
1271
1272#[cfg(test)]
1275mod tests {
1276
1277 #[test]
1278 fn test_funcs_creation() {
1279 }
1282}
1283#[repr(C)]
1290pub struct spir_sampling {
1291 pub(crate) _private: *const std::ffi::c_void,
1292}
1293
1294impl spir_sampling {
1295 pub(crate) fn inner(&self) -> &SamplingType {
1297 unsafe { &*(self._private as *const SamplingType) }
1298 }
1299}
1300
1301impl Clone for spir_sampling {
1302 fn clone(&self) -> Self {
1303 let inner = self.inner().clone();
1305 Self {
1306 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
1307 }
1308 }
1309}
1310
1311impl Drop for spir_sampling {
1312 fn drop(&mut self) {
1313 unsafe {
1314 if !self._private.is_null() {
1315 let _ = Box::from_raw(self._private as *const SamplingType as *mut SamplingType);
1316 }
1317 }
1318 }
1319}
1320
1321#[derive(Clone)]
1323pub(crate) enum SamplingType {
1324 TauFermionic(Arc<sparse_ir::sampling::TauSampling<Fermionic>>),
1325 TauBosonic(Arc<sparse_ir::sampling::TauSampling<Bosonic>>),
1326 MatsubaraFermionic(Arc<sparse_ir::matsubara_sampling::MatsubaraSampling<Fermionic>>),
1327 MatsubaraBosonic(Arc<sparse_ir::matsubara_sampling::MatsubaraSampling<Bosonic>>),
1328 MatsubaraPositiveOnlyFermionic(
1329 Arc<sparse_ir::matsubara_sampling::MatsubaraSamplingPositiveOnly<Fermionic>>,
1330 ),
1331 MatsubaraPositiveOnlyBosonic(
1332 Arc<sparse_ir::matsubara_sampling::MatsubaraSamplingPositiveOnly<Bosonic>>,
1333 ),
1334}
1335
1336impl InplaceFitter for SamplingType {
1341 fn n_points(&self) -> usize {
1342 match self {
1343 SamplingType::TauFermionic(s) => s.n_sampling_points(),
1344 SamplingType::TauBosonic(s) => s.n_sampling_points(),
1345 SamplingType::MatsubaraFermionic(s) => s.n_sampling_points(),
1346 SamplingType::MatsubaraBosonic(s) => s.n_sampling_points(),
1347 SamplingType::MatsubaraPositiveOnlyFermionic(s) => s.n_sampling_points(),
1348 SamplingType::MatsubaraPositiveOnlyBosonic(s) => s.n_sampling_points(),
1349 }
1350 }
1351
1352 fn basis_size(&self) -> usize {
1353 match self {
1354 SamplingType::TauFermionic(s) => s.basis_size(),
1355 SamplingType::TauBosonic(s) => s.basis_size(),
1356 SamplingType::MatsubaraFermionic(s) => s.basis_size(),
1357 SamplingType::MatsubaraBosonic(s) => s.basis_size(),
1358 SamplingType::MatsubaraPositiveOnlyFermionic(s) => s.basis_size(),
1359 SamplingType::MatsubaraPositiveOnlyBosonic(s) => s.basis_size(),
1360 }
1361 }
1362
1363 fn evaluate_nd_dd_to(
1364 &self,
1365 backend: Option<&GemmBackendHandle>,
1366 coeffs: &Slice<f64, DynRank>,
1367 dim: usize,
1368 out: &mut ViewMut<'_, f64, DynRank>,
1369 ) -> bool {
1370 match self {
1371 SamplingType::TauFermionic(s) => {
1372 InplaceFitter::evaluate_nd_dd_to(s.as_ref(), backend, coeffs, dim, out)
1373 }
1374 SamplingType::TauBosonic(s) => {
1375 InplaceFitter::evaluate_nd_dd_to(s.as_ref(), backend, coeffs, dim, out)
1376 }
1377 _ => false,
1379 }
1380 }
1381
1382 fn evaluate_nd_dz_to(
1383 &self,
1384 backend: Option<&GemmBackendHandle>,
1385 coeffs: &Slice<f64, DynRank>,
1386 dim: usize,
1387 out: &mut ViewMut<'_, Complex<f64>, DynRank>,
1388 ) -> bool {
1389 match self {
1390 SamplingType::MatsubaraFermionic(s) => {
1391 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1392 }
1393 SamplingType::MatsubaraBosonic(s) => {
1394 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1395 }
1396 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1397 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1398 }
1399 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1400 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1401 }
1402 _ => false,
1404 }
1405 }
1406
1407 fn evaluate_nd_zz_to(
1408 &self,
1409 backend: Option<&GemmBackendHandle>,
1410 coeffs: &Slice<Complex<f64>, DynRank>,
1411 dim: usize,
1412 out: &mut ViewMut<'_, Complex<f64>, DynRank>,
1413 ) -> bool {
1414 match self {
1415 SamplingType::TauFermionic(s) => {
1416 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1417 }
1418 SamplingType::TauBosonic(s) => {
1419 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1420 }
1421 SamplingType::MatsubaraFermionic(s) => {
1422 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1423 }
1424 SamplingType::MatsubaraBosonic(s) => {
1425 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1426 }
1427 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1428 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1429 }
1430 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1431 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1432 }
1433 }
1434 }
1435
1436 fn fit_nd_dd_to(
1437 &self,
1438 backend: Option<&GemmBackendHandle>,
1439 values: &Slice<f64, DynRank>,
1440 dim: usize,
1441 out: &mut ViewMut<'_, f64, DynRank>,
1442 ) -> bool {
1443 match self {
1444 SamplingType::TauFermionic(s) => {
1445 InplaceFitter::fit_nd_dd_to(s.as_ref(), backend, values, dim, out)
1446 }
1447 SamplingType::TauBosonic(s) => {
1448 InplaceFitter::fit_nd_dd_to(s.as_ref(), backend, values, dim, out)
1449 }
1450 _ => false,
1452 }
1453 }
1454
1455 fn fit_nd_zd_to(
1456 &self,
1457 backend: Option<&GemmBackendHandle>,
1458 values: &Slice<Complex<f64>, DynRank>,
1459 dim: usize,
1460 out: &mut ViewMut<'_, f64, DynRank>,
1461 ) -> bool {
1462 match self {
1463 SamplingType::MatsubaraFermionic(s) => {
1464 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1465 }
1466 SamplingType::MatsubaraBosonic(s) => {
1467 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1468 }
1469 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1470 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1471 }
1472 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1473 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1474 }
1475 _ => false,
1477 }
1478 }
1479
1480 fn fit_nd_zz_to(
1481 &self,
1482 backend: Option<&GemmBackendHandle>,
1483 values: &Slice<Complex<f64>, DynRank>,
1484 dim: usize,
1485 out: &mut ViewMut<'_, Complex<f64>, DynRank>,
1486 ) -> bool {
1487 match self {
1488 SamplingType::TauFermionic(s) => {
1489 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1490 }
1491 SamplingType::TauBosonic(s) => {
1492 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1493 }
1494 SamplingType::MatsubaraFermionic(s) => {
1495 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1496 }
1497 SamplingType::MatsubaraBosonic(s) => {
1498 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1499 }
1500 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1501 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1502 }
1503 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1504 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1505 }
1506 }
1507 }
1508}
1509
1510#[cfg(test)]
1511mod sampling_tests {
1512
1513 #[test]
1514 fn test_sampling_creation() {
1515 }
1518}
1519