use scirs2_core::ndarray::{s, Array1, Array2, Array3, Array4, Array5, ArrayView1, ArrayView2};
use scirs2_core::numeric::Complex;
use scirs2_core::numeric::{Float, FromPrimitive, Zero};
use std::collections::{HashMap, VecDeque};
use std::f64::consts::PI;
use std::sync::{Arc, RwLock};
use super::config::*;
use crate::error::NdimageResult;
#[derive(Debug, Clone)]
pub struct ConsciousnessState {
pub level: f64,
pub coherence_quality: f64,
pub phi_measure: f64,
pub attention_strength: f64,
pub self_awareness: f64,
pub timestamp: usize,
}
#[derive(Debug, Clone)]
pub struct ConsciousnessComplexity {
pub integrated_information: f64,
pub causal_complexity: f64,
pub temporal_coherence: f64,
pub hierarchical_index: f64,
pub emergence_strength: f64,
}
#[derive(Debug, Clone)]
pub enum CoherenceStrategy {
ErrorCorrection {
threshold: f64,
correction_rate: f64,
},
DecoherenceSuppression { suppression_strength: f64 },
EntanglementPurification { purification_cycles: usize },
DynamicalDecoupling { pulse_frequency: f64 },
QuantumZeno { measurement_frequency: f64 },
}
#[derive(Debug, Clone)]
pub struct QuantumCoherenceOptimizer {
pub strategies: Vec<CoherenceStrategy>,
pub optimization_params: HashMap<String, f64>,
pub performancehistory: VecDeque<f64>,
}
#[derive(Debug, Clone)]
pub struct QuantumConsciousnessEvolution {
pub evolutionhistory: VecDeque<ConsciousnessState>,
pub evolution_rate: f64,
pub complexitymetrics: ConsciousnessComplexity,
pub coherence_optimizer: QuantumCoherenceOptimizer,
pub selection_pressure: f64,
pub emergence_threshold: f64,
}
impl Default for QuantumConsciousnessEvolution {
fn default() -> Self {
Self {
evolutionhistory: VecDeque::new(),
evolution_rate: 0.01,
complexitymetrics: ConsciousnessComplexity {
integrated_information: 0.0,
causal_complexity: 0.0,
temporal_coherence: 0.0,
hierarchical_index: 0.0,
emergence_strength: 0.0,
},
coherence_optimizer: QuantumCoherenceOptimizer {
strategies: vec![
CoherenceStrategy::ErrorCorrection {
threshold: 0.95,
correction_rate: 0.1,
},
CoherenceStrategy::DecoherenceSuppression {
suppression_strength: 0.8,
},
CoherenceStrategy::EntanglementPurification {
purification_cycles: 5,
},
],
optimization_params: HashMap::new(),
performancehistory: VecDeque::new(),
},
selection_pressure: 0.1,
emergence_threshold: 0.7,
}
}
}
#[allow(dead_code)]
pub fn simulate_quantum_consciousness(
advancedfeatures: &Array5<f64>,
advancedstate: &mut AdvancedState,
config: &AdvancedConfig,
) -> NdimageResult<Array2<f64>> {
let (height, width, dimensions, temporal, consciousness) = advancedfeatures.dim();
let mut consciousness_output = Array2::zeros((height, width));
let shape_mismatch =
advancedstate.consciousness_amplitudes.dim() != (height, width, consciousness, 2);
let amplitudes_all_zero = advancedstate
.consciousness_amplitudes
.iter()
.all(|c| c.norm() < 1e-12);
let needs_init = shape_mismatch || amplitudes_all_zero;
if needs_init {
advancedstate.consciousness_amplitudes = Array4::zeros((height, width, consciousness, 2));
let amplitude = Complex::new((1.0 / consciousness as f64).sqrt(), 0.0);
advancedstate.consciousness_amplitudes.fill(amplitude);
}
for y in 0..height {
for x in 0..width {
let mut consciousness_amplitude = Complex::new(0.0, 0.0);
for c in 0..consciousness {
let mut feature_vector = Vec::new();
for d in 0..dimensions {
for t in 0..temporal {
feature_vector.push(advancedfeatures[(y, x, d, t, c)]);
}
}
let quantumstate = apply_quantum_consciousness_operators(
&feature_vector,
&advancedstate
.consciousness_amplitudes
.slice(s![y, x, c, ..]),
config,
)?;
advancedstate.consciousness_amplitudes[(y, x, c, 0)] =
Complex::new(quantumstate.re, 0.0);
advancedstate.consciousness_amplitudes[(y, x, c, 1)] =
Complex::new(quantumstate.im, 0.0);
consciousness_amplitude += quantumstate;
}
let consciousness_probability = consciousness_amplitude.norm_sqr();
consciousness_output[(y, x)] = consciousness_probability;
}
}
apply_global_consciousness_coherence(&mut consciousness_output, advancedstate, config)?;
apply_temporal_causal_inference(&mut consciousness_output, advancedstate, config)?;
Ok(consciousness_output)
}
#[allow(dead_code)]
fn apply_quantum_consciousness_operators(
feature_vector: &[f64],
consciousnessstate: &ArrayView1<Complex<f64>>,
config: &AdvancedConfig,
) -> NdimageResult<Complex<f64>> {
if feature_vector.is_empty() || consciousnessstate.is_empty() {
return Ok(Complex::new(0.0, 0.0));
}
let mut quantumstate = Complex::new(0.0, 0.0);
let feature_norm = feature_vector
.iter()
.map(|&x| x * x)
.sum::<f64>()
.sqrt()
.max(1e-10);
let normalizedfeatures: Vec<f64> = feature_vector.iter().map(|&x| x / feature_norm).collect();
for (i, &feature) in normalizedfeatures.iter().enumerate() {
if i < consciousnessstate.len() {
let phase = feature * PI * config.quantum.phase_factor;
let amplitude = (feature.abs() / config.consciousness_depth as f64).sqrt();
let existingstate = consciousnessstate[i % consciousnessstate.len()];
let cos_phase = phase.cos();
let sin_phase = phase.sin();
let rotated_real = existingstate.re * cos_phase - existingstate.im * sin_phase;
let rotated_imag = existingstate.re * sin_phase + existingstate.im * cos_phase;
quantumstate += Complex::new(rotated_real, rotated_imag) * amplitude;
}
}
let entanglement_factor = config.quantum.entanglement_strength;
let entangled_phase = normalizedfeatures.iter().sum::<f64>() * PI * entanglement_factor;
let entanglement_rotation = Complex::new(entangled_phase.cos(), entangled_phase.sin());
quantumstate *= entanglement_rotation;
let consciousness_depth_factor =
1.0 / (1.0 + (-(config.consciousness_depth as f64) * 0.1).exp());
quantumstate *= consciousness_depth_factor;
let decoherence_factor = (1.0 - config.quantum.decoherence_rate).max(0.1);
quantumstate *= decoherence_factor;
let norm = quantumstate.norm();
if norm > 1e-10 {
quantumstate /= norm;
}
Ok(quantumstate)
}
#[allow(dead_code)]
fn apply_global_consciousness_coherence(
consciousness_output: &mut Array2<f64>,
advancedstate: &AdvancedState,
config: &AdvancedConfig,
) -> NdimageResult<()> {
let phi = calculate_simplified_phi_measure(advancedstate, config)?;
let gamma = config.quantum.decoherence_rate.max(0.0);
let damping = (-gamma * phi).exp();
consciousness_output.mapv_inplace(|x| x * damping);
Ok(())
}
#[allow(dead_code)]
pub fn enhanced_quantum_consciousness_evolution<T>(
image: ArrayView2<T>,
advancedfeatures: &Array5<f64>,
advancedstate: &mut AdvancedState,
config: &AdvancedConfig,
evolution_system: &mut QuantumConsciousnessEvolution,
) -> NdimageResult<Array2<f64>>
where
T: Float + FromPrimitive + Copy,
{
let (height, width, dimensions, temporal, consciousness) = advancedfeatures.dim();
let mut consciousness_output = Array2::zeros((height, width));
let currentstate = analyze_consciousnessstate(advancedstate, config)?;
evolve_consciousness_parameters(evolution_system, ¤tstate, config)?;
for y in 0..height {
for x in 0..width {
let mut evolved_consciousness_amplitude = Complex::new(0.0, 0.0);
for c in 0..consciousness {
let mut feature_vector = Vec::new();
for d in 0..dimensions {
for t in 0..temporal {
feature_vector.push(advancedfeatures[(y, x, d, t, c)]);
}
}
let evolved_quantumstate = apply_evolved_quantum_consciousness_operators(
&feature_vector,
&advancedstate
.consciousness_amplitudes
.slice(s![y, x, c, ..]),
config,
evolution_system,
)?;
advancedstate.consciousness_amplitudes[(y, x, c, 0)] =
Complex::new(evolved_quantumstate.re, 0.0);
advancedstate.consciousness_amplitudes[(y, x, c, 1)] =
Complex::new(evolved_quantumstate.im, 0.0);
evolved_consciousness_amplitude += evolved_quantumstate;
}
let evolved_response = apply_consciousness_evolution_selection(
evolved_consciousness_amplitude,
evolution_system,
(y, x),
config,
)?;
consciousness_output[(y, x)] = evolved_response;
}
}
apply_evolved_global_consciousness_coherence(
&mut consciousness_output,
advancedstate,
evolution_system,
config,
)?;
update_consciousness_evolutionhistory(evolution_system, ¤tstate)?;
Ok(consciousness_output)
}
#[allow(dead_code)]
fn analyze_consciousnessstate(
advancedstate: &AdvancedState,
config: &AdvancedConfig,
) -> NdimageResult<ConsciousnessState> {
let total_amplitudes = advancedstate.consciousness_amplitudes.len() as f64;
let coherence_sum = advancedstate
.consciousness_amplitudes
.iter()
.map(|&| amp.norm())
.sum::<f64>();
let consciousness_level = if total_amplitudes > 0.0 {
coherence_sum / total_amplitudes
} else {
0.0
};
let coherence_variance = advancedstate
.consciousness_amplitudes
.iter()
.map(|&| {
let norm = amp.norm();
(norm - consciousness_level).powi(2)
})
.sum::<f64>()
/ total_amplitudes.max(1.0);
let coherence_quality = 1.0 / (1.0 + coherence_variance);
let phi_measure = calculate_simplified_phi_measure(advancedstate, config)?;
let attention_strength = {
let topology = advancedstate
.network_topology
.read()
.expect("Operation failed");
topology.global_properties.coherence
};
let self_awareness = (consciousness_level * coherence_quality * phi_measure).cbrt();
Ok(ConsciousnessState {
level: consciousness_level,
coherence_quality,
phi_measure,
attention_strength,
self_awareness,
timestamp: advancedstate.temporal_memory.len(),
})
}
#[allow(dead_code)]
fn calculate_simplified_phi_measure(
advancedstate: &AdvancedState,
_config: &AdvancedConfig,
) -> NdimageResult<f64> {
let probs: Vec<f64> = advancedstate
.consciousness_amplitudes
.iter()
.map(|c| c.norm_sqr())
.collect();
let total: f64 = probs.iter().sum();
if total < 1e-12 || probs.len() < 2 {
return Ok(0.0);
}
let probs: Vec<f64> = probs.iter().map(|p| p / total).collect();
let n = probs.len();
let half = n / 2;
let p_left: f64 = probs[..half].iter().sum();
let h_left = if p_left > 1e-12 && p_left < 1.0 - 1e-12 {
let p_right_complement = 1.0 - p_left;
-p_left * p_left.ln() - p_right_complement * p_right_complement.ln()
} else {
0.0
};
let p_right: f64 = probs[half..].iter().sum();
let h_right = if p_right > 1e-12 && p_right < 1.0 - 1e-12 {
let p_left_complement = 1.0 - p_right;
-p_right * p_right.ln() - p_left_complement * p_left_complement.ln()
} else {
0.0
};
let h_joint: f64 = -probs
.iter()
.filter(|&&p| p > 1e-12)
.map(|&p| p * p.ln())
.sum::<f64>();
let phi = (h_left + h_right - h_joint).max(0.0);
Ok(phi.min(1.0))
}
#[allow(dead_code)]
fn evolve_consciousness_parameters(
evolution_system: &mut QuantumConsciousnessEvolution,
currentstate: &ConsciousnessState,
_config: &AdvancedConfig,
) -> NdimageResult<()> {
let consciousness_fitness = (currentstate.level
+ currentstate.coherence_quality
+ currentstate.phi_measure
+ currentstate.self_awareness)
/ 4.0;
if consciousness_fitness > evolution_system.emergence_threshold {
evolution_system.evolution_rate = (evolution_system.evolution_rate * 1.05).min(0.1);
evolution_system.selection_pressure =
(evolution_system.selection_pressure * 0.95).max(0.01);
} else {
evolution_system.evolution_rate = (evolution_system.evolution_rate * 0.95).max(0.001);
evolution_system.selection_pressure = (evolution_system.selection_pressure * 1.05).min(0.5);
}
evolution_system.complexitymetrics.integrated_information = currentstate.phi_measure;
evolution_system.complexitymetrics.temporal_coherence = currentstate.coherence_quality;
evolution_system.complexitymetrics.emergence_strength = consciousness_fitness;
evolve_coherence_strategies(
&mut evolution_system.coherence_optimizer,
consciousness_fitness,
)?;
Ok(())
}
#[allow(dead_code)]
fn evolve_coherence_strategies(
optimizer: &mut QuantumCoherenceOptimizer,
fitness: f64,
) -> NdimageResult<()> {
optimizer.performancehistory.push_back(fitness);
if optimizer.performancehistory.len() > 50 {
optimizer.performancehistory.pop_front();
}
let n = optimizer.performancehistory.len();
if n < 2 {
return Ok(());
}
let psi: Vec<f64> = optimizer.performancehistory.iter().cloned().collect();
let psi_norm: f64 = psi.iter().map(|x| x * x).sum::<f64>().sqrt();
if psi_norm < 1e-12 {
return Ok(());
}
let psi: Vec<f64> = psi.iter().map(|x| x / psi_norm).collect();
let dt = 0.01_f64;
let mut l_psi = vec![0.0_f64; n];
for i in 0..n {
let degree = if i == 0 || i == n - 1 { 1.0 } else { 2.0 };
let left = if i > 0 { psi[i - 1] } else { 0.0 };
let right = if i < n - 1 { psi[i + 1] } else { 0.0 };
l_psi[i] = degree * psi[i] - left - right;
}
let mut new_history: VecDeque<f64> = VecDeque::with_capacity(n);
for i in 0..n {
let new_norm = (psi[i] * psi[i] + (dt * l_psi[i]).powi(2)).sqrt();
new_history.push_back(new_norm);
}
optimizer.performancehistory = new_history;
Ok(())
}
#[allow(dead_code)]
fn apply_evolved_quantum_consciousness_operators(
feature_vector: &[f64],
consciousnessstate: &ArrayView1<Complex<f64>>,
config: &AdvancedConfig,
evolution_system: &QuantumConsciousnessEvolution,
) -> NdimageResult<Complex<f64>> {
let mut quantumstate =
apply_quantum_consciousness_operators(feature_vector, consciousnessstate, config)?;
let evolution_enhancement = Complex::new(
1.0 + evolution_system.evolution_rate
* evolution_system.complexitymetrics.emergence_strength,
evolution_system.selection_pressure * 0.1,
);
quantumstate *= evolution_enhancement;
let coherence_boost = 1.0
+ evolution_system
.coherence_optimizer
.performancehistory
.iter()
.sum::<f64>()
/ evolution_system
.coherence_optimizer
.performancehistory
.len()
.max(1) as f64;
quantumstate *= coherence_boost;
let norm = quantumstate.norm();
if norm > 1e-10 {
quantumstate /= norm;
}
Ok(quantumstate)
}
#[allow(dead_code)]
fn apply_consciousness_evolution_selection(
consciousness_amplitude: Complex<f64>,
evolution_system: &QuantumConsciousnessEvolution,
position: (usize, usize),
_config: &AdvancedConfig,
) -> NdimageResult<f64> {
let base_probability = consciousness_amplitude.norm_sqr();
let selection_factor = 1.0
+ evolution_system.selection_pressure
* (evolution_system.complexitymetrics.emergence_strength - 0.5);
let spatial_coherence = 1.0 + 0.1 * ((position.0 + position.1) as f64 * 0.01).sin();
let evolved_probability = base_probability * selection_factor * spatial_coherence;
Ok(evolved_probability.min(1.0))
}
#[allow(dead_code)]
fn apply_evolved_global_consciousness_coherence(
consciousness_output: &mut Array2<f64>,
advancedstate: &AdvancedState,
evolution_system: &QuantumConsciousnessEvolution,
config: &AdvancedConfig,
) -> NdimageResult<()> {
let evolved_coherence = evolution_system
.coherence_optimizer
.performancehistory
.back()
.cloned()
.unwrap_or(evolution_system.complexitymetrics.temporal_coherence);
let phi = calculate_simplified_phi_measure(advancedstate, config)?;
let gamma = config.quantum.decoherence_rate.max(0.0);
let (height, width) = consciousness_output.dim();
for y in 0..height {
for x in 0..width {
let spatial_mod = (1.0
+ 0.05
* ((y as f64 / height.max(1) as f64) * PI).sin()
* ((x as f64 / width.max(1) as f64) * PI).cos())
.abs();
let local_phi = (phi * spatial_mod).min(1.0);
let local_damping = (-gamma * local_phi).exp();
let scale = local_damping * (1.0 + evolved_coherence * 0.05);
consciousness_output[(y, x)] *= scale;
}
}
Ok(())
}
#[allow(dead_code)]
fn update_consciousness_evolutionhistory(
evolution_system: &mut QuantumConsciousnessEvolution,
currentstate: &ConsciousnessState,
) -> NdimageResult<()> {
evolution_system
.evolutionhistory
.push_back(currentstate.clone());
if evolution_system.evolutionhistory.len() > 100 {
evolution_system.evolutionhistory.pop_front();
}
Ok(())
}
pub(crate) fn apply_temporal_causal_inference(
consciousness_output: &mut Array2<f64>,
state: &AdvancedState,
config: &AdvancedConfig,
) -> NdimageResult<()> {
let (height, width) = consciousness_output.dim();
if height == 0 || width == 0 || state.causal_graph.is_empty() {
return Ok(());
}
let tau = config.temporal_window.max(1) as f64;
let causal_depth = config.causal_depth as f64;
let alpha = (causal_depth / (causal_depth + tau)).clamp(0.0, 1.0);
let snapshot = consciousness_output.clone();
let lagged_value = |source_id: usize, delay: usize| -> f64 {
let sy = source_id / width;
let sx = source_id % width;
if sy >= height || sx >= width {
return 0.0;
}
if delay == 0 || state.temporal_memory.is_empty() {
return snapshot[(sy, sx)];
}
let len = state.temporal_memory.len();
let lag = delay.min(len);
let idx = len - lag;
let frame = &state.temporal_memory[idx];
let (fh, fw, _fd) = frame.dim();
if sy < fh && sx < fw {
frame[(sy, sx, 0)]
} else {
snapshot[(sy, sx)]
}
};
let mut influence = vec![(0.0_f64, 0.0_f64, 0.0_f64); height * width];
for relations in state.causal_graph.values() {
for relation in relations {
if relation.target >= influence.len() {
continue;
}
let raw = relation.strength.abs() * relation.confidence.clamp(0.0, 1.0);
if raw <= 0.0 {
continue;
}
let decay = (-(relation.delay as f64) / tau).exp();
let weight = raw * decay;
let source_activity = lagged_value(relation.source, relation.delay);
let (ref mut acc, ref mut total_w, ref mut total_raw) = influence[relation.target];
*acc += weight * source_activity;
*total_w += weight;
*total_raw += raw;
}
}
for y in 0..height {
for x in 0..width {
let id = y * width + x;
let (acc, total_w, total_raw) = influence[id];
if total_w > 1e-12 && total_raw > 1e-12 {
let influence_norm = acc / total_w;
let mean_decay = (total_w / total_raw).clamp(0.0, 1.0);
let effective_alpha = (alpha * mean_decay).clamp(0.0, 1.0);
let current = snapshot[(y, x)];
let updated = (1.0 - effective_alpha) * current + effective_alpha * influence_norm;
consciousness_output[(y, x)] = if updated.is_finite() {
updated.max(0.0)
} else {
current
};
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use scirs2_core::ndarray::{Array1, Array2, Array3, Array4};
use scirs2_core::numeric::Complex;
use std::collections::{BTreeMap, VecDeque};
use std::sync::{Arc, RwLock};
fn make_test_state(amplitudes: Array4<Complex<f64>>) -> AdvancedState {
use scirs2_core::ndarray::Array5;
AdvancedState {
consciousness_amplitudes: amplitudes,
meta_parameters: Array2::zeros((4, 4)),
network_topology: Arc::new(RwLock::new(NetworkTopology {
connections: std::collections::HashMap::new(),
nodes: Vec::new(),
global_properties: NetworkProperties {
coherence: 0.5,
self_organization_index: 0.3,
consciousness_emergence: 0.2,
efficiency: 0.8,
},
})),
temporal_memory: VecDeque::new(),
causal_graph: BTreeMap::new(),
advancedfeatures: Array5::zeros((1, 1, 1, 1, 1)),
resource_allocation: ResourceState {
cpu_allocation: vec![0.5],
memory_allocation: 0.5,
gpu_allocation: None,
quantum_allocation: None,
allocationhistory: VecDeque::new(),
},
efficiencymetrics: EfficiencyMetrics {
ops_per_second: 1000.0,
memory_efficiency: 0.8,
energy_efficiency: 0.6,
quality_efficiency: 0.75,
temporal_efficiency: 0.9,
},
processing_cycles: 0,
}
}
#[test]
fn test_phi_measure_nonnegative() {
let mut amps = Array4::zeros((4, 4, 2, 2));
for (i, v) in amps.iter_mut().enumerate() {
*v = Complex::new((i as f64 * 0.1).sin(), (i as f64 * 0.1).cos());
}
let state = make_test_state(amps);
let config = AdvancedConfig::default();
let phi =
calculate_simplified_phi_measure(&state, &config).expect("phi measure should not fail");
assert!(phi >= 0.0, "phi must be non-negative, got {}", phi);
}
#[test]
fn test_phi_measure_zero_for_uniform_state() {
let amps = Array4::from_elem((4, 4, 2, 2), Complex::new(1.0, 0.0));
let state = make_test_state(amps);
let config = AdvancedConfig::default();
let phi =
calculate_simplified_phi_measure(&state, &config).expect("phi measure should not fail");
assert!(
phi < 1e-10,
"phi should be near 0 for uniform distribution, got {}",
phi
);
}
#[test]
fn test_quantum_walk_step_preserves_probability() {
let mut optimizer = QuantumCoherenceOptimizer {
strategies: Vec::new(),
optimization_params: std::collections::HashMap::new(),
performancehistory: VecDeque::new(),
};
for i in 0..10_usize {
evolve_coherence_strategies(&mut optimizer, 0.1 * i as f64)
.expect("evolve should not fail");
}
let history: Vec<f64> = optimizer.performancehistory.iter().cloned().collect();
assert!(!history.is_empty(), "history should not be empty");
for &v in &history {
assert!(
v.is_finite() && v >= 0.0,
"quantum walk output should be finite non-negative, got {}",
v
);
}
}
fn make_relation(
source: usize,
target: usize,
strength: f64,
delay: usize,
confidence: f64,
) -> CausalRelation {
CausalRelation {
source,
target,
strength,
delay,
confidence,
}
}
#[test]
fn test_temporal_causal_inference_empty_graph_is_noop() {
let amps = Array4::from_elem((2, 2, 1, 2), Complex::new(0.5, 0.0));
let state = make_test_state(amps); let config = AdvancedConfig::default();
let mut output = Array2::from_shape_fn((4, 4), |(y, x)| 0.1 * (y + x) as f64);
let before = output.clone();
apply_temporal_causal_inference(&mut output, &state, &config)
.expect("temporal causal inference should not fail");
assert_eq!(
before, output,
"empty causal graph must leave field unchanged"
);
}
#[test]
fn test_temporal_causal_inference_blends_toward_source() {
let amps = Array4::from_elem((2, 2, 1, 2), Complex::new(0.5, 0.0));
let mut state = make_test_state(amps);
let config = AdvancedConfig::default();
let width = 4usize;
let source_id = 0usize;
let target_id = 1usize;
state.causal_graph.insert(
source_id,
vec![make_relation(source_id, target_id, 1.0, 0, 1.0)],
);
let mut output = Array2::<f64>::zeros((1, width));
output[(0, 0)] = 1.0; output[(0, 1)] = 0.0; let source_val = output[(0, 0)];
let target_before = output[(0, 1)];
apply_temporal_causal_inference(&mut output, &state, &config)
.expect("temporal causal inference should not fail");
let target_after = output[(0, 1)];
assert!(
(output[(0, 0)] - source_val).abs() < 1e-12,
"source pixel must be unaffected"
);
assert!(
target_after > target_before,
"target should increase toward source, before={} after={}",
target_before,
target_after
);
assert!(
target_after <= source_val + 1e-12,
"blended value must not exceed source value, got {}",
target_after
);
assert!(
target_after.is_finite() && target_after >= 0.0,
"output must be finite and non-negative, got {}",
target_after
);
let tau = config.temporal_window.max(1) as f64;
let causal_depth = config.causal_depth as f64;
let alpha = causal_depth / (causal_depth + tau);
let expected = (1.0 - alpha) * target_before + alpha * source_val;
assert!(
(target_after - expected).abs() < 1e-10,
"blend mismatch: expected {} got {}",
expected,
target_after
);
}
#[test]
fn test_temporal_causal_inference_delay_monotonic_decay() {
let config = AdvancedConfig::default();
let width = 4usize;
let source_id = 0usize;
let target_id = 1usize;
let run_for_delay = |delay: usize| -> f64 {
let amps = Array4::from_elem((2, 2, 1, 2), Complex::new(0.5, 0.0));
let mut state = make_test_state(amps);
state.causal_graph.insert(
source_id,
vec![make_relation(source_id, target_id, 1.0, delay, 1.0)],
);
for _ in 0..16 {
let mut frame = Array3::<f64>::zeros((1, width, 1));
frame[(0, 0, 0)] = 1.0; state.temporal_memory.push_back(frame);
}
let mut output = Array2::<f64>::zeros((1, width));
output[(0, 0)] = 1.0;
output[(0, 1)] = 0.0;
apply_temporal_causal_inference(&mut output, &state, &config)
.expect("temporal causal inference should not fail");
output[(0, 1)]
};
let near = run_for_delay(1);
let far = run_for_delay(8);
assert!(near > 0.0 && far > 0.0, "both should increase the target");
assert!(
near > far,
"shorter delay should yield stronger influence: near(delay=1)={} far(delay=8)={}",
near,
far
);
}
}