1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8pub struct MultiplierOperator {
10 pub symbol: String,
12 pub is_bounded: bool,
14}
15impl MultiplierOperator {
16 pub fn new(symbol: impl Into<String>, is_bounded: bool) -> Self {
18 Self {
19 symbol: symbol.into(),
20 is_bounded,
21 }
22 }
23 pub fn lp_boundedness(&self) -> bool {
25 self.is_bounded
26 }
27 pub fn hormander_condition(&self) -> bool {
29 self.is_bounded
30 }
31}
32pub struct HardySpace {
34 pub p: f64,
36 pub is_real_variable: bool,
38}
39impl HardySpace {
40 pub fn new(p: f64, is_real_variable: bool) -> Self {
42 Self {
43 p,
44 is_real_variable,
45 }
46 }
47 pub fn atomic_decomposition(&self) -> bool {
49 self.p <= 1.0
50 }
51 pub fn duality_with_bmo(&self) -> bool {
53 (self.p - 1.0).abs() < 1e-12
54 }
55}
56pub struct GroupHarmonic {
58 pub group_type: String,
60}
61impl GroupHarmonic {
62 pub fn new(group_type: impl Into<String>) -> Self {
64 Self {
65 group_type: group_type.into(),
66 }
67 }
68 pub fn representation_theory_connection(&self) -> bool {
70 true
71 }
72 pub fn peter_weyl(&self) -> bool {
74 self.group_type.to_lowercase().contains("compact")
75 }
76}
77#[derive(Debug, Clone)]
84pub struct HardySpaceAtom {
85 pub lo: usize,
87 pub hi: usize,
89 pub values: Vec<f64>,
91}
92impl HardySpaceAtom {
93 pub fn new(lo: usize, hi: usize, values: Vec<f64>) -> Self {
95 HardySpaceAtom { lo, hi, values }
96 }
97 pub fn support_length(&self) -> usize {
99 if self.hi >= self.lo {
100 self.hi - self.lo + 1
101 } else {
102 0
103 }
104 }
105 pub fn has_compact_support(&self) -> bool {
107 self.values
108 .iter()
109 .enumerate()
110 .filter(|&(i, _)| i < self.lo || i > self.hi)
111 .all(|(_, &v)| v.abs() < 1e-12)
112 }
113 pub fn satisfies_linfty_bound(&self) -> bool {
115 let len = self.support_length();
116 if len == 0 {
117 return true;
118 }
119 let bound = 1.0 / len as f64;
120 self.values.iter().all(|&v| v.abs() <= bound + 1e-12)
121 }
122 pub fn has_zero_mean(&self) -> bool {
124 let sum: f64 = self.values.iter().sum();
125 sum.abs() < 1e-10
126 }
127 pub fn is_valid_atom(&self) -> bool {
129 self.has_compact_support() && self.satisfies_linfty_bound() && self.has_zero_mean()
130 }
131 pub fn canonical(signal_len: usize, lo: usize, hi: usize) -> Self {
134 let mut values = vec![0.0f64; signal_len];
135 let len = if hi >= lo { hi - lo + 1 } else { 0 };
136 if len < 2 {
137 return HardySpaceAtom { lo, hi, values };
138 }
139 let weight = 1.0 / len as f64;
140 let mid = lo + len / 2;
141 for i in lo..mid {
142 if i < signal_len {
143 values[i] = weight;
144 }
145 }
146 for i in mid..=hi {
147 if i < signal_len {
148 values[i] = -weight;
149 }
150 }
151 HardySpaceAtom { lo, hi, values }
152 }
153}
154#[derive(Debug, Clone)]
158pub struct LittlewoodPaleySquare {
159 pub signal: Vec<f64>,
161}
162impl LittlewoodPaleySquare {
163 pub fn new(signal: Vec<f64>) -> Self {
165 LittlewoodPaleySquare { signal }
166 }
167 fn dft(signal: &[f64]) -> Vec<(f64, f64)> {
169 let n = signal.len();
170 if n == 0 {
171 return vec![];
172 }
173 let two_pi_over_n = 2.0 * std::f64::consts::PI / n as f64;
174 (0..n)
175 .map(|k| {
176 signal
177 .iter()
178 .enumerate()
179 .fold((0.0, 0.0), |(re, im), (j, &x)| {
180 let angle = two_pi_over_n * (k * j) as f64;
181 (re + x * angle.cos(), im - x * angle.sin())
182 })
183 })
184 .collect()
185 }
186 fn idft(spectrum: &[(f64, f64)]) -> Vec<f64> {
188 let n = spectrum.len();
189 if n == 0 {
190 return vec![];
191 }
192 let two_pi_over_n = 2.0 * std::f64::consts::PI / n as f64;
193 let n_f = n as f64;
194 (0..n)
195 .map(|j| {
196 spectrum
197 .iter()
198 .enumerate()
199 .map(|(k, &(re, im))| {
200 let angle = two_pi_over_n * (k * j) as f64;
201 (re * angle.cos() - im * angle.sin()) / n_f
202 })
203 .sum()
204 })
205 .collect()
206 }
207 pub fn square_function_pointwise(&self) -> Vec<f64> {
209 let n = self.signal.len();
210 if n == 0 {
211 return vec![];
212 }
213 let spectrum = Self::dft(&self.signal);
214 let mut sum_sq = vec![0.0f64; n];
215 let mut j = 1usize;
216 while j < n {
217 let lo = j;
218 let hi = (2 * j).min(n);
219 let mut block_spectrum: Vec<(f64, f64)> = vec![(0.0, 0.0); n];
220 for k in lo..hi {
221 block_spectrum[k] = spectrum[k];
222 let mirror = n - k;
223 if mirror < n && mirror != k {
224 block_spectrum[mirror] = spectrum[mirror];
225 }
226 }
227 let block_signal = Self::idft(&block_spectrum);
228 for i in 0..n {
229 sum_sq[i] += block_signal[i] * block_signal[i];
230 }
231 j = hi;
232 if hi >= n {
233 break;
234 }
235 }
236 sum_sq.iter().map(|&s| s.sqrt()).collect()
237 }
238 pub fn l2_norm_squared(&self) -> f64 {
240 self.square_function_pointwise()
241 .iter()
242 .map(|&v| v * v)
243 .sum()
244 }
245 pub fn signal_l2_norm_squared(&self) -> f64 {
247 self.signal.iter().map(|&x| x * x).sum()
248 }
249 pub fn verify_lp_inequality(&self) -> (f64, f64, f64) {
253 let sq_norm = self.l2_norm_squared();
254 let sig_norm = self.signal_l2_norm_squared();
255 let ratio = if sig_norm > 1e-15 {
256 sq_norm / sig_norm
257 } else {
258 1.0
259 };
260 (sq_norm, sig_norm, ratio)
261 }
262}
263#[derive(Debug, Clone)]
268pub struct FourierMultiplierOp {
269 pub symbol: Vec<f64>,
271}
272impl FourierMultiplierOp {
273 pub fn new(symbol: Vec<f64>) -> Self {
275 FourierMultiplierOp { symbol }
276 }
277 pub fn hilbert_multiplier(n: usize) -> Self {
280 let mut symbol = vec![0.0f64; n];
281 for k in 1..n / 2 {
282 symbol[k] = 1.0;
283 }
284 for k in n / 2..n {
285 symbol[k] = -1.0;
286 }
287 FourierMultiplierOp { symbol }
288 }
289 pub fn low_pass(n: usize, cutoff: usize) -> Self {
291 let mut symbol = vec![0.0f64; n];
292 for k in 0..=cutoff.min(n - 1) {
293 symbol[k] = 1.0;
294 }
295 for k in (n - cutoff).min(n)..n {
296 symbol[k] = 1.0;
297 }
298 FourierMultiplierOp { symbol }
299 }
300 pub fn apply(&self, signal: &[f64]) -> Vec<f64> {
304 let n = signal.len();
305 assert_eq!(n, self.symbol.len());
306 if n == 0 {
307 return vec![];
308 }
309 let two_pi_over_n = 2.0 * std::f64::consts::PI / n as f64;
310 let spectrum: Vec<(f64, f64)> = (0..n)
311 .map(|k| {
312 signal
313 .iter()
314 .enumerate()
315 .fold((0.0, 0.0), |(re, im), (j, &x)| {
316 let angle = two_pi_over_n * (k * j) as f64;
317 (re + x * angle.cos(), im - x * angle.sin())
318 })
319 })
320 .collect();
321 let filtered: Vec<(f64, f64)> = spectrum
322 .iter()
323 .zip(self.symbol.iter())
324 .map(|(&(re, im), &m)| (re * m, im * m))
325 .collect();
326 let n_f = n as f64;
327 (0..n)
328 .map(|j| {
329 filtered
330 .iter()
331 .enumerate()
332 .map(|(k, &(re, im))| {
333 let angle = two_pi_over_n * (k * j) as f64;
334 (re * angle.cos() - im * angle.sin()) / n_f
335 })
336 .sum()
337 })
338 .collect()
339 }
340 pub fn l2_operator_norm(&self) -> f64 {
344 self.symbol.iter().fold(0.0_f64, |acc, &m| acc.max(m.abs()))
345 }
346 pub fn is_l2_bounded(&self) -> bool {
348 self.l2_operator_norm().is_finite()
349 }
350}
351#[allow(dead_code)]
353#[derive(Debug, Clone)]
354pub struct CalderonZygmundOperator {
355 pub name: String,
357 pub l2_bounded: bool,
359 pub kernel_order: f64,
361 pub dimension: usize,
363}
364#[allow(dead_code)]
365impl CalderonZygmundOperator {
366 pub fn new(name: &str, dim: usize) -> Self {
368 CalderonZygmundOperator {
369 name: name.to_string(),
370 l2_bounded: true,
371 kernel_order: 0.0,
372 dimension: dim,
373 }
374 }
375 pub fn hilbert_transform() -> Self {
377 CalderonZygmundOperator::new("H", 1)
378 }
379 pub fn riesz_transform(j: usize, n: usize) -> Self {
381 CalderonZygmundOperator::new(&format!("R_{j}"), n)
382 }
383 pub fn lp_boundedness(&self, p: f64) -> bool {
385 self.l2_bounded && p > 1.0 && p < f64::INFINITY
386 }
387 pub fn weak_type_one_one(&self) -> bool {
389 self.l2_bounded
390 }
391 pub fn cotlar_stein_description(&self) -> String {
393 format!(
394 "Cotlar-Stein for {}: almost orthogonal sum bounded on L^2",
395 self.name
396 )
397 }
398 pub fn t1_theorem_condition(&self) -> String {
400 format!(
401 "T(1) theorem: {} bounded on L^2 iff T(1), T^*(1) ∈ BMO",
402 self.name
403 )
404 }
405}
406pub struct LPSquareFunction {
411 pub signal: Vec<f64>,
413}
414impl LPSquareFunction {
415 pub fn new(signal: Vec<f64>) -> Self {
417 Self { signal }
418 }
419 pub fn square_function_pointwise(&self) -> Vec<f64> {
421 let n = self.signal.len();
422 if n == 0 {
423 return vec![];
424 }
425 let spectrum = dft(&self.signal);
426 let mut sum_sq = vec![0.0f64; n];
427 let mut j = 1usize;
428 while j < n {
429 let lo = j;
430 let hi = (2 * j).min(n);
431 let mut block_spectrum: Vec<(f64, f64)> = vec![(0.0, 0.0); n];
432 for k in lo..hi {
433 block_spectrum[k] = spectrum[k];
434 let mirror = n - k;
435 if mirror < n && mirror != k {
436 block_spectrum[mirror] = spectrum[mirror];
437 }
438 }
439 let block_signal = idft(&block_spectrum);
440 for i in 0..n {
441 sum_sq[i] += block_signal[i] * block_signal[i];
442 }
443 j = hi;
444 if hi >= n {
445 break;
446 }
447 }
448 sum_sq.iter().map(|&s| s.sqrt()).collect()
449 }
450 pub fn l2_norm_squared(&self) -> f64 {
452 self.square_function_pointwise()
453 .iter()
454 .map(|&v| v * v)
455 .sum()
456 }
457}
458pub struct CalderonZygmund {
460 pub kernel: String,
462 pub is_singular: bool,
464}
465impl CalderonZygmund {
466 pub fn new(kernel: impl Into<String>, is_singular: bool) -> Self {
468 Self {
469 kernel: kernel.into(),
470 is_singular,
471 }
472 }
473 pub fn lp_estimate(&self) -> bool {
475 true
476 }
477 pub fn endpoint_l1(&self) -> bool {
479 true
480 }
481}
482#[allow(dead_code)]
484#[derive(Debug, Clone)]
485pub struct OscillatoryIntegralData {
486 pub phase: String,
488 pub amplitude: String,
490 pub frequency: f64,
492 pub dim: usize,
494}
495#[allow(dead_code)]
496impl OscillatoryIntegralData {
497 pub fn new(phase: &str, amplitude: &str, lambda: f64, dim: usize) -> Self {
499 OscillatoryIntegralData {
500 phase: phase.to_string(),
501 amplitude: amplitude.to_string(),
502 frequency: lambda,
503 dim,
504 }
505 }
506 pub fn stationary_phase_decay(&self) -> f64 {
508 self.frequency.powf(-(self.dim as f64) / 2.0)
509 }
510 pub fn van_der_corput_bound(&self, k: usize) -> f64 {
512 self.frequency.powf(-1.0 / k as f64)
513 }
514 pub fn strichartz_description(&self) -> String {
516 format!(
517 "Strichartz: ||e^{{it∆}}f||_{{L^p_t L^q_x}} <= C ||f||_{{L^2}} (n={})",
518 self.dim
519 )
520 }
521}
522#[allow(dead_code)]
524#[derive(Debug, Clone)]
525pub struct BMOData {
526 pub values: Vec<f64>,
528 pub bmo_seminorm: f64,
530}
531#[allow(dead_code)]
532impl BMOData {
533 pub fn new(values: Vec<f64>) -> Self {
535 let seminorm = Self::compute_bmo_seminorm(&values);
536 BMOData {
537 values,
538 bmo_seminorm: seminorm,
539 }
540 }
541 fn compute_bmo_seminorm(values: &[f64]) -> f64 {
544 if values.is_empty() {
545 return 0.0;
546 }
547 let mean: f64 = values.iter().sum::<f64>() / values.len() as f64;
548 let dev: f64 = values.iter().map(|&x| (x - mean).abs()).sum::<f64>() / values.len() as f64;
549 dev
550 }
551 pub fn john_nirenberg_constant(&self) -> f64 {
553 if self.bmo_seminorm < 1e-14 {
554 0.0
555 } else {
556 1.0 / self.bmo_seminorm
557 }
558 }
559 pub fn is_vmo_approx(&self, tol: f64) -> bool {
561 self.bmo_seminorm < tol
562 }
563}
564pub struct FourierSeries {
566 pub period: f64,
568 pub coefficients: Vec<(f64, f64)>,
570}
571impl FourierSeries {
572 pub fn new(period: f64, coefficients: Vec<(f64, f64)>) -> Self {
574 Self {
575 period,
576 coefficients,
577 }
578 }
579 pub fn partial_sum(&self, n: usize, x: f64) -> f64 {
583 let t = self.period;
584 let (a0, _b0) = self.coefficients.first().copied().unwrap_or((0.0, 0.0));
585 let mut s = a0 / 2.0;
586 let limit = n.min(self.coefficients.len().saturating_sub(1));
587 for k in 1..=limit {
588 let (ak, bk) = self.coefficients[k];
589 let arg = 2.0 * std::f64::consts::PI * (k as f64) * x / t;
590 s += ak * arg.cos() + bk * arg.sin();
591 }
592 s
593 }
594 pub fn parseval_identity(&self) -> f64 {
596 let (a0, _) = self.coefficients.first().copied().unwrap_or((0.0, 0.0));
597 let mut s = a0 * a0 / 4.0;
598 for &(ak, bk) in self.coefficients.iter().skip(1) {
599 s += 0.5 * (ak * ak + bk * bk);
600 }
601 s
602 }
603 pub fn dirichlet_kernel(&self) -> f64 {
605 let n = self.coefficients.len();
606 let x = 0.1_f64;
607 let num = ((n as f64 + 0.5) * x).sin();
608 let den = (x / 2.0).sin();
609 if den.abs() < 1e-15 {
610 (2 * n + 1) as f64
611 } else {
612 num / den
613 }
614 }
615}
616#[allow(dead_code)]
618#[derive(Debug, Clone)]
619pub struct FourierRestrictionData {
620 pub manifold: String,
622 pub dimension: usize,
624 pub stein_tomas_p: f64,
626}
627#[allow(dead_code)]
628impl FourierRestrictionData {
629 pub fn new(manifold: &str, dim: usize) -> Self {
631 let n = dim as f64;
632 let p0 = 2.0 * (n + 1.0) / (n - 1.0);
633 FourierRestrictionData {
634 manifold: manifold.to_string(),
635 dimension: dim,
636 stein_tomas_p: p0,
637 }
638 }
639 pub fn stein_tomas_statement(&self) -> String {
641 format!(
642 "Stein-Tomas: R_{{{}}}: L^{{p'}} → L^2(S) for p' <= {:.3}",
643 self.manifold, self.stein_tomas_p
644 )
645 }
646 pub fn decoupling_description(&self) -> String {
648 format!(
649 "Bourgain-Demeter decoupling for {} in R^{}",
650 self.manifold, self.dimension
651 )
652 }
653 pub fn endpoint_holds(&self) -> bool {
655 false
656 }
657}
658pub struct FourierTransform {
660 pub is_continuous: bool,
662}
663impl FourierTransform {
664 pub fn new(is_continuous: bool) -> Self {
666 Self { is_continuous }
667 }
668 pub fn fourier_inversion(&self) -> bool {
670 true
671 }
672 pub fn plancherel_theorem(&self) -> bool {
674 true
675 }
676 pub fn riemann_lebesgue(&self) -> bool {
678 self.is_continuous
679 }
680}
681#[allow(dead_code)]
683#[derive(Debug, Clone)]
684pub struct MultilinearCZData {
685 pub m: usize,
687 pub name: String,
689 pub is_bounded: bool,
691}
692#[allow(dead_code)]
693impl MultilinearCZData {
694 pub fn new(name: &str, m: usize) -> Self {
696 MultilinearCZData {
697 m,
698 name: name.to_string(),
699 is_bounded: true,
700 }
701 }
702 pub fn holder_exponent(exponents: &[f64]) -> f64 {
704 exponents.iter().map(|&p| 1.0 / p).sum()
705 }
706 pub fn leibniz_rule(&self) -> String {
708 format!("Product rule for {}: fractional differentiation", self.name)
709 }
710}
711pub struct Convolution {
713 pub f: String,
715 pub g: String,
717}
718impl Convolution {
719 pub fn new(f: impl Into<String>, g: impl Into<String>) -> Self {
721 Self {
722 f: f.into(),
723 g: g.into(),
724 }
725 }
726 pub fn is_commutative(&self) -> bool {
728 true
729 }
730 pub fn convolution_theorem(&self) -> bool {
732 true
733 }
734 pub fn young_inequality(&self) -> bool {
736 true
737 }
738}
739#[derive(Debug, Clone)]
746pub struct CalderonZygmundDecomp {
747 pub signal: Vec<f64>,
749 pub alpha: f64,
751}
752impl CalderonZygmundDecomp {
753 pub fn new(signal: Vec<f64>, alpha: f64) -> Self {
755 assert!(alpha > 0.0, "alpha must be positive");
756 CalderonZygmundDecomp { signal, alpha }
757 }
758 pub fn bad_intervals(&self) -> Vec<(usize, usize)> {
762 let n = self.signal.len();
763 if n == 0 {
764 return vec![];
765 }
766 let mut bad = Vec::new();
767 let mut i = 0;
768 while i < n {
769 let mut len = 1;
770 let mut found = false;
771 while i + len <= n {
772 let avg: f64 = self.signal[i..i + len].iter().sum::<f64>() / len as f64;
773 if avg > self.alpha {
774 bad.push((i, i + len - 1));
775 found = true;
776 break;
777 }
778 len += 1;
779 }
780 if !found {
781 i += 1;
782 } else {
783 i += len;
784 }
785 }
786 bad
787 }
788 pub fn good_part(&self) -> Vec<f64> {
790 let bad = self.bad_intervals();
791 self.signal
792 .iter()
793 .enumerate()
794 .map(|(i, &fi)| {
795 if bad.iter().any(|&(lo, hi)| i >= lo && i <= hi) {
796 self.alpha
797 } else {
798 fi
799 }
800 })
801 .collect()
802 }
803 pub fn bad_part(&self) -> Vec<f64> {
805 let g = self.good_part();
806 self.signal
807 .iter()
808 .zip(g.iter())
809 .map(|(&f, &gv)| f - gv)
810 .collect()
811 }
812 pub fn verify_decomposition(&self) -> bool {
814 let g = self.good_part();
815 let b = self.bad_part();
816 self.signal
817 .iter()
818 .zip(g.iter().zip(b.iter()))
819 .all(|(&f, (&gv, &bv))| (f - gv - bv).abs() < 1e-12)
820 }
821 pub fn good_part_bounded(&self) -> bool {
823 let g = self.good_part();
824 g.iter().all(|&v| v.abs() <= 2.0 * self.alpha + 1e-12)
825 }
826}
827pub struct LittlewoodPaley {
829 pub dyadic_blocks: Vec<String>,
831}
832impl LittlewoodPaley {
833 pub fn new(dyadic_blocks: Vec<String>) -> Self {
835 Self { dyadic_blocks }
836 }
837 pub fn lp_equivalence(&self) -> bool {
839 !self.dyadic_blocks.is_empty()
840 }
841 pub fn square_function(&self) -> usize {
843 self.dyadic_blocks.len()
844 }
845}
846pub struct WaveletTransform {
848 pub mother_wavelet: String,
850 pub num_levels: usize,
852}
853impl WaveletTransform {
854 pub fn new(mother_wavelet: impl Into<String>, num_levels: usize) -> Self {
856 Self {
857 mother_wavelet: mother_wavelet.into(),
858 num_levels,
859 }
860 }
861 pub fn continuous_wavelet(&self) -> bool {
863 true
864 }
865 pub fn discrete_wavelet(&self) -> Vec<usize> {
867 (0..self.num_levels).collect()
868 }
869 pub fn haar_wavelet(&self) -> bool {
871 self.mother_wavelet.to_lowercase().contains("haar")
872 }
873}
874pub struct WeightedNorm {
876 pub weight: String,
878 pub ap_condition: bool,
880}
881impl WeightedNorm {
882 pub fn new(weight: impl Into<String>, ap_condition: bool) -> Self {
884 Self {
885 weight: weight.into(),
886 ap_condition,
887 }
888 }
889 pub fn muckenhoupt_ap(&self) -> bool {
891 self.ap_condition
892 }
893 pub fn reverse_holder(&self) -> bool {
895 self.ap_condition
896 }
897}
898#[allow(dead_code)]
900#[derive(Debug, Clone)]
901pub struct MaximalFunctionData {
902 pub dimension: usize,
904 pub samples: Vec<f64>,
906}
907#[allow(dead_code)]
908impl MaximalFunctionData {
909 pub fn new(dimension: usize, samples: Vec<f64>) -> Self {
911 MaximalFunctionData { dimension, samples }
912 }
913 pub fn hl_maximal_at(&self, i: usize, r: usize) -> f64 {
916 if self.samples.is_empty() {
917 return 0.0;
918 }
919 let lo = i.saturating_sub(r);
920 let hi = (i + r).min(self.samples.len() - 1);
921 let window = &self.samples[lo..=hi];
922 window.iter().copied().fold(f64::NEG_INFINITY, f64::max)
923 }
924 pub fn weak_type_bound_approx(&self, lambda: f64) -> f64 {
926 if lambda <= 0.0 {
927 return self.samples.len() as f64;
928 }
929 let l1_norm: f64 = self.samples.iter().map(|&x| x.abs()).sum();
930 l1_norm / lambda
931 }
932 pub fn lp_norm_estimate(&self, p: f64) -> f64 {
934 if p <= 1.0 {
935 return f64::INFINITY;
936 }
937 let lp_norm: f64 = self
938 .samples
939 .iter()
940 .map(|&x| x.abs().powf(p))
941 .sum::<f64>()
942 .powf(1.0 / p);
943 let cp = p / (p - 1.0);
944 cp * lp_norm
945 }
946}