Skip to main content

evolving_sheaf/
flow.rs

1/// Flow energy functions that drive the evolution of restriction maps.
2pub type FlowFn = fn(edge_idx: usize, t: f64) -> f64;
3
4/// Constant flow: always returns 1.0.
5pub fn flow_constant(_edge: usize, _t: f64) -> f64 {
6    1.0
7}
8
9/// Sinusoidal flow: 1.0 + 0.5·sin(0.5·t + edge·0.3).
10pub fn flow_sinusoidal(edge: usize, t: f64) -> f64 {
11    1.0 + 0.5 * (0.5 * t + edge as f64 * 0.3).sin()
12}
13
14/// Pulse flow: alternates between high (3.0) and low (0.5).
15pub fn flow_pulse(edge: usize, t: f64) -> f64 {
16    let period = 4.0;
17    let phase = t.rem_euclid(period);
18    let pw = 0.3 + 0.05 * (edge % 5) as f64;
19    if phase < pw { 3.0 } else { 0.5 }
20}
21
22/// A deterministic "random" walk based on a hash-like seed.
23pub fn flow_random_walk(edge: usize, t: f64) -> f64 {
24    let seed = (t * 100.0) as i64 + edge as i64 * 137;
25    // Simple deterministic hash
26    let s = (seed.wrapping_mul(2654435761)) as u64;
27    let s = ((s >> 16) ^ s).wrapping_mul(0x45d9f3b);
28    let s = ((s >> 16) ^ s).wrapping_mul(0x45d9f3b);
29    let s = (s >> 16) ^ s;
30    0.5 + (s & 0x7FFF_FFFF) as f64 / 0x7FFF_FFFF as f64
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn test_constant_flow() {
39        let v = flow_constant(0, 0.0);
40        assert!((v - 1.0).abs() < 1e-12);
41        let v = flow_constant(5, 100.0);
42        assert!((v - 1.0).abs() < 1e-12);
43    }
44
45    #[test]
46    fn test_sinusoidal_range() {
47        for edge in 0..10 {
48            for t in [0.0, 1.0, 10.0, 100.0] {
49                let v = flow_sinusoidal(edge, t);
50                assert!(v >= 0.5 && v <= 1.5, "sinusoidal in [0.5, 1.5]");
51            }
52        }
53    }
54
55    #[test]
56    fn test_pulse_oscillation() {
57        let v_low = flow_pulse(0, 0.0);
58        let v_high = flow_pulse(0, 0.15);
59        let v_low2 = flow_pulse(0, 2.0);
60        assert!(v_high >= v_low, "pulse has high and low phases");
61        assert!((v_low - 0.5).abs() < 1e-6 || (v_low - 3.0).abs() < 1e-6);
62        assert!((v_low2 - 0.5).abs() < 1e-6);
63    }
64
65    #[test]
66    fn test_random_walk_range() {
67        for edge in 0..5 {
68            for t in [0.0, 1.0, 10.0] {
69                let v = flow_random_walk(edge, t);
70                assert!(v >= 0.5 && v < 1.5, "random walk in [0.5, 1.5)");
71            }
72        }
73    }
74
75    #[test]
76    fn test_random_walk_deterministic() {
77        let v1 = flow_random_walk(3, 7.0);
78        let v2 = flow_random_walk(3, 7.0);
79        assert!((v1 - v2).abs() < 1e-12, "deterministic walk");
80    }
81}