use scirs2_core::ndarray::{Array2, Array3, ArrayView2};
use scirs2_core::numeric::{Float, FromPrimitive};
use std::cmp::Ordering;
use std::collections::{BTreeMap, VecDeque};
use super::config::*;
use crate::error::NdimageResult;
#[allow(dead_code)]
pub fn analyze_temporal_causality<T>(
image: &ArrayView2<T>,
advancedstate: &mut AdvancedState,
config: &AdvancedConfig,
) -> NdimageResult<Array2<f64>>
where
T: Float + FromPrimitive + Copy,
{
let (height, width) = image.dim();
let mut causal_output = Array2::zeros((height, width));
let current_temporal = image_to_temporal_representation(image)?;
advancedstate
.temporal_memory
.push_back(current_temporal.clone());
while advancedstate.temporal_memory.len() > config.temporal_window {
advancedstate.temporal_memory.pop_front();
}
if advancedstate.temporal_memory.len() >= config.causal_depth {
for y in 0..height {
for x in 0..width {
let pixel_id = y * width + x;
let temporal_sequence =
extract_pixel_temporal_sequence(&advancedstate.temporal_memory, (y, x))?;
let causal_relationships =
detect_causal_relationships(&temporal_sequence, pixel_id, config)?;
advancedstate
.causal_graph
.insert(pixel_id, causal_relationships.clone());
let causal_influence = calculate_causal_influence(
&causal_relationships,
&advancedstate.causal_graph,
config,
)?;
causal_output[(y, x)] = causal_influence;
}
}
}
Ok(causal_output)
}
#[allow(dead_code)]
fn image_to_temporal_representation<T>(image: &ArrayView2<T>) -> NdimageResult<Array3<f64>>
where
T: Float + FromPrimitive + Copy,
{
let (height, width) = image.dim();
let mut temporal_features = Array3::zeros((height, width, 4));
for y in 0..height {
for x in 0..width {
let pixel_val = image[(y, x)].to_f64().unwrap_or(0.0);
temporal_features[(y, x, 0)] = pixel_val;
let h_grad = if x > 0 && x < width - 1 {
let left = image[(y, x - 1)].to_f64().unwrap_or(0.0);
let right = image[(y, x + 1)].to_f64().unwrap_or(0.0);
(right - left) / 2.0
} else {
0.0
};
temporal_features[(y, x, 1)] = h_grad;
let v_grad = if y > 0 && y < height - 1 {
let up = image[(y - 1, x)].to_f64().unwrap_or(0.0);
let down = image[(y + 1, x)].to_f64().unwrap_or(0.0);
(down - up) / 2.0
} else {
0.0
};
temporal_features[(y, x, 2)] = v_grad;
let mut local_vals = Vec::new();
for dy in -1..=1i32 {
for dx in -1..=1i32 {
let ny = y as i32 + dy;
let nx = x as i32 + dx;
if ny >= 0 && ny < height as i32 && nx >= 0 && nx < width as i32 {
let val = image[(ny as usize, nx as usize)].to_f64().unwrap_or(0.0);
local_vals.push(val);
}
}
}
let local_variance = if local_vals.len() > 1 {
let mean = local_vals.iter().sum::<f64>() / local_vals.len() as f64;
local_vals.iter().map(|&v| (v - mean).powi(2)).sum::<f64>()
/ local_vals.len() as f64
} else {
0.0
};
temporal_features[(y, x, 3)] = local_variance;
}
}
Ok(temporal_features)
}
#[allow(dead_code)]
fn extract_pixel_temporal_sequence(
temporal_memory: &VecDeque<Array3<f64>>,
position: (usize, usize),
) -> NdimageResult<Vec<f64>> {
let (y, x) = position;
let mut sequence = Vec::new();
for frame in temporal_memory {
if y < frame.shape()[0] && x < frame.shape()[1] {
let mut pixel_features = Vec::new();
for feature_idx in 0..frame.shape()[2] {
pixel_features.push(frame[(y, x, feature_idx)]);
}
let combined_value = pixel_features
.iter()
.enumerate()
.map(|(i, &val)| val * (i as f64 + 1.0) / pixel_features.len() as f64)
.sum::<f64>();
sequence.push(combined_value);
}
}
while sequence.len() < 8 {
sequence.push(0.0);
}
Ok(sequence)
}
#[allow(dead_code)]
fn detect_causal_relationships(
temporal_sequence: &[f64],
pixel_id: usize,
config: &AdvancedConfig,
) -> NdimageResult<Vec<CausalRelation>> {
let mut causal_relations = Vec::new();
if temporal_sequence.len() < config.causal_depth {
return Ok(causal_relations);
}
for delay in 1..config.causal_depth.min(temporal_sequence.len() / 2) {
let mut cause_values = Vec::new();
let mut effect_values = Vec::new();
for i in delay..temporal_sequence.len() {
cause_values.push(temporal_sequence[i - delay]);
effect_values.push(temporal_sequence[i]);
}
if cause_values.len() < 3 {
continue;
}
let cause_mean = cause_values.iter().sum::<f64>() / cause_values.len() as f64;
let effect_mean = effect_values.iter().sum::<f64>() / effect_values.len() as f64;
let numerator: f64 = cause_values
.iter()
.zip(effect_values.iter())
.map(|(&c, &e)| (c - cause_mean) * (e - effect_mean))
.sum();
let cause_var: f64 = cause_values.iter().map(|&c| (c - cause_mean).powi(2)).sum();
let effect_var: f64 = effect_values
.iter()
.map(|&e| (e - effect_mean).powi(2))
.sum();
let denominator = (cause_var * effect_var).sqrt();
if denominator > 1e-10 {
let correlation = numerator / denominator;
let causal_strength = correlation.abs();
if causal_strength > 0.3 {
let confidence =
(causal_strength * (cause_values.len() as f64).ln() / 10.0).min(1.0);
let target_id = if correlation > 0.0 {
pixel_id + delay } else {
if pixel_id >= delay {
pixel_id - delay
} else {
pixel_id
} };
causal_relations.push(CausalRelation {
source: pixel_id,
target: target_id,
strength: causal_strength,
delay,
confidence,
});
}
}
}
for window_size in 2..=(config.causal_depth / 2).min(temporal_sequence.len() / 4) {
if temporal_sequence.len() < window_size * 2 {
continue;
}
let mut entropy_source = 0.0;
let mut entropy_target = 0.0;
let mut mutual_entropy = 0.0;
for i in window_size..temporal_sequence.len() - window_size {
let source_window = &temporal_sequence[i - window_size..i];
let target_window = &temporal_sequence[i..i + window_size];
let source_var = calculate_window_variance(source_window);
let target_var = calculate_window_variance(target_window);
entropy_source += source_var;
entropy_target += target_var;
let cross_corr = source_window
.iter()
.zip(target_window.iter())
.map(|(&s, &t)| s * t)
.sum::<f64>()
/ window_size as f64;
mutual_entropy += cross_corr.abs();
}
let n_windows = (temporal_sequence.len() - window_size * 2) as f64;
if n_windows > 0.0 {
entropy_source /= n_windows;
entropy_target /= n_windows;
mutual_entropy /= n_windows;
let transfer_entropy = mutual_entropy / (entropy_source + entropy_target + 1e-10);
if transfer_entropy > 0.2 {
let confidence = (transfer_entropy * n_windows.ln() / 5.0).min(1.0);
causal_relations.push(CausalRelation {
source: pixel_id,
target: pixel_id + window_size, strength: transfer_entropy,
delay: window_size,
confidence,
});
}
}
}
causal_relations.sort_by(|a, b| {
b.strength
.partial_cmp(&a.strength)
.unwrap_or(Ordering::Equal)
});
causal_relations.truncate(config.causal_depth / 2);
Ok(causal_relations)
}
#[allow(dead_code)]
fn calculate_causal_influence(
relationships: &[CausalRelation],
causal_graph: &BTreeMap<usize, Vec<CausalRelation>>,
_config: &AdvancedConfig,
) -> NdimageResult<f64> {
if relationships.is_empty() {
return Ok(0.0);
}
let direct_influence: f64 = relationships
.iter()
.map(|rel| rel.strength * rel.confidence)
.sum();
let mut indirect_influence = 0.0;
for relation in relationships {
if let Some(target_relations) = causal_graph.get(&relation.target) {
for target_rel in target_relations {
let distance_weight = 1.0 / (relation.delay as f64 + 1.0);
indirect_influence +=
target_rel.strength * target_rel.confidence * distance_weight * 0.5;
}
}
}
let total_influence = direct_influence + indirect_influence;
let normalized_influence = total_influence / (1.0 + total_influence);
Ok(normalized_influence)
}
#[allow(dead_code)]
fn calculate_window_variance(window: &[f64]) -> f64 {
if window.is_empty() {
return 0.0;
}
let mean = window.iter().sum::<f64>() / window.len() as f64;
let variance = window.iter().map(|&x| (x - mean).powi(2)).sum::<f64>() / window.len() as f64;
variance
}
#[allow(dead_code)]
pub fn analyze_multiscale_temporal_causality(
temporal_memory: &VecDeque<Array3<f64>>,
config: &AdvancedConfig,
) -> NdimageResult<Vec<Array2<f64>>> {
let mut scales_results = Vec::new();
if temporal_memory.is_empty() {
return Ok(scales_results);
}
let (height, width, _) = temporal_memory[0].dim();
for scale in 1..=3 {
let mut scale_result = Array2::zeros((height, width));
let step_size = scale * 2;
let mut scaled_memory = VecDeque::new();
for (i, frame) in temporal_memory.iter().enumerate() {
if i % step_size == 0 {
scaled_memory.push_back(frame.clone());
}
}
if scaled_memory.len() >= config.causal_depth / scale {
for y in 0..height {
for x in 0..width {
if let Ok(temporal_sequence) =
extract_pixel_temporal_sequence(&scaled_memory, (y, x))
{
let pixel_id = y * width + x;
if let Ok(relationships) =
detect_causal_relationships(&temporal_sequence, pixel_id, config)
{
let causal_strength: f64 = relationships
.iter()
.map(|rel| rel.strength * rel.confidence)
.sum();
scale_result[(y, x)] = causal_strength / (scale as f64);
}
}
}
}
}
scales_results.push(scale_result);
}
Ok(scales_results)
}
#[cfg(test)]
mod tests {
use super::*;
use scirs2_core::ndarray::Array2;
#[test]
fn test_calculate_window_variance() {
let window = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let variance = calculate_window_variance(&window);
assert!(variance > 0.0);
let empty_window = vec![];
let zero_variance = calculate_window_variance(&empty_window);
assert_eq!(zero_variance, 0.0);
}
#[test]
fn test_image_to_temporal_representation() {
let image = Array2::<f64>::zeros((10, 10));
let result = image_to_temporal_representation(&image.view());
assert!(result.is_ok());
let temporal_features = result.expect("Operation failed");
assert_eq!(temporal_features.dim(), (10, 10, 4));
}
#[test]
fn test_extract_pixel_temporal_sequence() {
let mut temporal_memory = VecDeque::new();
let frame1 = Array3::<f64>::zeros((5, 5, 4));
let frame2 = Array3::<f64>::ones((5, 5, 4));
temporal_memory.push_back(frame1);
temporal_memory.push_back(frame2);
let result = extract_pixel_temporal_sequence(&temporal_memory, (2, 2));
assert!(result.is_ok());
let sequence = result.expect("Operation failed");
assert!(!sequence.is_empty());
}
}