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 #[allow(dead_code)]
108 RegularizedBoseFermionic(Arc<FiniteTempBasis<RegularizedBoseKernel, Fermionic>>),
109 RegularizedBoseBosonic(Arc<FiniteTempBasis<RegularizedBoseKernel, Bosonic>>),
110 DLRFermionic(Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Fermionic>>),
113 DLRBosonic(Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Bosonic>>),
114}
115
116#[derive(Clone)]
118pub(crate) enum KernelType {
119 Logistic(Arc<LogisticKernel>),
120 RegularizedBose(Arc<RegularizedBoseKernel>),
121}
122
123impl spir_kernel {
124 pub(crate) fn inner(&self) -> &KernelType {
126 unsafe { &*(self._private as *const KernelType) }
127 }
128
129 pub(crate) fn new_logistic(lambda: f64) -> Self {
130 let inner = KernelType::Logistic(Arc::new(LogisticKernel::new(lambda)));
131 Self {
132 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
133 }
134 }
135
136 pub(crate) fn new_regularized_bose(lambda: f64) -> Self {
137 let inner = KernelType::RegularizedBose(Arc::new(RegularizedBoseKernel::new(lambda)));
138 Self {
139 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
140 }
141 }
142
143 pub(crate) fn lambda(&self) -> f64 {
144 match self.inner() {
145 KernelType::Logistic(k) => k.lambda(),
146 KernelType::RegularizedBose(k) => k.lambda(),
147 }
148 }
149
150 pub(crate) fn compute(&self, x: f64, y: f64) -> f64 {
151 match self.inner() {
152 KernelType::Logistic(k) => k.compute(x, y),
153 KernelType::RegularizedBose(k) => k.compute(x, y),
154 }
155 }
156
157 pub(crate) fn as_logistic(&self) -> Option<&Arc<LogisticKernel>> {
159 match self.inner() {
160 KernelType::Logistic(k) => Some(k),
161 _ => None,
162 }
163 }
164
165 pub(crate) fn as_regularized_bose(&self) -> Option<&Arc<RegularizedBoseKernel>> {
166 match self.inner() {
167 KernelType::RegularizedBose(k) => Some(k),
168 _ => None,
169 }
170 }
171
172 pub(crate) fn domain(&self) -> (f64, f64, f64, f64) {
174 (-1.0, 1.0, -1.0, 1.0)
176 }
177}
178
179impl Clone for spir_kernel {
180 fn clone(&self) -> Self {
181 let inner = self.inner().clone();
183 Self {
184 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
185 }
186 }
187}
188
189impl Drop for spir_kernel {
190 fn drop(&mut self) {
191 unsafe {
192 if !self._private.is_null() {
193 let _ = Box::from_raw(self._private as *const KernelType as *mut KernelType);
194 }
195 }
196 }
197}
198
199impl spir_sve_result {
200 fn inner_arc(&self) -> &Arc<SVEResult> {
202 unsafe { &*(self._private as *const Arc<SVEResult>) }
203 }
204
205 pub(crate) fn new(sve_result: SVEResult) -> Self {
206 let inner = Arc::new(sve_result);
207 Self {
208 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
209 }
210 }
211
212 pub(crate) fn size(&self) -> usize {
213 self.inner_arc().s.len()
214 }
215
216 pub(crate) fn svals(&self) -> &[f64] {
217 &self.inner_arc().s
218 }
219
220 #[allow(dead_code)]
221 pub(crate) fn epsilon(&self) -> f64 {
222 self.inner_arc().epsilon
223 }
224
225 #[allow(dead_code)]
226 pub(crate) fn truncate(&self, epsilon: f64, max_size: Option<usize>) -> Self {
227 let (u_part, s_part, v_part) = self.inner_arc().part(Some(epsilon), max_size);
228 let truncated = SVEResult::new(u_part, s_part, v_part, epsilon);
229 Self::new(truncated)
230 }
231
232 pub(crate) fn inner(&self) -> &Arc<SVEResult> {
234 self.inner_arc()
235 }
236}
237
238impl Clone for spir_sve_result {
239 fn clone(&self) -> Self {
240 let inner = self.inner_arc().clone();
242 Self {
243 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
244 }
245 }
246}
247
248impl Drop for spir_sve_result {
249 fn drop(&mut self) {
250 unsafe {
251 if !self._private.is_null() {
252 let _ =
253 Box::from_raw(self._private as *const Arc<SVEResult> as *mut Arc<SVEResult>);
254 }
255 }
256 }
257}
258
259impl spir_basis {
260 pub(crate) fn inner(&self) -> &BasisType {
262 unsafe { &*(self._private as *const BasisType) }
263 }
264
265 fn inner_type(&self) -> &BasisType {
266 self.inner()
267 }
268
269 pub(crate) fn new_logistic_fermionic(
270 basis: FiniteTempBasis<LogisticKernel, Fermionic>,
271 ) -> Self {
272 let inner = BasisType::LogisticFermionic(Arc::new(basis));
273 Self {
274 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
275 }
276 }
277
278 pub(crate) fn new_logistic_bosonic(basis: FiniteTempBasis<LogisticKernel, Bosonic>) -> Self {
279 let inner = BasisType::LogisticBosonic(Arc::new(basis));
280 Self {
281 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
282 }
283 }
284
285 #[allow(dead_code)]
288 pub(crate) fn new_regularized_bose_fermionic(
289 basis: FiniteTempBasis<RegularizedBoseKernel, Fermionic>,
290 ) -> Self {
291 let inner = BasisType::RegularizedBoseFermionic(Arc::new(basis));
292 Self {
293 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
294 }
295 }
296
297 pub(crate) fn new_regularized_bose_bosonic(
298 basis: FiniteTempBasis<RegularizedBoseKernel, Bosonic>,
299 ) -> Self {
300 let inner = BasisType::RegularizedBoseBosonic(Arc::new(basis));
301 Self {
302 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
303 }
304 }
305
306 pub(crate) fn new_dlr_fermionic(
307 dlr: Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Fermionic>>,
308 ) -> Self {
309 let inner = BasisType::DLRFermionic(dlr);
310 Self {
311 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
312 }
313 }
314
315 pub(crate) fn new_dlr_bosonic(
316 dlr: Arc<sparse_ir::dlr::DiscreteLehmannRepresentation<Bosonic>>,
317 ) -> Self {
318 let inner = BasisType::DLRBosonic(dlr);
319 Self {
320 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
321 }
322 }
323
324 pub(crate) fn size(&self) -> usize {
325 match self.inner_type() {
326 BasisType::LogisticFermionic(b) => b.size(),
327 BasisType::LogisticBosonic(b) => b.size(),
328 BasisType::RegularizedBoseFermionic(b) => b.size(),
329 BasisType::RegularizedBoseBosonic(b) => b.size(),
330 BasisType::DLRFermionic(dlr) => dlr.poles.len(),
331 BasisType::DLRBosonic(dlr) => dlr.poles.len(),
332 }
333 }
334
335 pub(crate) fn svals(&self) -> Vec<f64> {
336 match self.inner_type() {
337 BasisType::LogisticFermionic(b) => b.s().to_vec(),
338 BasisType::LogisticBosonic(b) => b.s().to_vec(),
339 BasisType::RegularizedBoseFermionic(b) => b.s().to_vec(),
340 BasisType::RegularizedBoseBosonic(b) => b.s().to_vec(),
341 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
343 }
344 }
345
346 pub(crate) fn statistics(&self) -> i32 {
347 match self.inner_type() {
349 BasisType::LogisticFermionic(_) => 1,
350 BasisType::LogisticBosonic(_) => 0,
351 BasisType::RegularizedBoseFermionic(_) => 1,
352 BasisType::RegularizedBoseBosonic(_) => 0,
353 BasisType::DLRFermionic(_) => 1,
354 BasisType::DLRBosonic(_) => 0,
355 }
356 }
357
358 pub(crate) fn beta(&self) -> f64 {
359 match self.inner_type() {
360 BasisType::LogisticFermionic(b) => b.beta(),
361 BasisType::LogisticBosonic(b) => b.beta(),
362 BasisType::RegularizedBoseFermionic(b) => b.beta(),
363 BasisType::RegularizedBoseBosonic(b) => b.beta(),
364 BasisType::DLRFermionic(dlr) => dlr.beta,
365 BasisType::DLRBosonic(dlr) => dlr.beta,
366 }
367 }
368
369 #[allow(dead_code)]
370 pub(crate) fn wmax(&self) -> f64 {
371 match self.inner_type() {
372 BasisType::LogisticFermionic(b) => b.wmax(),
373 BasisType::LogisticBosonic(b) => b.wmax(),
374 BasisType::RegularizedBoseFermionic(b) => b.wmax(),
375 BasisType::RegularizedBoseBosonic(b) => b.wmax(),
376 BasisType::DLRFermionic(dlr) => dlr.wmax,
377 BasisType::DLRBosonic(dlr) => dlr.wmax,
378 }
379 }
380
381 pub(crate) fn default_tau_sampling_points(&self) -> Vec<f64> {
382 match self.inner_type() {
383 BasisType::LogisticFermionic(b) => b.default_tau_sampling_points(),
384 BasisType::LogisticBosonic(b) => b.default_tau_sampling_points(),
385 BasisType::RegularizedBoseFermionic(b) => b.default_tau_sampling_points(),
386 BasisType::RegularizedBoseBosonic(b) => b.default_tau_sampling_points(),
387 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
389 }
390 }
391
392 pub(crate) fn default_tau_sampling_points_size_requested(
393 &self,
394 size_requested: usize,
395 ) -> Vec<f64> {
396 match self.inner_type() {
397 BasisType::LogisticFermionic(b) => {
398 b.default_tau_sampling_points_size_requested(size_requested)
399 }
400 BasisType::LogisticBosonic(b) => {
401 b.default_tau_sampling_points_size_requested(size_requested)
402 }
403 BasisType::RegularizedBoseFermionic(b) => {
404 b.default_tau_sampling_points_size_requested(size_requested)
405 }
406 BasisType::RegularizedBoseBosonic(b) => {
407 b.default_tau_sampling_points_size_requested(size_requested)
408 }
409 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
411 }
412 }
413
414 pub(crate) fn default_matsubara_sampling_points(&self, positive_only: bool) -> Vec<i64> {
415 match self.inner_type() {
416 BasisType::LogisticFermionic(b) => {
417 b.default_matsubara_sampling_points_i64(positive_only)
418 }
419 BasisType::LogisticBosonic(b) => b.default_matsubara_sampling_points_i64(positive_only),
420 BasisType::RegularizedBoseFermionic(b) => {
421 b.default_matsubara_sampling_points_i64(positive_only)
422 }
423 BasisType::RegularizedBoseBosonic(b) => {
424 b.default_matsubara_sampling_points_i64(positive_only)
425 }
426 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
428 }
429 }
430
431 pub(crate) fn default_matsubara_sampling_points_with_mitigate(
432 &self,
433 positive_only: bool,
434 mitigate: bool,
435 n_points: usize,
436 ) -> Vec<i64> {
437 match self.inner_type() {
438 BasisType::LogisticFermionic(b) => b
439 .default_matsubara_sampling_points_i64_with_mitigate(
440 positive_only,
441 mitigate,
442 n_points,
443 ),
444 BasisType::LogisticBosonic(b) => b.default_matsubara_sampling_points_i64_with_mitigate(
445 positive_only,
446 mitigate,
447 n_points,
448 ),
449 BasisType::RegularizedBoseFermionic(b) => b
450 .default_matsubara_sampling_points_i64_with_mitigate(
451 positive_only,
452 mitigate,
453 n_points,
454 ),
455 BasisType::RegularizedBoseBosonic(b) => b
456 .default_matsubara_sampling_points_i64_with_mitigate(
457 positive_only,
458 mitigate,
459 n_points,
460 ),
461 BasisType::DLRFermionic(_) | BasisType::DLRBosonic(_) => vec![],
463 }
464 }
465
466 pub(crate) fn default_omega_sampling_points(&self) -> Vec<f64> {
467 match self.inner_type() {
468 BasisType::LogisticFermionic(b) => b.default_omega_sampling_points(),
469 BasisType::LogisticBosonic(b) => b.default_omega_sampling_points(),
470 BasisType::RegularizedBoseFermionic(b) => b.default_omega_sampling_points(),
471 BasisType::RegularizedBoseBosonic(b) => b.default_omega_sampling_points(),
472 BasisType::DLRFermionic(dlr) => dlr.poles.clone(),
474 BasisType::DLRBosonic(dlr) => dlr.poles.clone(),
475 }
476 }
477}
478
479impl Clone for spir_basis {
480 fn clone(&self) -> Self {
481 let inner = self.inner_type().clone();
483 Self {
484 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
485 }
486 }
487}
488
489impl Drop for spir_basis {
490 fn drop(&mut self) {
491 unsafe {
492 if !self._private.is_null() {
493 let _ = Box::from_raw(self._private as *const BasisType as *mut BasisType);
494 }
495 }
496 }
497}
498
499#[derive(Clone)]
505pub(crate) struct PolyVectorFuncs {
506 pub poly: Arc<PiecewiseLegendrePolyVector>,
507 pub domain: FunctionDomain,
508}
509
510impl PolyVectorFuncs {
511 pub fn evaluate_at(&self, x: f64, beta: f64) -> Vec<f64> {
513 let (x_reg, sign) = match self.domain {
515 FunctionDomain::Tau(Statistics::Fermionic) => {
516 normalize_tau::<Fermionic>(x, beta)
518 }
519 FunctionDomain::Tau(Statistics::Bosonic) => {
520 normalize_tau::<Bosonic>(x, beta)
522 }
523 FunctionDomain::Omega => {
524 (x, 1.0)
526 }
527 };
528
529 self.poly
531 .polyvec
532 .iter()
533 .map(|p| sign * p.evaluate(x_reg))
534 .collect()
535 }
536
537 pub fn batch_evaluate_at(&self, xs: &[f64], beta: f64) -> Vec<Vec<f64>> {
540 let n_funcs = self.poly.polyvec.len();
541 let n_points = xs.len();
542 let mut result = vec![vec![0.0; n_points]; n_funcs];
543
544 let normalized: Vec<(f64, f64)> = xs
546 .iter()
547 .map(|&x| match self.domain {
548 FunctionDomain::Tau(Statistics::Fermionic) => normalize_tau::<Fermionic>(x, beta),
549 FunctionDomain::Tau(Statistics::Bosonic) => normalize_tau::<Bosonic>(x, beta),
550 FunctionDomain::Omega => (x, 1.0),
551 })
552 .collect();
553
554 let xs_reg: Vec<f64> = normalized.iter().map(|(x, _)| *x).collect();
556 let signs: Vec<f64> = normalized.iter().map(|(_, s)| *s).collect();
557
558 for (i, p) in self.poly.polyvec.iter().enumerate() {
560 let values = p.evaluate_many(&xs_reg);
561 for (j, &val) in values.iter().enumerate() {
562 result[i][j] = signs[j] * val;
563 }
564 }
565
566 result
567 }
568}
569
570#[derive(Clone)]
572pub(crate) struct FTVectorFuncs {
573 pub ft_fermionic: Option<Arc<PiecewiseLegendreFTVector<Fermionic>>>,
574 pub ft_bosonic: Option<Arc<PiecewiseLegendreFTVector<Bosonic>>>,
575 pub statistics: Statistics,
576}
577
578#[derive(Clone)]
580pub(crate) struct DLRTauFuncs {
581 pub poles: Vec<f64>,
582 pub beta: f64,
583 pub wmax: f64,
584 pub pole_weights: Vec<f64>,
585 pub kernel_ypower: i32,
586 pub statistics: Statistics,
587}
588
589impl DLRTauFuncs {
590 fn zero_pole_tau_limit(&self) -> f64 {
591 match self.kernel_ypower {
592 0 => -0.5,
593 1 => -1.0 / (self.beta * self.wmax * self.wmax),
594 _ => panic!(
595 "DLR tau evaluation does not support kernel ypower = {}",
596 self.kernel_ypower
597 ),
598 }
599 }
600
601 fn evaluate_single(&self, tau: f64, pole: f64, pole_weight: f64) -> f64 {
602 match self.statistics {
603 Statistics::Fermionic => {
604 let (tau_reg, sign) = normalize_tau::<Fermionic>(tau, self.beta);
605 let value = if pole >= 0.0 {
606 -(-pole * tau_reg).exp() / (1.0 + (-self.beta * pole).exp())
607 } else {
608 -(pole * (self.beta - tau_reg)).exp() / (1.0 + (self.beta * pole).exp())
609 };
610 sign * value * pole_weight
611 }
612 Statistics::Bosonic => {
613 let (tau_reg, sign) = normalize_tau::<Bosonic>(tau, self.beta);
614 if pole == 0.0 {
615 sign * self.zero_pole_tau_limit()
616 } else if pole > 0.0 {
617 let denominator = -(-self.beta * pole).exp_m1();
618 sign * (-(-tau_reg * pole).exp() * pole_weight / denominator)
619 } else {
620 let denominator = -(self.beta * pole).exp_m1();
621 sign * ((pole * (self.beta - tau_reg)).exp() * pole_weight / denominator)
622 }
623 }
624 }
625 }
626
627 pub fn evaluate_at(&self, tau: f64) -> Vec<f64> {
629 self.poles
630 .iter()
631 .zip(self.pole_weights.iter())
632 .map(|(&pole, &pole_weight)| self.evaluate_single(tau, pole, pole_weight))
633 .collect()
634 }
635
636 pub fn batch_evaluate_at(&self, taus: &[f64]) -> Vec<Vec<f64>> {
639 let n_funcs = self.poles.len();
640 let n_points = taus.len();
641 let mut result = vec![vec![0.0; n_points]; n_funcs];
642
643 for (j, &tau) in taus.iter().enumerate() {
645 for (i, (&pole, &pole_weight)) in
646 self.poles.iter().zip(self.pole_weights.iter()).enumerate()
647 {
648 result[i][j] = self.evaluate_single(tau, pole, pole_weight);
649 }
650 }
651
652 result
653 }
654}
655
656#[derive(Clone)]
658pub(crate) struct DLRMatsubaraFuncs {
659 pub poles: Vec<f64>,
660 pub beta: f64,
661 pub wmax: f64,
662 pub pole_weights: Vec<f64>,
663 pub kernel_ypower: i32,
664 pub statistics: Statistics,
665}
666
667impl DLRMatsubaraFuncs {
668 fn zero_pole_matsubara_limit(&self) -> f64 {
669 match self.kernel_ypower {
670 0 => -0.5 * self.beta,
671 1 => -1.0 / (self.wmax * self.wmax),
672 _ => panic!(
673 "DLR Matsubara evaluation does not support kernel ypower = {}",
674 self.kernel_ypower
675 ),
676 }
677 }
678}
679
680#[derive(Clone)]
686pub(crate) enum FuncsType {
687 PolyVector(PolyVectorFuncs),
689
690 FTVector(FTVectorFuncs),
692
693 DLRTau(DLRTauFuncs),
695
696 DLRMatsubara(DLRMatsubaraFuncs),
698}
699
700#[repr(C)]
709pub struct spir_funcs {
710 pub(crate) _private: *const std::ffi::c_void,
711 pub(crate) beta: f64,
712}
713
714impl spir_funcs {
715 pub(crate) fn inner_type(&self) -> &FuncsType {
717 unsafe { &*(self._private as *const FuncsType) }
718 }
719
720 pub(crate) fn from_u_fermionic(poly: Arc<PiecewiseLegendrePolyVector>, beta: f64) -> Self {
722 let inner = FuncsType::PolyVector(PolyVectorFuncs {
723 poly,
724 domain: FunctionDomain::Tau(Statistics::Fermionic),
725 });
726 Self {
727 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
728 beta,
729 }
730 }
731
732 pub(crate) fn from_u_bosonic(poly: Arc<PiecewiseLegendrePolyVector>, beta: f64) -> Self {
734 let inner = FuncsType::PolyVector(PolyVectorFuncs {
735 poly,
736 domain: FunctionDomain::Tau(Statistics::Bosonic),
737 });
738 Self {
739 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
740 beta,
741 }
742 }
743
744 pub(crate) fn from_v(poly: Arc<PiecewiseLegendrePolyVector>, beta: f64) -> Self {
746 let inner = FuncsType::PolyVector(PolyVectorFuncs {
747 poly,
748 domain: FunctionDomain::Omega,
749 });
750 Self {
751 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
752 beta,
753 }
754 }
755
756 pub(crate) fn from_uhat_fermionic(
758 ft: Arc<PiecewiseLegendreFTVector<Fermionic>>,
759 beta: f64,
760 ) -> Self {
761 let inner = FuncsType::FTVector(FTVectorFuncs {
762 ft_fermionic: Some(ft),
763 ft_bosonic: None,
764 statistics: Statistics::Fermionic,
765 });
766 Self {
767 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
768 beta,
769 }
770 }
771
772 pub(crate) fn from_uhat_bosonic(
774 ft: Arc<PiecewiseLegendreFTVector<Bosonic>>,
775 beta: f64,
776 ) -> Self {
777 let inner = FuncsType::FTVector(FTVectorFuncs {
778 ft_fermionic: None,
779 ft_bosonic: Some(ft),
780 statistics: Statistics::Bosonic,
781 });
782 Self {
783 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
784 beta,
785 }
786 }
787
788 pub(crate) fn from_uhat_full_fermionic(
794 ft: Arc<PiecewiseLegendreFTVector<Fermionic>>,
795 beta: f64,
796 ) -> Self {
797 let inner = FuncsType::FTVector(FTVectorFuncs {
798 ft_fermionic: Some(ft),
799 ft_bosonic: None,
800 statistics: Statistics::Fermionic,
801 });
802 Self {
803 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
804 beta,
805 }
806 }
807
808 pub(crate) fn from_uhat_full_bosonic(
814 ft: Arc<PiecewiseLegendreFTVector<Bosonic>>,
815 beta: f64,
816 ) -> Self {
817 let inner = FuncsType::FTVector(FTVectorFuncs {
818 ft_fermionic: None,
819 ft_bosonic: Some(ft),
820 statistics: Statistics::Bosonic,
821 });
822 Self {
823 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
824 beta,
825 }
826 }
827
828 pub(crate) fn from_dlr_tau_fermionic(
831 poles: Vec<f64>,
832 beta: f64,
833 wmax: f64,
834 pole_weights: Vec<f64>,
835 kernel_ypower: i32,
836 ) -> Self {
837 let inner = FuncsType::DLRTau(DLRTauFuncs {
838 poles,
839 beta,
840 wmax,
841 pole_weights,
842 kernel_ypower,
843 statistics: Statistics::Fermionic,
844 });
845 Self {
846 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
847 beta,
848 }
849 }
850
851 pub(crate) fn from_dlr_tau_bosonic(
854 poles: Vec<f64>,
855 beta: f64,
856 wmax: f64,
857 pole_weights: Vec<f64>,
858 kernel_ypower: i32,
859 ) -> Self {
860 let inner = FuncsType::DLRTau(DLRTauFuncs {
861 poles,
862 beta,
863 wmax,
864 pole_weights,
865 kernel_ypower,
866 statistics: Statistics::Bosonic,
867 });
868 Self {
869 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
870 beta,
871 }
872 }
873
874 pub(crate) fn from_dlr_matsubara_fermionic(
876 poles: Vec<f64>,
877 beta: f64,
878 wmax: f64,
879 pole_weights: Vec<f64>,
880 kernel_ypower: i32,
881 ) -> Self {
882 let inner = FuncsType::DLRMatsubara(DLRMatsubaraFuncs {
883 poles,
884 beta,
885 wmax,
886 pole_weights,
887 kernel_ypower,
888 statistics: Statistics::Fermionic,
889 });
890 Self {
891 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
892 beta,
893 }
894 }
895
896 pub(crate) fn from_dlr_matsubara_bosonic(
898 poles: Vec<f64>,
899 beta: f64,
900 wmax: f64,
901 pole_weights: Vec<f64>,
902 kernel_ypower: i32,
903 ) -> Self {
904 let inner = FuncsType::DLRMatsubara(DLRMatsubaraFuncs {
905 poles,
906 beta,
907 wmax,
908 pole_weights,
909 kernel_ypower,
910 statistics: Statistics::Bosonic,
911 });
912 Self {
913 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
914 beta,
915 }
916 }
917
918 pub(crate) fn size(&self) -> usize {
920 match self.inner_type() {
921 FuncsType::PolyVector(pv) => pv.poly.polyvec.len(),
922 FuncsType::FTVector(ftv) => {
923 if let Some(ft) = &ftv.ft_fermionic {
924 ft.polyvec.len()
925 } else if let Some(ft) = &ftv.ft_bosonic {
926 ft.polyvec.len()
927 } else {
928 0
929 }
930 }
931 FuncsType::DLRTau(dlr) => dlr.poles.len(),
932 FuncsType::DLRMatsubara(dlr) => dlr.poles.len(),
933 }
934 }
935
936 pub(crate) fn knots(&self) -> Option<Vec<f64>> {
938 match self.inner_type() {
939 FuncsType::PolyVector(pv) => {
940 let mut all_knots = Vec::new();
942 for p in &pv.poly.polyvec {
943 for &knot in &p.knots {
944 if !all_knots.iter().any(|&k: &f64| (k - knot).abs() < 1e-14) {
945 all_knots.push(knot);
946 }
947 }
948 }
949 all_knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
950 Some(all_knots)
951 }
952 _ => None, }
954 }
955
956 pub(crate) fn eval_continuous(&self, x: f64) -> Option<Vec<f64>> {
964 match self.inner_type() {
965 FuncsType::PolyVector(pv) => Some(pv.evaluate_at(x, self.beta)),
966 FuncsType::DLRTau(dlr) => Some(dlr.evaluate_at(x)),
967 _ => None,
968 }
969 }
970
971 pub(crate) fn eval_matsubara(&self, n: i64) -> Option<Vec<num_complex::Complex64>> {
979 match self.inner_type() {
980 FuncsType::FTVector(ftv) => {
981 if ftv.statistics == Statistics::Fermionic {
982 let ft = ftv.ft_fermionic.as_ref()?;
984 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
985 let mut result = Vec::with_capacity(ft.polyvec.len());
986 for p in &ft.polyvec {
987 result.push(p.evaluate(&freq));
988 }
989 Some(result)
990 } else {
991 let ft = ftv.ft_bosonic.as_ref()?;
993 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
994 let mut result = Vec::with_capacity(ft.polyvec.len());
995 for p in &ft.polyvec {
996 result.push(p.evaluate(&freq));
997 }
998 Some(result)
999 }
1000 }
1001 FuncsType::DLRMatsubara(dlr) => {
1002 use num_complex::Complex;
1004
1005 let mut result = Vec::with_capacity(dlr.poles.len());
1006 if dlr.statistics == Statistics::Fermionic {
1007 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
1008 let iv = freq.value_imaginary(dlr.beta);
1009 for (i, &pole) in dlr.poles.iter().enumerate() {
1010 let pole_weight = dlr.pole_weights[i];
1011 result
1012 .push(Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0)));
1013 }
1014 } else {
1015 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
1016 let iv = freq.value_imaginary(dlr.beta);
1017 for (i, &pole) in dlr.poles.iter().enumerate() {
1018 if pole == 0.0 {
1019 if freq.n() == 0 {
1020 result.push(Complex::new(dlr.zero_pole_matsubara_limit(), 0.0));
1021 } else {
1022 result.push(Complex::new(0.0, 0.0));
1023 }
1024 } else {
1025 let pole_weight = dlr.pole_weights[i];
1026 result.push(
1027 Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0)),
1028 );
1029 }
1030 }
1031 }
1032 Some(result)
1033 }
1034 _ => None,
1035 }
1036 }
1037
1038 pub(crate) fn batch_eval_continuous(&self, xs: &[f64]) -> Option<Vec<Vec<f64>>> {
1040 match self.inner_type() {
1041 FuncsType::PolyVector(pv) => Some(pv.batch_evaluate_at(xs, self.beta)),
1042 FuncsType::DLRTau(dlr) => Some(dlr.batch_evaluate_at(xs)),
1043 _ => None,
1044 }
1045 }
1046
1047 pub(crate) fn batch_eval_matsubara(
1055 &self,
1056 ns: &[i64],
1057 ) -> Option<Vec<Vec<num_complex::Complex64>>> {
1058 match self.inner_type() {
1059 FuncsType::FTVector(ftv) => {
1060 if ftv.statistics == Statistics::Fermionic {
1061 let ft = ftv.ft_fermionic.as_ref()?;
1063 let n_funcs = ft.polyvec.len();
1064 let n_points = ns.len();
1065 let mut result =
1066 vec![vec![num_complex::Complex64::new(0.0, 0.0); n_points]; n_funcs];
1067
1068 for (j, &n) in ns.iter().enumerate() {
1069 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
1070 for (i, p) in ft.polyvec.iter().enumerate() {
1071 result[i][j] = p.evaluate(&freq);
1072 }
1073 }
1074 Some(result)
1075 } else {
1076 let ft = ftv.ft_bosonic.as_ref()?;
1078 let n_funcs = ft.polyvec.len();
1079 let n_points = ns.len();
1080 let mut result =
1081 vec![vec![num_complex::Complex64::new(0.0, 0.0); n_points]; n_funcs];
1082
1083 for (j, &n) in ns.iter().enumerate() {
1084 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
1085 for (i, p) in ft.polyvec.iter().enumerate() {
1086 result[i][j] = p.evaluate(&freq);
1087 }
1088 }
1089 Some(result)
1090 }
1091 }
1092 FuncsType::DLRMatsubara(dlr) => {
1093 use num_complex::Complex;
1095
1096 let n_funcs = dlr.poles.len();
1097 let n_points = ns.len();
1098 let mut result = vec![vec![Complex::new(0.0, 0.0); n_points]; n_funcs];
1099
1100 for (j, &n) in ns.iter().enumerate() {
1101 if dlr.statistics == Statistics::Fermionic {
1102 let freq = MatsubaraFreq::<Fermionic>::new(n).ok()?;
1103 let iv = freq.value_imaginary(dlr.beta);
1104 for (i, &pole) in dlr.poles.iter().enumerate() {
1105 let pole_weight = dlr.pole_weights[i];
1106 result[i][j] =
1107 Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0));
1108 }
1109 } else {
1110 let freq = MatsubaraFreq::<Bosonic>::new(n).ok()?;
1111 let iv = freq.value_imaginary(dlr.beta);
1112 for (i, &pole) in dlr.poles.iter().enumerate() {
1113 if pole == 0.0 {
1114 if freq.n() == 0 {
1115 result[i][j] =
1116 Complex::new(dlr.zero_pole_matsubara_limit(), 0.0);
1117 } else {
1118 result[i][j] = Complex::new(0.0, 0.0);
1119 }
1120 } else {
1121 let pole_weight = dlr.pole_weights[i];
1122 result[i][j] =
1123 Complex::new(pole_weight, 0.0) / (iv - Complex::new(pole, 0.0));
1124 }
1125 }
1126 }
1127 }
1128
1129 Some(result)
1130 }
1131 FuncsType::DLRTau(_) => {
1132 None
1134 }
1135 _ => None,
1136 }
1137 }
1138
1139 pub(crate) fn get_slice(&self, indices: &[usize]) -> Option<Self> {
1147 match self.inner_type() {
1148 FuncsType::PolyVector(pv) => {
1149 let mut new_polys = Vec::with_capacity(indices.len());
1150 for &idx in indices {
1151 if idx >= pv.poly.polyvec.len() {
1152 return None;
1153 }
1154 new_polys.push(pv.poly.polyvec[idx].clone());
1155 }
1156 let new_poly_vec = PiecewiseLegendrePolyVector::new(new_polys);
1157 Some(Self {
1158 _private: Box::into_raw(Box::new(FuncsType::PolyVector(PolyVectorFuncs {
1159 poly: Arc::new(new_poly_vec),
1160 domain: pv.domain,
1161 }))) as *mut std::ffi::c_void,
1162 beta: self.beta,
1163 })
1164 }
1165 FuncsType::FTVector(ftv) => {
1166 if ftv.statistics == Statistics::Fermionic {
1168 let ft = ftv.ft_fermionic.as_ref()?;
1169 let mut new_polyvec = Vec::with_capacity(indices.len());
1170 for &idx in indices {
1171 if idx >= ft.polyvec.len() {
1172 return None;
1173 }
1174 new_polyvec.push(ft.polyvec[idx].clone());
1175 }
1176 let new_ft_vector =
1177 Arc::new(PiecewiseLegendreFTVector::from_vector(new_polyvec));
1178 Some(Self {
1179 _private: Box::into_raw(Box::new(FuncsType::FTVector(FTVectorFuncs {
1180 ft_fermionic: Some(new_ft_vector),
1181 ft_bosonic: None,
1182 statistics: ftv.statistics,
1183 }))) as *mut std::ffi::c_void,
1184 beta: self.beta,
1185 })
1186 } else {
1187 let ft = ftv.ft_bosonic.as_ref()?;
1188 let mut new_polyvec = Vec::with_capacity(indices.len());
1189 for &idx in indices {
1190 if idx >= ft.polyvec.len() {
1191 return None;
1192 }
1193 new_polyvec.push(ft.polyvec[idx].clone());
1194 }
1195 let new_ft_vector =
1196 Arc::new(PiecewiseLegendreFTVector::from_vector(new_polyvec));
1197 Some(Self {
1198 _private: Box::into_raw(Box::new(FuncsType::FTVector(FTVectorFuncs {
1199 ft_fermionic: None,
1200 ft_bosonic: Some(new_ft_vector),
1201 statistics: ftv.statistics,
1202 }))) as *mut std::ffi::c_void,
1203 beta: self.beta,
1204 })
1205 }
1206 }
1207 FuncsType::DLRTau(dlr) => {
1208 let mut new_poles = Vec::with_capacity(indices.len());
1210 let mut new_pole_weights = Vec::with_capacity(indices.len());
1211 for &idx in indices {
1212 if idx >= dlr.poles.len() {
1213 return None;
1214 }
1215 new_poles.push(dlr.poles[idx]);
1216 new_pole_weights.push(dlr.pole_weights[idx]);
1217 }
1218 Some(Self {
1219 _private: Box::into_raw(Box::new(FuncsType::DLRTau(DLRTauFuncs {
1220 poles: new_poles,
1221 beta: dlr.beta,
1222 wmax: dlr.wmax,
1223 pole_weights: new_pole_weights,
1224 kernel_ypower: dlr.kernel_ypower,
1225 statistics: dlr.statistics,
1226 }))) as *mut std::ffi::c_void,
1227 beta: dlr.beta,
1228 })
1229 }
1230 FuncsType::DLRMatsubara(dlr) => {
1231 let mut new_poles = Vec::with_capacity(indices.len());
1233 let mut new_pole_weights = Vec::with_capacity(indices.len());
1234 for &idx in indices {
1235 if idx >= dlr.poles.len() {
1236 return None;
1237 }
1238 new_poles.push(dlr.poles[idx]);
1239 new_pole_weights.push(dlr.pole_weights[idx]);
1240 }
1241 Some(Self {
1242 _private: Box::into_raw(Box::new(FuncsType::DLRMatsubara(DLRMatsubaraFuncs {
1243 poles: new_poles,
1244 beta: dlr.beta,
1245 wmax: dlr.wmax,
1246 pole_weights: new_pole_weights,
1247 kernel_ypower: dlr.kernel_ypower,
1248 statistics: dlr.statistics,
1249 }))) as *mut std::ffi::c_void,
1250 beta: dlr.beta,
1251 })
1252 }
1253 }
1254 }
1255}
1256
1257impl Clone for spir_funcs {
1258 fn clone(&self) -> Self {
1259 let inner = self.inner_type().clone();
1261 Self {
1262 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
1263 beta: self.beta,
1264 }
1265 }
1266}
1267
1268impl Drop for spir_funcs {
1269 fn drop(&mut self) {
1270 unsafe {
1271 if !self._private.is_null() {
1272 let _ = Box::from_raw(self._private as *const FuncsType as *mut FuncsType);
1273 }
1274 }
1275 }
1276}
1277
1278#[cfg(test)]
1281mod tests {
1282
1283 #[test]
1284 fn test_funcs_creation() {
1285 }
1288}
1289#[repr(C)]
1296pub struct spir_sampling {
1297 pub(crate) _private: *const std::ffi::c_void,
1298}
1299
1300impl spir_sampling {
1301 pub(crate) fn inner(&self) -> &SamplingType {
1303 unsafe { &*(self._private as *const SamplingType) }
1304 }
1305}
1306
1307impl Clone for spir_sampling {
1308 fn clone(&self) -> Self {
1309 let inner = self.inner().clone();
1311 Self {
1312 _private: Box::into_raw(Box::new(inner)) as *const std::ffi::c_void,
1313 }
1314 }
1315}
1316
1317impl Drop for spir_sampling {
1318 fn drop(&mut self) {
1319 unsafe {
1320 if !self._private.is_null() {
1321 let _ = Box::from_raw(self._private as *const SamplingType as *mut SamplingType);
1322 }
1323 }
1324 }
1325}
1326
1327#[derive(Clone)]
1329pub(crate) enum SamplingType {
1330 TauFermionic(Arc<sparse_ir::sampling::TauSampling<Fermionic>>),
1331 TauBosonic(Arc<sparse_ir::sampling::TauSampling<Bosonic>>),
1332 MatsubaraFermionic(Arc<sparse_ir::matsubara_sampling::MatsubaraSampling<Fermionic>>),
1333 MatsubaraBosonic(Arc<sparse_ir::matsubara_sampling::MatsubaraSampling<Bosonic>>),
1334 MatsubaraPositiveOnlyFermionic(
1335 Arc<sparse_ir::matsubara_sampling::MatsubaraSamplingPositiveOnly<Fermionic>>,
1336 ),
1337 MatsubaraPositiveOnlyBosonic(
1338 Arc<sparse_ir::matsubara_sampling::MatsubaraSamplingPositiveOnly<Bosonic>>,
1339 ),
1340}
1341
1342impl InplaceFitter for SamplingType {
1347 fn n_points(&self) -> usize {
1348 match self {
1349 SamplingType::TauFermionic(s) => s.n_sampling_points(),
1350 SamplingType::TauBosonic(s) => s.n_sampling_points(),
1351 SamplingType::MatsubaraFermionic(s) => s.n_sampling_points(),
1352 SamplingType::MatsubaraBosonic(s) => s.n_sampling_points(),
1353 SamplingType::MatsubaraPositiveOnlyFermionic(s) => s.n_sampling_points(),
1354 SamplingType::MatsubaraPositiveOnlyBosonic(s) => s.n_sampling_points(),
1355 }
1356 }
1357
1358 fn basis_size(&self) -> usize {
1359 match self {
1360 SamplingType::TauFermionic(s) => s.basis_size(),
1361 SamplingType::TauBosonic(s) => s.basis_size(),
1362 SamplingType::MatsubaraFermionic(s) => s.basis_size(),
1363 SamplingType::MatsubaraBosonic(s) => s.basis_size(),
1364 SamplingType::MatsubaraPositiveOnlyFermionic(s) => s.basis_size(),
1365 SamplingType::MatsubaraPositiveOnlyBosonic(s) => s.basis_size(),
1366 }
1367 }
1368
1369 fn evaluate_nd_dd_to(
1370 &self,
1371 backend: Option<&GemmBackendHandle>,
1372 coeffs: &Slice<f64, DynRank>,
1373 dim: usize,
1374 out: &mut ViewMut<'_, f64, DynRank>,
1375 ) -> bool {
1376 match self {
1377 SamplingType::TauFermionic(s) => {
1378 InplaceFitter::evaluate_nd_dd_to(s.as_ref(), backend, coeffs, dim, out)
1379 }
1380 SamplingType::TauBosonic(s) => {
1381 InplaceFitter::evaluate_nd_dd_to(s.as_ref(), backend, coeffs, dim, out)
1382 }
1383 _ => false,
1385 }
1386 }
1387
1388 fn evaluate_nd_dz_to(
1389 &self,
1390 backend: Option<&GemmBackendHandle>,
1391 coeffs: &Slice<f64, DynRank>,
1392 dim: usize,
1393 out: &mut ViewMut<'_, Complex<f64>, DynRank>,
1394 ) -> bool {
1395 match self {
1396 SamplingType::MatsubaraFermionic(s) => {
1397 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1398 }
1399 SamplingType::MatsubaraBosonic(s) => {
1400 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1401 }
1402 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1403 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1404 }
1405 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1406 InplaceFitter::evaluate_nd_dz_to(s.as_ref(), backend, coeffs, dim, out)
1407 }
1408 _ => false,
1410 }
1411 }
1412
1413 fn evaluate_nd_zz_to(
1414 &self,
1415 backend: Option<&GemmBackendHandle>,
1416 coeffs: &Slice<Complex<f64>, DynRank>,
1417 dim: usize,
1418 out: &mut ViewMut<'_, Complex<f64>, DynRank>,
1419 ) -> bool {
1420 match self {
1421 SamplingType::TauFermionic(s) => {
1422 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1423 }
1424 SamplingType::TauBosonic(s) => {
1425 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1426 }
1427 SamplingType::MatsubaraFermionic(s) => {
1428 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1429 }
1430 SamplingType::MatsubaraBosonic(s) => {
1431 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1432 }
1433 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1434 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1435 }
1436 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1437 InplaceFitter::evaluate_nd_zz_to(s.as_ref(), backend, coeffs, dim, out)
1438 }
1439 }
1440 }
1441
1442 fn fit_nd_dd_to(
1443 &self,
1444 backend: Option<&GemmBackendHandle>,
1445 values: &Slice<f64, DynRank>,
1446 dim: usize,
1447 out: &mut ViewMut<'_, f64, DynRank>,
1448 ) -> bool {
1449 match self {
1450 SamplingType::TauFermionic(s) => {
1451 InplaceFitter::fit_nd_dd_to(s.as_ref(), backend, values, dim, out)
1452 }
1453 SamplingType::TauBosonic(s) => {
1454 InplaceFitter::fit_nd_dd_to(s.as_ref(), backend, values, dim, out)
1455 }
1456 _ => false,
1458 }
1459 }
1460
1461 fn fit_nd_zd_to(
1462 &self,
1463 backend: Option<&GemmBackendHandle>,
1464 values: &Slice<Complex<f64>, DynRank>,
1465 dim: usize,
1466 out: &mut ViewMut<'_, f64, DynRank>,
1467 ) -> bool {
1468 match self {
1469 SamplingType::MatsubaraFermionic(s) => {
1470 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1471 }
1472 SamplingType::MatsubaraBosonic(s) => {
1473 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1474 }
1475 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1476 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1477 }
1478 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1479 InplaceFitter::fit_nd_zd_to(s.as_ref(), backend, values, dim, out)
1480 }
1481 _ => false,
1483 }
1484 }
1485
1486 fn fit_nd_zz_to(
1487 &self,
1488 backend: Option<&GemmBackendHandle>,
1489 values: &Slice<Complex<f64>, DynRank>,
1490 dim: usize,
1491 out: &mut ViewMut<'_, Complex<f64>, DynRank>,
1492 ) -> bool {
1493 match self {
1494 SamplingType::TauFermionic(s) => {
1495 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1496 }
1497 SamplingType::TauBosonic(s) => {
1498 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1499 }
1500 SamplingType::MatsubaraFermionic(s) => {
1501 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1502 }
1503 SamplingType::MatsubaraBosonic(s) => {
1504 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1505 }
1506 SamplingType::MatsubaraPositiveOnlyFermionic(s) => {
1507 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1508 }
1509 SamplingType::MatsubaraPositiveOnlyBosonic(s) => {
1510 InplaceFitter::fit_nd_zz_to(s.as_ref(), backend, values, dim, out)
1511 }
1512 }
1513 }
1514}
1515
1516#[cfg(test)]
1517mod sampling_tests {
1518
1519 #[test]
1520 fn test_sampling_creation() {
1521 }
1524}
1525