maple_runtime/fabrics/
coupling.rs1use crate::allocator::AttentionAllocator;
6use crate::runtime_core::DecouplingResult;
7use crate::types::*;
8use dashmap::DashMap;
9use petgraph::graph::{DiGraph, NodeIndex};
10use std::sync::Arc;
11use tokio::sync::RwLock;
12
13pub struct CouplingFabric {
15 couplings: DashMap<CouplingId, Coupling>,
17
18 graph: Arc<RwLock<CouplingGraph>>,
20
21 attention: Arc<AttentionAllocator>,
23
24 config: CouplingConfig,
26}
27
28struct CouplingGraph {
29 graph: DiGraph<ResonatorId, CouplingId>,
30 node_map: std::collections::HashMap<ResonatorId, NodeIndex>,
31}
32
33impl CouplingGraph {
34 fn new() -> Self {
35 Self {
36 graph: DiGraph::new(),
37 node_map: std::collections::HashMap::new(),
38 }
39 }
40
41 fn add_node(&mut self, resonator: ResonatorId) -> NodeIndex {
42 if let Some(&node) = self.node_map.get(&resonator) {
43 return node;
44 }
45
46 let node = self.graph.add_node(resonator);
47 self.node_map.insert(resonator, node);
48 node
49 }
50
51 fn add_edge(&mut self, coupling: &Coupling) {
52 let source_node = self.add_node(coupling.source);
53 let target_node = self.add_node(coupling.target);
54 self.graph.add_edge(source_node, target_node, coupling.id);
55 }
56
57 fn remove_edge(&mut self, coupling_id: &CouplingId) {
58 if let Some(edge_index) = self
59 .graph
60 .edge_indices()
61 .find(|&e| self.graph[e] == *coupling_id)
62 {
63 self.graph.remove_edge(edge_index);
64 }
65 }
66}
67
68impl CouplingFabric {
69 pub fn new(config: &CouplingConfig, attention: Arc<AttentionAllocator>) -> Self {
70 Self {
71 couplings: DashMap::new(),
72 graph: Arc::new(RwLock::new(CouplingGraph::new())),
73 attention,
74 config: config.clone(),
75 }
76 }
77
78 pub async fn register(&self, resonator: &ResonatorId) -> Result<(), String> {
80 let mut graph = self.graph.write().await;
81 graph.add_node(*resonator);
82 Ok(())
83 }
84
85 pub async fn establish_coupling(
92 &self,
93 params: CouplingParams,
94 ) -> Result<(CouplingId, AllocationToken), CouplingError> {
95 params
97 .validate()
98 .map_err(|e| CouplingError::ValidationFailed(e.to_string()))?;
99
100 let attention_available = self
102 .attention
103 .available_for_coupling(¶ms.source)
104 .await?;
105
106 if attention_available < params.initial_attention_cost {
107 return Err(CouplingError::InsufficientAttention {
108 requested: params.initial_attention_cost,
109 available: attention_available,
110 });
111 }
112
113 if params.initial_strength > self.config.max_initial_strength {
116 return Err(CouplingError::TooAggressiveInitialStrength);
117 }
118
119 let attention_token = self
121 .attention
122 .allocate(¶ms.source, params.initial_attention_cost)
123 .await?;
124
125 let coupling = Coupling {
127 id: CouplingId::generate(),
128 source: params.source,
129 target: params.target,
130 strength: params.initial_strength,
131 persistence: params.persistence,
132 scope: params.scope,
133 symmetry: params.symmetry,
134 attention_allocated: params.initial_attention_cost,
135 meaning_convergence: 0.0,
136 interaction_count: 0,
137 created_at: TemporalAnchor::now(),
138 last_resonance: TemporalAnchor::now(),
139 };
140
141 let coupling_id = coupling.id;
142
143 self.graph.write().await.add_edge(&coupling);
145 self.couplings.insert(coupling.id, coupling.clone());
146
147 tracing::debug!(
148 "Established coupling {} -> {} (strength: {})",
149 params.source,
150 params.target,
151 params.initial_strength
152 );
153
154 Ok((coupling_id, attention_token))
155 }
156
157 pub async fn strengthen(
159 &self,
160 coupling_id: CouplingId,
161 delta: f64,
162 ) -> Result<(), CouplingError> {
163 if delta > self.config.max_strengthening_rate {
165 return Err(CouplingError::StrengtheningTooRapid);
166 }
167
168 if let Some(mut coupling) = self.couplings.get_mut(&coupling_id) {
169 let new_strength = (coupling.strength + delta).min(1.0);
170 coupling.strength = new_strength;
171
172 let additional_attention = (delta * 10.0) as u64;
174 self.attention
175 .allocate_more(&coupling.source, additional_attention)
176 .await?;
177 coupling.attention_allocated += additional_attention;
178
179 tracing::debug!("Strengthened coupling {} to {}", coupling_id, new_strength);
180 }
181
182 Ok(())
183 }
184
185 pub async fn weaken(&self, coupling_id: CouplingId, factor: f64) -> Result<(), CouplingError> {
187 if let Some(mut coupling) = self.couplings.get_mut(&coupling_id) {
188 coupling.strength *= 1.0 - factor;
189
190 let attention_release = (coupling.attention_allocated as f64 * factor) as u64;
192 self.attention
193 .release_partial(&coupling.source, attention_release)
194 .await;
195 coupling.attention_allocated -= attention_release;
196
197 tracing::debug!("Weakened coupling {} by factor {}", coupling_id, factor);
198 }
199
200 Ok(())
201 }
202
203 pub async fn decouple_safely(
208 &self,
209 coupling_id: CouplingId,
210 ) -> Result<DecouplingResult, CouplingError> {
211 let coupling = self
212 .couplings
213 .get(&coupling_id)
214 .ok_or(CouplingError::NotFound)?
215 .clone();
216
217 self.graph.write().await.remove_edge(&coupling_id);
222
223 self.attention
225 .release_all(&coupling.source, coupling.attention_allocated)
226 .await;
227
228 self.couplings.remove(&coupling_id);
230
231 tracing::debug!("Decoupled {}", coupling_id);
232
233 Ok(DecouplingResult::Success)
234 }
235
236 pub fn get_coupling(&self, id: &CouplingId) -> Option<Coupling> {
238 self.couplings.get(id).map(|r| r.clone())
239 }
240
241 pub fn get_couplings_for(&self, resonator: &ResonatorId) -> Vec<Coupling> {
243 self.couplings
244 .iter()
245 .filter(|entry| entry.source == *resonator || entry.target == *resonator)
246 .map(|entry| entry.clone())
247 .collect()
248 }
249
250 pub async fn restore_couplings(
252 &self,
253 _resonator: &ResonatorId,
254 couplings: &[Coupling],
255 ) -> Result<(), String> {
256 for coupling in couplings {
257 self.graph.write().await.add_edge(coupling);
258 self.couplings.insert(coupling.id, coupling.clone());
259 }
260
261 tracing::debug!("Restored {} couplings", couplings.len());
262 Ok(())
263 }
264
265 pub async fn persist_topology(&self) -> Result<(), String> {
267 tracing::info!("Persisting {} couplings", self.couplings.len());
269 Ok(())
270 }
271
272 pub fn count(&self) -> usize {
274 self.couplings.len()
275 }
276}