maple_runtime/fabrics/
coupling.rs1use dashmap::DashMap;
6use std::sync::Arc;
7use tokio::sync::RwLock;
8use petgraph::graph::{DiGraph, NodeIndex};
9use crate::types::*;
10use crate::allocator::AttentionAllocator;
11use crate::runtime_core::CouplingHandle;
12use crate::runtime_core::DecouplingResult;
13
14
15pub struct CouplingFabric {
17 couplings: DashMap<CouplingId, Coupling>,
19
20 graph: Arc<RwLock<CouplingGraph>>,
22
23 attention: Arc<AttentionAllocator>,
25
26 config: CouplingConfig,
28}
29
30struct CouplingGraph {
31 graph: DiGraph<ResonatorId, CouplingId>,
32 node_map: std::collections::HashMap<ResonatorId, NodeIndex>,
33}
34
35impl CouplingGraph {
36 fn new() -> Self {
37 Self {
38 graph: DiGraph::new(),
39 node_map: std::collections::HashMap::new(),
40 }
41 }
42
43 fn add_node(&mut self, resonator: ResonatorId) -> NodeIndex {
44 if let Some(&node) = self.node_map.get(&resonator) {
45 return node;
46 }
47
48 let node = self.graph.add_node(resonator);
49 self.node_map.insert(resonator, node);
50 node
51 }
52
53 fn add_edge(&mut self, coupling: &Coupling) {
54 let source_node = self.add_node(coupling.source);
55 let target_node = self.add_node(coupling.target);
56 self.graph.add_edge(source_node, target_node, coupling.id);
57 }
58
59 fn remove_edge(&mut self, coupling_id: &CouplingId) {
60 if let Some(edge_index) = self
61 .graph
62 .edge_indices()
63 .find(|&e| self.graph[e] == *coupling_id)
64 {
65 self.graph.remove_edge(edge_index);
66 }
67 }
68}
69
70impl CouplingFabric {
71 pub fn new(config: &CouplingConfig, attention: Arc<AttentionAllocator>) -> Self {
72 Self {
73 couplings: DashMap::new(),
74 graph: Arc::new(RwLock::new(CouplingGraph::new())),
75 attention,
76 config: config.clone(),
77 }
78 }
79
80 pub async fn register(&self, resonator: &ResonatorId) -> Result<(), String> {
82 let mut graph = self.graph.write().await;
83 graph.add_node(*resonator);
84 Ok(())
85 }
86
87 pub async fn establish_coupling(
94 &self,
95 params: CouplingParams,
96 ) -> Result<(CouplingId, AllocationToken), CouplingError> {
97 params.validate().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!(
180 "Strengthened coupling {} to {}",
181 coupling_id,
182 new_strength
183 );
184 }
185
186 Ok(())
187 }
188
189 pub async fn weaken(&self, coupling_id: CouplingId, factor: f64) -> Result<(), CouplingError> {
191 if let Some(mut coupling) = self.couplings.get_mut(&coupling_id) {
192 coupling.strength *= 1.0 - factor;
193
194 let attention_release = (coupling.attention_allocated as f64 * factor) as u64;
196 self.attention
197 .release_partial(&coupling.source, attention_release)
198 .await;
199 coupling.attention_allocated -= attention_release;
200
201 tracing::debug!("Weakened coupling {} by factor {}", coupling_id, factor);
202 }
203
204 Ok(())
205 }
206
207 pub async fn decouple_safely(
212 &self,
213 coupling_id: CouplingId,
214 ) -> Result<DecouplingResult, CouplingError> {
215 let coupling = self
216 .couplings
217 .get(&coupling_id)
218 .ok_or(CouplingError::NotFound)?
219 .clone();
220
221 self.graph.write().await.remove_edge(&coupling_id);
226
227 self.attention
229 .release_all(&coupling.source, coupling.attention_allocated)
230 .await;
231
232 self.couplings.remove(&coupling_id);
234
235 tracing::debug!("Decoupled {}", coupling_id);
236
237 Ok(DecouplingResult::Success)
238 }
239
240 pub fn get_coupling(&self, id: &CouplingId) -> Option<Coupling> {
242 self.couplings.get(id).map(|r| r.clone())
243 }
244
245 pub fn get_couplings_for(&self, resonator: &ResonatorId) -> Vec<Coupling> {
247 self.couplings
248 .iter()
249 .filter(|entry| {
250 entry.source == *resonator || entry.target == *resonator
251 })
252 .map(|entry| entry.clone())
253 .collect()
254 }
255
256 pub async fn restore_couplings(
258 &self,
259 _resonator: &ResonatorId,
260 couplings: &[Coupling],
261 ) -> Result<(), String> {
262 for coupling in couplings {
263 self.graph.write().await.add_edge(coupling);
264 self.couplings.insert(coupling.id, coupling.clone());
265 }
266
267 tracing::debug!("Restored {} couplings", couplings.len());
268 Ok(())
269 }
270
271 pub async fn persist_topology(&self) -> Result<(), String> {
273 tracing::info!("Persisting {} couplings", self.couplings.len());
275 Ok(())
276 }
277
278 pub fn count(&self) -> usize {
280 self.couplings.len()
281 }
282}