use super::functions::*;
use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
pub struct MultiplierOperator {
pub symbol: String,
pub is_bounded: bool,
}
impl MultiplierOperator {
pub fn new(symbol: impl Into<String>, is_bounded: bool) -> Self {
Self {
symbol: symbol.into(),
is_bounded,
}
}
pub fn lp_boundedness(&self) -> bool {
self.is_bounded
}
pub fn hormander_condition(&self) -> bool {
self.is_bounded
}
}
pub struct HardySpace {
pub p: f64,
pub is_real_variable: bool,
}
impl HardySpace {
pub fn new(p: f64, is_real_variable: bool) -> Self {
Self {
p,
is_real_variable,
}
}
pub fn atomic_decomposition(&self) -> bool {
self.p <= 1.0
}
pub fn duality_with_bmo(&self) -> bool {
(self.p - 1.0).abs() < 1e-12
}
}
pub struct GroupHarmonic {
pub group_type: String,
}
impl GroupHarmonic {
pub fn new(group_type: impl Into<String>) -> Self {
Self {
group_type: group_type.into(),
}
}
pub fn representation_theory_connection(&self) -> bool {
true
}
pub fn peter_weyl(&self) -> bool {
self.group_type.to_lowercase().contains("compact")
}
}
#[derive(Debug, Clone)]
pub struct HardySpaceAtom {
pub lo: usize,
pub hi: usize,
pub values: Vec<f64>,
}
impl HardySpaceAtom {
pub fn new(lo: usize, hi: usize, values: Vec<f64>) -> Self {
HardySpaceAtom { lo, hi, values }
}
pub fn support_length(&self) -> usize {
if self.hi >= self.lo {
self.hi - self.lo + 1
} else {
0
}
}
pub fn has_compact_support(&self) -> bool {
self.values
.iter()
.enumerate()
.filter(|&(i, _)| i < self.lo || i > self.hi)
.all(|(_, &v)| v.abs() < 1e-12)
}
pub fn satisfies_linfty_bound(&self) -> bool {
let len = self.support_length();
if len == 0 {
return true;
}
let bound = 1.0 / len as f64;
self.values.iter().all(|&v| v.abs() <= bound + 1e-12)
}
pub fn has_zero_mean(&self) -> bool {
let sum: f64 = self.values.iter().sum();
sum.abs() < 1e-10
}
pub fn is_valid_atom(&self) -> bool {
self.has_compact_support() && self.satisfies_linfty_bound() && self.has_zero_mean()
}
pub fn canonical(signal_len: usize, lo: usize, hi: usize) -> Self {
let mut values = vec![0.0f64; signal_len];
let len = if hi >= lo { hi - lo + 1 } else { 0 };
if len < 2 {
return HardySpaceAtom { lo, hi, values };
}
let weight = 1.0 / len as f64;
let mid = lo + len / 2;
for i in lo..mid {
if i < signal_len {
values[i] = weight;
}
}
for i in mid..=hi {
if i < signal_len {
values[i] = -weight;
}
}
HardySpaceAtom { lo, hi, values }
}
}
#[derive(Debug, Clone)]
pub struct LittlewoodPaleySquare {
pub signal: Vec<f64>,
}
impl LittlewoodPaleySquare {
pub fn new(signal: Vec<f64>) -> Self {
LittlewoodPaleySquare { signal }
}
fn dft(signal: &[f64]) -> Vec<(f64, f64)> {
let n = signal.len();
if n == 0 {
return vec![];
}
let two_pi_over_n = 2.0 * std::f64::consts::PI / n as f64;
(0..n)
.map(|k| {
signal
.iter()
.enumerate()
.fold((0.0, 0.0), |(re, im), (j, &x)| {
let angle = two_pi_over_n * (k * j) as f64;
(re + x * angle.cos(), im - x * angle.sin())
})
})
.collect()
}
fn idft(spectrum: &[(f64, f64)]) -> Vec<f64> {
let n = spectrum.len();
if n == 0 {
return vec![];
}
let two_pi_over_n = 2.0 * std::f64::consts::PI / n as f64;
let n_f = n as f64;
(0..n)
.map(|j| {
spectrum
.iter()
.enumerate()
.map(|(k, &(re, im))| {
let angle = two_pi_over_n * (k * j) as f64;
(re * angle.cos() - im * angle.sin()) / n_f
})
.sum()
})
.collect()
}
pub fn square_function_pointwise(&self) -> Vec<f64> {
let n = self.signal.len();
if n == 0 {
return vec![];
}
let spectrum = Self::dft(&self.signal);
let mut sum_sq = vec![0.0f64; n];
let mut j = 1usize;
while j < n {
let lo = j;
let hi = (2 * j).min(n);
let mut block_spectrum: Vec<(f64, f64)> = vec![(0.0, 0.0); n];
for k in lo..hi {
block_spectrum[k] = spectrum[k];
let mirror = n - k;
if mirror < n && mirror != k {
block_spectrum[mirror] = spectrum[mirror];
}
}
let block_signal = Self::idft(&block_spectrum);
for i in 0..n {
sum_sq[i] += block_signal[i] * block_signal[i];
}
j = hi;
if hi >= n {
break;
}
}
sum_sq.iter().map(|&s| s.sqrt()).collect()
}
pub fn l2_norm_squared(&self) -> f64 {
self.square_function_pointwise()
.iter()
.map(|&v| v * v)
.sum()
}
pub fn signal_l2_norm_squared(&self) -> f64 {
self.signal.iter().map(|&x| x * x).sum()
}
pub fn verify_lp_inequality(&self) -> (f64, f64, f64) {
let sq_norm = self.l2_norm_squared();
let sig_norm = self.signal_l2_norm_squared();
let ratio = if sig_norm > 1e-15 {
sq_norm / sig_norm
} else {
1.0
};
(sq_norm, sig_norm, ratio)
}
}
#[derive(Debug, Clone)]
pub struct FourierMultiplierOp {
pub symbol: Vec<f64>,
}
impl FourierMultiplierOp {
pub fn new(symbol: Vec<f64>) -> Self {
FourierMultiplierOp { symbol }
}
pub fn hilbert_multiplier(n: usize) -> Self {
let mut symbol = vec![0.0f64; n];
for k in 1..n / 2 {
symbol[k] = 1.0;
}
for k in n / 2..n {
symbol[k] = -1.0;
}
FourierMultiplierOp { symbol }
}
pub fn low_pass(n: usize, cutoff: usize) -> Self {
let mut symbol = vec![0.0f64; n];
for k in 0..=cutoff.min(n - 1) {
symbol[k] = 1.0;
}
for k in (n - cutoff).min(n)..n {
symbol[k] = 1.0;
}
FourierMultiplierOp { symbol }
}
pub fn apply(&self, signal: &[f64]) -> Vec<f64> {
let n = signal.len();
assert_eq!(n, self.symbol.len());
if n == 0 {
return vec![];
}
let two_pi_over_n = 2.0 * std::f64::consts::PI / n as f64;
let spectrum: Vec<(f64, f64)> = (0..n)
.map(|k| {
signal
.iter()
.enumerate()
.fold((0.0, 0.0), |(re, im), (j, &x)| {
let angle = two_pi_over_n * (k * j) as f64;
(re + x * angle.cos(), im - x * angle.sin())
})
})
.collect();
let filtered: Vec<(f64, f64)> = spectrum
.iter()
.zip(self.symbol.iter())
.map(|(&(re, im), &m)| (re * m, im * m))
.collect();
let n_f = n as f64;
(0..n)
.map(|j| {
filtered
.iter()
.enumerate()
.map(|(k, &(re, im))| {
let angle = two_pi_over_n * (k * j) as f64;
(re * angle.cos() - im * angle.sin()) / n_f
})
.sum()
})
.collect()
}
pub fn l2_operator_norm(&self) -> f64 {
self.symbol.iter().fold(0.0_f64, |acc, &m| acc.max(m.abs()))
}
pub fn is_l2_bounded(&self) -> bool {
self.l2_operator_norm().is_finite()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CalderonZygmundOperator {
pub name: String,
pub l2_bounded: bool,
pub kernel_order: f64,
pub dimension: usize,
}
#[allow(dead_code)]
impl CalderonZygmundOperator {
pub fn new(name: &str, dim: usize) -> Self {
CalderonZygmundOperator {
name: name.to_string(),
l2_bounded: true,
kernel_order: 0.0,
dimension: dim,
}
}
pub fn hilbert_transform() -> Self {
CalderonZygmundOperator::new("H", 1)
}
pub fn riesz_transform(j: usize, n: usize) -> Self {
CalderonZygmundOperator::new(&format!("R_{j}"), n)
}
pub fn lp_boundedness(&self, p: f64) -> bool {
self.l2_bounded && p > 1.0 && p < f64::INFINITY
}
pub fn weak_type_one_one(&self) -> bool {
self.l2_bounded
}
pub fn cotlar_stein_description(&self) -> String {
format!(
"Cotlar-Stein for {}: almost orthogonal sum bounded on L^2",
self.name
)
}
pub fn t1_theorem_condition(&self) -> String {
format!(
"T(1) theorem: {} bounded on L^2 iff T(1), T^*(1) ∈ BMO",
self.name
)
}
}
pub struct LPSquareFunction {
pub signal: Vec<f64>,
}
impl LPSquareFunction {
pub fn new(signal: Vec<f64>) -> Self {
Self { signal }
}
pub fn square_function_pointwise(&self) -> Vec<f64> {
let n = self.signal.len();
if n == 0 {
return vec![];
}
let spectrum = dft(&self.signal);
let mut sum_sq = vec![0.0f64; n];
let mut j = 1usize;
while j < n {
let lo = j;
let hi = (2 * j).min(n);
let mut block_spectrum: Vec<(f64, f64)> = vec![(0.0, 0.0); n];
for k in lo..hi {
block_spectrum[k] = spectrum[k];
let mirror = n - k;
if mirror < n && mirror != k {
block_spectrum[mirror] = spectrum[mirror];
}
}
let block_signal = idft(&block_spectrum);
for i in 0..n {
sum_sq[i] += block_signal[i] * block_signal[i];
}
j = hi;
if hi >= n {
break;
}
}
sum_sq.iter().map(|&s| s.sqrt()).collect()
}
pub fn l2_norm_squared(&self) -> f64 {
self.square_function_pointwise()
.iter()
.map(|&v| v * v)
.sum()
}
}
pub struct CalderonZygmund {
pub kernel: String,
pub is_singular: bool,
}
impl CalderonZygmund {
pub fn new(kernel: impl Into<String>, is_singular: bool) -> Self {
Self {
kernel: kernel.into(),
is_singular,
}
}
pub fn lp_estimate(&self) -> bool {
true
}
pub fn endpoint_l1(&self) -> bool {
true
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct OscillatoryIntegralData {
pub phase: String,
pub amplitude: String,
pub frequency: f64,
pub dim: usize,
}
#[allow(dead_code)]
impl OscillatoryIntegralData {
pub fn new(phase: &str, amplitude: &str, lambda: f64, dim: usize) -> Self {
OscillatoryIntegralData {
phase: phase.to_string(),
amplitude: amplitude.to_string(),
frequency: lambda,
dim,
}
}
pub fn stationary_phase_decay(&self) -> f64 {
self.frequency.powf(-(self.dim as f64) / 2.0)
}
pub fn van_der_corput_bound(&self, k: usize) -> f64 {
self.frequency.powf(-1.0 / k as f64)
}
pub fn strichartz_description(&self) -> String {
format!(
"Strichartz: ||e^{{it∆}}f||_{{L^p_t L^q_x}} <= C ||f||_{{L^2}} (n={})",
self.dim
)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct BMOData {
pub values: Vec<f64>,
pub bmo_seminorm: f64,
}
#[allow(dead_code)]
impl BMOData {
pub fn new(values: Vec<f64>) -> Self {
let seminorm = Self::compute_bmo_seminorm(&values);
BMOData {
values,
bmo_seminorm: seminorm,
}
}
fn compute_bmo_seminorm(values: &[f64]) -> f64 {
if values.is_empty() {
return 0.0;
}
let mean: f64 = values.iter().sum::<f64>() / values.len() as f64;
let dev: f64 = values.iter().map(|&x| (x - mean).abs()).sum::<f64>() / values.len() as f64;
dev
}
pub fn john_nirenberg_constant(&self) -> f64 {
if self.bmo_seminorm < 1e-14 {
0.0
} else {
1.0 / self.bmo_seminorm
}
}
pub fn is_vmo_approx(&self, tol: f64) -> bool {
self.bmo_seminorm < tol
}
}
pub struct FourierSeries {
pub period: f64,
pub coefficients: Vec<(f64, f64)>,
}
impl FourierSeries {
pub fn new(period: f64, coefficients: Vec<(f64, f64)>) -> Self {
Self {
period,
coefficients,
}
}
pub fn partial_sum(&self, n: usize, x: f64) -> f64 {
let t = self.period;
let (a0, _b0) = self.coefficients.first().copied().unwrap_or((0.0, 0.0));
let mut s = a0 / 2.0;
let limit = n.min(self.coefficients.len().saturating_sub(1));
for k in 1..=limit {
let (ak, bk) = self.coefficients[k];
let arg = 2.0 * std::f64::consts::PI * (k as f64) * x / t;
s += ak * arg.cos() + bk * arg.sin();
}
s
}
pub fn parseval_identity(&self) -> f64 {
let (a0, _) = self.coefficients.first().copied().unwrap_or((0.0, 0.0));
let mut s = a0 * a0 / 4.0;
for &(ak, bk) in self.coefficients.iter().skip(1) {
s += 0.5 * (ak * ak + bk * bk);
}
s
}
pub fn dirichlet_kernel(&self) -> f64 {
let n = self.coefficients.len();
let x = 0.1_f64;
let num = ((n as f64 + 0.5) * x).sin();
let den = (x / 2.0).sin();
if den.abs() < 1e-15 {
(2 * n + 1) as f64
} else {
num / den
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct FourierRestrictionData {
pub manifold: String,
pub dimension: usize,
pub stein_tomas_p: f64,
}
#[allow(dead_code)]
impl FourierRestrictionData {
pub fn new(manifold: &str, dim: usize) -> Self {
let n = dim as f64;
let p0 = 2.0 * (n + 1.0) / (n - 1.0);
FourierRestrictionData {
manifold: manifold.to_string(),
dimension: dim,
stein_tomas_p: p0,
}
}
pub fn stein_tomas_statement(&self) -> String {
format!(
"Stein-Tomas: R_{{{}}}: L^{{p'}} → L^2(S) for p' <= {:.3}",
self.manifold, self.stein_tomas_p
)
}
pub fn decoupling_description(&self) -> String {
format!(
"Bourgain-Demeter decoupling for {} in R^{}",
self.manifold, self.dimension
)
}
pub fn endpoint_holds(&self) -> bool {
false
}
}
pub struct FourierTransform {
pub is_continuous: bool,
}
impl FourierTransform {
pub fn new(is_continuous: bool) -> Self {
Self { is_continuous }
}
pub fn fourier_inversion(&self) -> bool {
true
}
pub fn plancherel_theorem(&self) -> bool {
true
}
pub fn riemann_lebesgue(&self) -> bool {
self.is_continuous
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MultilinearCZData {
pub m: usize,
pub name: String,
pub is_bounded: bool,
}
#[allow(dead_code)]
impl MultilinearCZData {
pub fn new(name: &str, m: usize) -> Self {
MultilinearCZData {
m,
name: name.to_string(),
is_bounded: true,
}
}
pub fn holder_exponent(exponents: &[f64]) -> f64 {
exponents.iter().map(|&p| 1.0 / p).sum()
}
pub fn leibniz_rule(&self) -> String {
format!("Product rule for {}: fractional differentiation", self.name)
}
}
pub struct Convolution {
pub f: String,
pub g: String,
}
impl Convolution {
pub fn new(f: impl Into<String>, g: impl Into<String>) -> Self {
Self {
f: f.into(),
g: g.into(),
}
}
pub fn is_commutative(&self) -> bool {
true
}
pub fn convolution_theorem(&self) -> bool {
true
}
pub fn young_inequality(&self) -> bool {
true
}
}
#[derive(Debug, Clone)]
pub struct CalderonZygmundDecomp {
pub signal: Vec<f64>,
pub alpha: f64,
}
impl CalderonZygmundDecomp {
pub fn new(signal: Vec<f64>, alpha: f64) -> Self {
assert!(alpha > 0.0, "alpha must be positive");
CalderonZygmundDecomp { signal, alpha }
}
pub fn bad_intervals(&self) -> Vec<(usize, usize)> {
let n = self.signal.len();
if n == 0 {
return vec![];
}
let mut bad = Vec::new();
let mut i = 0;
while i < n {
let mut len = 1;
let mut found = false;
while i + len <= n {
let avg: f64 = self.signal[i..i + len].iter().sum::<f64>() / len as f64;
if avg > self.alpha {
bad.push((i, i + len - 1));
found = true;
break;
}
len += 1;
}
if !found {
i += 1;
} else {
i += len;
}
}
bad
}
pub fn good_part(&self) -> Vec<f64> {
let bad = self.bad_intervals();
self.signal
.iter()
.enumerate()
.map(|(i, &fi)| {
if bad.iter().any(|&(lo, hi)| i >= lo && i <= hi) {
self.alpha
} else {
fi
}
})
.collect()
}
pub fn bad_part(&self) -> Vec<f64> {
let g = self.good_part();
self.signal
.iter()
.zip(g.iter())
.map(|(&f, &gv)| f - gv)
.collect()
}
pub fn verify_decomposition(&self) -> bool {
let g = self.good_part();
let b = self.bad_part();
self.signal
.iter()
.zip(g.iter().zip(b.iter()))
.all(|(&f, (&gv, &bv))| (f - gv - bv).abs() < 1e-12)
}
pub fn good_part_bounded(&self) -> bool {
let g = self.good_part();
g.iter().all(|&v| v.abs() <= 2.0 * self.alpha + 1e-12)
}
}
pub struct LittlewoodPaley {
pub dyadic_blocks: Vec<String>,
}
impl LittlewoodPaley {
pub fn new(dyadic_blocks: Vec<String>) -> Self {
Self { dyadic_blocks }
}
pub fn lp_equivalence(&self) -> bool {
!self.dyadic_blocks.is_empty()
}
pub fn square_function(&self) -> usize {
self.dyadic_blocks.len()
}
}
pub struct WaveletTransform {
pub mother_wavelet: String,
pub num_levels: usize,
}
impl WaveletTransform {
pub fn new(mother_wavelet: impl Into<String>, num_levels: usize) -> Self {
Self {
mother_wavelet: mother_wavelet.into(),
num_levels,
}
}
pub fn continuous_wavelet(&self) -> bool {
true
}
pub fn discrete_wavelet(&self) -> Vec<usize> {
(0..self.num_levels).collect()
}
pub fn haar_wavelet(&self) -> bool {
self.mother_wavelet.to_lowercase().contains("haar")
}
}
pub struct WeightedNorm {
pub weight: String,
pub ap_condition: bool,
}
impl WeightedNorm {
pub fn new(weight: impl Into<String>, ap_condition: bool) -> Self {
Self {
weight: weight.into(),
ap_condition,
}
}
pub fn muckenhoupt_ap(&self) -> bool {
self.ap_condition
}
pub fn reverse_holder(&self) -> bool {
self.ap_condition
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MaximalFunctionData {
pub dimension: usize,
pub samples: Vec<f64>,
}
#[allow(dead_code)]
impl MaximalFunctionData {
pub fn new(dimension: usize, samples: Vec<f64>) -> Self {
MaximalFunctionData { dimension, samples }
}
pub fn hl_maximal_at(&self, i: usize, r: usize) -> f64 {
if self.samples.is_empty() {
return 0.0;
}
let lo = i.saturating_sub(r);
let hi = (i + r).min(self.samples.len() - 1);
let window = &self.samples[lo..=hi];
window.iter().copied().fold(f64::NEG_INFINITY, f64::max)
}
pub fn weak_type_bound_approx(&self, lambda: f64) -> f64 {
if lambda <= 0.0 {
return self.samples.len() as f64;
}
let l1_norm: f64 = self.samples.iter().map(|&x| x.abs()).sum();
l1_norm / lambda
}
pub fn lp_norm_estimate(&self, p: f64) -> f64 {
if p <= 1.0 {
return f64::INFINITY;
}
let lp_norm: f64 = self
.samples
.iter()
.map(|&x| x.abs().powf(p))
.sum::<f64>()
.powf(1.0 / p);
let cp = p / (p - 1.0);
cp * lp_norm
}
}