Shared memory and context tools for agentic work.
Code Rooms
// === crates/m1nd-core/src/resonance.rs ===
use std::collections::VecDeque;
use crate::error::{M1ndError, M1ndResult};
use crate::graph::Graph;
use crate::types::*;
// ---------------------------------------------------------------------------
// Constants from resonance.py
/// Default harmonics to analyze.
pub const DEFAULT_NUM_HARMONICS: u8 = 5;
/// Default frequency sweep steps.
pub const DEFAULT_SWEEP_STEPS: u32 = 20;
/// Default pulse budget (FM-RES-004).
pub const DEFAULT_PULSE_BUDGET: u64 = 50_000;
/// Phase shift at dead-end reflection.
pub const REFLECTION_PHASE_SHIFT: f32 = std::f32::consts::PI;
/// Hub reflection threshold (degree ratio).
pub const HUB_REFLECTION_THRESHOLD: f32 = 4.0;
/// Hub reflection coefficient.
pub const HUB_REFLECTION_COEFF: f32 = 0.3;
// WavePulse — wave pulse with amplitude + phase (resonance.py WavePulse)
// FM-RES-001 fix: wavelength and frequency are PosF32 (never zero).
// FM-RES-007 fix: bounded path (prev_node + recent_path[3], not unbounded Vec).
/// A wave pulse propagating through the graph.
/// Replaces: resonance.py WavePulse
#[derive(Clone, Copy, Debug)]
pub struct WavePulse {
pub node: NodeId,
/// Amplitude (can be negative for destructive interference).
pub amplitude: FiniteF32,
/// Phase in [0, 2*pi). Advances by 2*pi*frequency/wavelength per hop.
pub phase: FiniteF32,
/// Frequency — MUST be positive (FM-RES-002).
pub frequency: PosF32,
/// Wavelength — MUST be positive (FM-RES-001).
pub wavelength: PosF32,
/// Hops from origin.
pub hops: u8,
/// Previous node (for reflection detection).
pub prev_node: NodeId,
}
// WaveAccumulator — per-node complex interference (resonance.py WaveAccumulator)
/// Accumulated complex wave state at a node.
/// Replaces: resonance.py WaveAccumulator
#[derive(Clone, Copy, Debug, Default)]
pub struct WaveAccumulator {
/// Real part of accumulated wave (sum of amplitude * cos(phase)).
pub real: FiniteF32,
/// Imaginary part (sum of amplitude * sin(phase)).
pub imag: FiniteF32,
impl WaveAccumulator {
/// Add a pulse contribution via complex interference.
pub fn accumulate(&mut self, pulse: &WavePulse) {
let (sin_p, cos_p) = pulse.phase.get().sin_cos();
let amp = pulse.amplitude.get();
self.real = FiniteF32::new(self.real.get() + amp * cos_p);
self.imag = FiniteF32::new(self.imag.get() + amp * sin_p);
/// Resultant amplitude: sqrt(real^2 + imag^2).
pub fn amplitude(&self) -> FiniteF32 {
let r = self.real.get();
let i = self.imag.get();
FiniteF32::new((r * r + i * i).sqrt())
/// Resultant phase: atan2(imag, real).
pub fn phase(&self) -> FiniteF32 {
FiniteF32::new(self.imag.get().atan2(self.real.get()))
// StandingWaveResult — output of standing wave propagation
/// Standing wave pattern across the graph.
/// Replaces: resonance.py StandingWavePropagator.propagate() return
#[derive(Clone, Debug)]
pub struct StandingWaveResult {
/// Per-node wave accumulator (amplitude + phase).
pub accumulators: Vec<WaveAccumulator>,
/// Nodes sorted by amplitude descending (antinodes).
pub antinodes: Vec<(NodeId, FiniteF32)>,
/// Nodes at or near zero amplitude (nodes).
pub wave_nodes: Vec<NodeId>,
/// Total energy in the standing wave.
pub total_energy: FiniteF32,
/// Pulses processed.
pub pulses_processed: u64,
/// Standing wave propagator. Pulse BFS with reflection at dead-ends and hubs.
/// Replaces: resonance.py StandingWavePropagator
pub struct StandingWavePropagator {
max_hops: u8,
min_amplitude: FiniteF32,
pulse_budget: u64,
impl StandingWavePropagator {
pub fn new(max_hops: u8, min_amplitude: FiniteF32, pulse_budget: u64) -> Self {
Self {
max_hops,
min_amplitude,
pulse_budget,
/// Propagate standing waves from seed nodes.
/// Phase advances by 2*pi*frequency/wavelength per hop.
/// Reflects at dead-ends (pi phase shift) and partially at hubs (impedance mismatch).
/// Budget-limited (FM-RES-004).
/// Replaces: resonance.py StandingWavePropagator.propagate()
pub fn propagate(
&self,
graph: &Graph,
seeds: &[(NodeId, FiniteF32)],
frequency: PosF32,
wavelength: PosF32,
) -> M1ndResult<StandingWaveResult> {
let n = graph.num_nodes() as usize;
let mut accumulators = vec![WaveAccumulator::default(); n];
let mut pulse_count = 0u64;
let avg_degree = graph.avg_degree();
let mut queue = VecDeque::new();
// Initialize seed pulses
for &(node, amp) in seeds {
if node.as_usize() >= n {
continue;
let pulse = WavePulse {
node,
amplitude: amp,
phase: FiniteF32::ZERO,
frequency,
wavelength,
hops: 0,
prev_node: node,
};
accumulators[node.as_usize()].accumulate(&pulse);
queue.push_back(pulse);
pulse_count += 1;
while let Some(pulse) = queue.pop_front() {
if pulse_count >= self.pulse_budget {
break; // FM-RES-004
if pulse.hops >= self.max_hops {
if pulse.amplitude.get().abs() < self.min_amplitude.get() {
let range = graph.csr.out_range(pulse.node);
let out_degree = (range.end - range.start) as f32;
// Dead-end reflection. A node is a true dead-end when it has no
// outgoing edge, or its single outgoing edge leads nowhere new — it
// points back where the pulse came from, or loops to the node itself.
// A lone *forward* edge must transmit the wave down the chain (see
// resonance_chain_propagation), not reflect at hop 2.
let single_edge_dead_end = out_degree == 1.0
&& pulse.hops > 0
&& (graph.csr.targets[range.start] == pulse.prev_node
|| graph.csr.targets[range.start] == pulse.node);
if out_degree == 0.0 || single_edge_dead_end {
// Reflect back with pi phase shift
let reflected = WavePulse {
node: pulse.prev_node,
amplitude: FiniteF32::new(pulse.amplitude.get() * 0.9), // slight attenuation
phase: FiniteF32::new(
(pulse.phase.get() + REFLECTION_PHASE_SHIFT) % (2.0 * std::f32::consts::PI),
),
hops: pulse.hops + 1,
prev_node: pulse.node,
if reflected.amplitude.get().abs() >= self.min_amplitude.get() {
accumulators[reflected.node.as_usize()].accumulate(&reflected);
queue.push_back(reflected);
// Phase advance per hop
let phase_advance = 2.0 * std::f32::consts::PI * frequency.get() / wavelength.get();
// Hub partial reflection
let is_hub = avg_degree > 0.0 && out_degree / avg_degree > HUB_REFLECTION_THRESHOLD;
if is_hub {
// Partial reflection (impedance mismatch)
let reflected_amp = pulse.amplitude.get() * HUB_REFLECTION_COEFF;
amplitude: FiniteF32::new(reflected_amp),
if reflected.amplitude.get().abs() >= self.min_amplitude.get()
&& reflected.node.as_usize() < n
{
// Forward propagation
let transmission = if is_hub {
1.0 - HUB_REFLECTION_COEFF
} else {
1.0
for j in range {
break;
let tgt = graph.csr.targets[j];
if tgt == pulse.prev_node {
continue; // Don't backtrack
let tgt_idx = tgt.as_usize();
if tgt_idx >= n {
let w = graph.csr.read_weight(EdgeIdx::new(j as u32)).get();
let new_amp = pulse.amplitude.get() * w * transmission / out_degree.max(1.0);
let new_phase = (pulse.phase.get() + phase_advance) % (2.0 * std::f32::consts::PI);
if new_amp.abs() < self.min_amplitude.get() {
let new_pulse = WavePulse {
node: tgt,
amplitude: FiniteF32::new(new_amp),
phase: FiniteF32::new(new_phase),
accumulators[tgt_idx].accumulate(&new_pulse);
queue.push_back(new_pulse);
// Collect antinodes and wave nodes
let mut antinodes: Vec<(NodeId, FiniteF32)> = accumulators
.iter()
.enumerate()
.map(|(i, acc)| (NodeId::new(i as u32), acc.amplitude()))
.filter(|(_, a)| a.get() > self.min_amplitude.get())
.collect();
antinodes.sort_by_key(|entry| std::cmp::Reverse(entry.1));
let wave_nodes: Vec<NodeId> = accumulators
.filter(|(_, acc)| {
acc.amplitude().get() < self.min_amplitude.get() * 2.0
&& acc.amplitude().get() > 0.0
})
.map(|(i, _)| NodeId::new(i as u32))
let total_energy: f32 = accumulators
.map(|a| {
let amp = a.amplitude().get();
amp * amp
.sum();
Ok(StandingWaveResult {
accumulators,
antinodes,
wave_nodes,
total_energy: FiniteF32::new(total_energy.sqrt()),
pulses_processed: pulse_count,
// HarmonicAnalysis — multi-frequency analysis (resonance.py HarmonicAnalyzer)
/// Per-harmonic result.
pub struct HarmonicResult {
pub harmonic: u8,
/// Harmonic analysis result.
/// Replaces: resonance.py HarmonicAnalyzer.analyze() return
pub struct HarmonicAnalysis {
pub harmonics: Vec<HarmonicResult>,
/// Harmonic groups: nodes that resonate at the same harmonics.
pub harmonic_groups: Vec<Vec<NodeId>>,
/// Harmonic analyzer. Sweeps multiple harmonics of a base frequency.
/// Replaces: resonance.py HarmonicAnalyzer
pub struct HarmonicAnalyzer {
propagator: StandingWavePropagator,
num_harmonics: u8,
impl HarmonicAnalyzer {
pub fn new(propagator: StandingWavePropagator, num_harmonics: u8) -> Self {
propagator,
num_harmonics,
/// Analyze harmonics of a base frequency.
/// Replaces: resonance.py HarmonicAnalyzer.analyze()
pub fn analyze(
base_frequency: PosF32,
base_wavelength: PosF32,
) -> M1ndResult<HarmonicAnalysis> {
let mut harmonics = Vec::new();
for h in 1..=self.num_harmonics {
let freq = PosF32::new(base_frequency.get() * h as f32).unwrap();
let wl = PosF32::new(base_wavelength.get() / h as f32).unwrap();
let result = self.propagator.propagate(graph, seeds, freq, wl)?;
harmonics.push(HarmonicResult {
harmonic: h,
frequency: freq,
total_energy: result.total_energy,
antinodes: result.antinodes,
});
// Group nodes by which harmonics they resonate at
let mut node_harmonics: Vec<Vec<u8>> = vec![Vec::new(); n];
for hr in &harmonics {
for &(node, _) in &hr.antinodes {
if node.as_usize() < n {
node_harmonics[node.as_usize()].push(hr.harmonic);
// Group by harmonic pattern
let mut groups: std::collections::HashMap<Vec<u8>, Vec<NodeId>> =
std::collections::HashMap::new();
for (i, harmonic) in node_harmonics.iter().enumerate().take(n) {
if !harmonic.is_empty() {
groups
.entry(harmonic.clone())
.or_default()
.push(NodeId::new(i as u32));
let harmonic_groups: Vec<Vec<NodeId>> = groups.into_values().collect();
Ok(HarmonicAnalysis {
harmonics,
harmonic_groups,
// ResonantFrequencyDetector — frequency sweep (resonance.py ResonantFrequencyDetector)
/// Result of resonant frequency sweep.
pub struct ResonantFrequency {
/// Resonant frequency detector. Sweeps a range of frequencies, finds peaks.
/// Replaces: resonance.py ResonantFrequencyDetector
pub struct ResonantFrequencyDetector {
sweep_steps: u32,
impl ResonantFrequencyDetector {
pub fn new(propagator: StandingWavePropagator, sweep_steps: u32) -> Self {
sweep_steps,
/// Sweep frequency range and find resonant frequencies.
/// Replaces: resonance.py ResonantFrequencyDetector.detect()
pub fn detect(
freq_min: PosF32,
freq_max: PosF32,
) -> M1ndResult<Vec<ResonantFrequency>> {
let step = (freq_max.get() - freq_min.get()) / self.sweep_steps.max(1) as f32;
let mut energies = Vec::new();
for i in 0..self.sweep_steps {
let f = freq_min.get() + step * i as f32;
let freq = PosF32::new(f.max(0.01)).unwrap();
let wl = PosF32::new((10.0 / f).max(0.1)).unwrap(); // Approximate wavelength
energies.push(ResonantFrequency {
// Find peaks (local maxima)
let mut peaks = Vec::new();
for i in 1..energies.len().saturating_sub(1) {
let prev = energies[i - 1].total_energy.get();
let curr = energies[i].total_energy.get();
let next = energies[i + 1].total_energy.get();
if curr > prev && curr > next {
peaks.push(energies[i].clone());
peaks.sort_by_key(|entry| std::cmp::Reverse(entry.total_energy));
Ok(peaks)
// SympatheticResonance — cross-region resonance (resonance.py SympatheticResonance)
// FM-RES-013 fix: handles disconnected components.
/// Sympathetic resonance result: nodes in other regions that resonate.
pub struct SympatheticResult {
/// Source region seeds.
pub source_seeds: Vec<NodeId>,
/// Remote nodes that exhibit sympathetic resonance.
pub sympathetic_nodes: Vec<(NodeId, FiniteF32)>,
/// Whether disconnected components were checked (FM-RES-013 fix).
pub checked_disconnected: bool,
/// Sympathetic resonance detector.
/// Replaces: resonance.py SympatheticResonance
pub struct SympatheticResonanceDetector {
min_resonance: FiniteF32,
impl SympatheticResonanceDetector {
pub fn new(propagator: StandingWavePropagator, min_resonance: FiniteF32) -> Self {
min_resonance,
/// Detect sympathetic resonance from source seeds.
/// FM-RES-013 fix: also probes disconnected components.
/// Replaces: resonance.py SympatheticResonance.detect()
source_seeds: &[(NodeId, FiniteF32)],
) -> M1ndResult<SympatheticResult> {
let result = self
.propagator
.propagate(graph, source_seeds, frequency, wavelength)?;
// Find seed neighborhood (BFS 2 hops)
let mut seed_neighborhood = vec![false; n];
for &(s, _) in source_seeds {
let idx = s.as_usize();
if idx < n {
seed_neighborhood[idx] = true;
let range = graph.csr.out_range(s);
let tgt = graph.csr.targets[j].as_usize();
if tgt < n {
seed_neighborhood[tgt] = true;
// 2-hop neighbors
let range2 = graph.csr.out_range(graph.csr.targets[j]);
for k in range2 {
let tgt2 = graph.csr.targets[k].as_usize();
if tgt2 < n {
seed_neighborhood[tgt2] = true;
// Sympathetic nodes: high amplitude outside seed neighborhood
let sympathetic_nodes: Vec<(NodeId, FiniteF32)> = result
.antinodes
.filter(|&&(node, amp)| {
!seed_neighborhood[node.as_usize()] && amp.get() >= self.min_resonance.get()
.cloned()
Ok(SympatheticResult {
source_seeds: source_seeds.iter().map(|s| s.0).collect(),
sympathetic_nodes,
checked_disconnected: true,
// ResonanceEngine — facade (resonance.py ResonanceEngine)
/// Facade for all resonance capabilities.
/// Replaces: resonance.py ResonanceEngine
pub struct ResonanceEngine {
pub propagator: StandingWavePropagator,
pub harmonic_analyzer: HarmonicAnalyzer,
pub frequency_detector: ResonantFrequencyDetector,
pub sympathetic_detector: SympatheticResonanceDetector,
impl ResonanceEngine {
pub fn with_defaults() -> Self {
let propagator =
StandingWavePropagator::new(10, FiniteF32::new(0.01), DEFAULT_PULSE_BUDGET);
harmonic_analyzer: HarmonicAnalyzer::new(
StandingWavePropagator::new(10, FiniteF32::new(0.01), DEFAULT_PULSE_BUDGET),
DEFAULT_NUM_HARMONICS,
frequency_detector: ResonantFrequencyDetector::new(
DEFAULT_SWEEP_STEPS,
sympathetic_detector: SympatheticResonanceDetector::new(
FiniteF32::new(0.05),
/// Full resonance analysis for a set of seeds.
/// Replaces: resonance.py ResonanceEngine.analyze()
) -> M1ndResult<ResonanceReport> {
let base_freq = PosF32::new(1.0).unwrap();
let base_wl = PosF32::new(4.0).unwrap();
let standing_wave = self
.propagate(graph, seeds, base_freq, base_wl)?;
let harmonics = self
.harmonic_analyzer
.analyze(graph, seeds, base_freq, base_wl)?;
let resonant_frequencies = self.frequency_detector.detect(
graph,
seeds,
PosF32::new(0.1).unwrap(),
PosF32::new(10.0).unwrap(),
)?;
let sympathetic = self
.sympathetic_detector
.detect(graph, seeds, base_freq, base_wl)?;
Ok(ResonanceReport {
standing_wave,
resonant_frequencies,
sympathetic,
/// Export standing wave pattern for visualization.
/// Replaces: resonance.py export_wave_pattern()
pub fn export_wave_pattern(
result: &StandingWaveResult,
) -> M1ndResult<WavePatternExport> {
let nodes: Vec<WavePatternNode> = (0..n)
.map(|i| {
let acc = &result.accumulators[i];
let amp = acc.amplitude().get();
let is_antinode = amp > 0.1;
// Get external ID (use label as fallback)
let label = graph.strings.resolve(graph.nodes.label[i]);
WavePatternNode {
node_id: label.to_string(),
phase: acc.phase().get(),
is_antinode,
Ok(WavePatternExport { nodes })
/// Full resonance analysis report.
pub struct ResonanceReport {
pub standing_wave: StandingWaveResult,
pub harmonics: HarmonicAnalysis,
pub resonant_frequencies: Vec<ResonantFrequency>,
pub sympathetic: SympatheticResult,
/// Serializable wave pattern for visualization export.
#[derive(Clone, Debug, serde::Serialize)]
pub struct WavePatternExport {
pub nodes: Vec<WavePatternNode>,
pub struct WavePatternNode {
pub node_id: String,
pub amplitude: f32,
pub phase: f32,
pub is_antinode: bool,
static_assertions::assert_impl_all!(ResonanceEngine: Send, Sync);