1use super::*;
23use crate::adaptive::hyperbolic::{RoutingStats, angle_difference};
24use async_trait::async_trait;
25use serde::{Deserialize, Serialize};
26use std::collections::HashMap;
27use std::sync::Arc;
28use tokio::sync::RwLock;
29
30const FIXED_POINT_SCALE: i64 = 1_000_000; const HYSTERESIS_THRESHOLD: f64 = 0.001;
35const HYSTERESIS_DAMPING: f64 = 0.8;
36
37#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
39pub struct EnhancedHyperbolicCoordinate {
40 r_fixed: i64,
42 theta_fixed: i64,
44}
45
46impl EnhancedHyperbolicCoordinate {
47 pub fn from_float(r: f64, theta: f64) -> Self {
49 Self {
50 r_fixed: (r * FIXED_POINT_SCALE as f64) as i64,
51 theta_fixed: (theta * FIXED_POINT_SCALE as f64) as i64,
52 }
53 }
54
55 pub fn r(&self) -> f64 {
57 self.r_fixed as f64 / FIXED_POINT_SCALE as f64
58 }
59
60 pub fn theta(&self) -> f64 {
62 self.theta_fixed as f64 / FIXED_POINT_SCALE as f64
63 }
64
65 pub fn set_r(&mut self, r: f64) {
67 self.r_fixed = (r * FIXED_POINT_SCALE as f64) as i64;
68 }
69
70 pub fn set_theta(&mut self, theta: f64) {
72 self.theta_fixed = (theta * FIXED_POINT_SCALE as f64) as i64;
73 }
74}
75
76pub struct EnhancedHyperbolicSpace {
78 my_coordinate: RwLock<EnhancedHyperbolicCoordinate>,
80
81 previous_coordinate: RwLock<Option<EnhancedHyperbolicCoordinate>>,
83
84 neighbor_coordinates: Arc<RwLock<HashMap<NodeId, EnhancedHyperbolicCoordinate>>>,
86
87 adjustment_params: AdjustmentParameters,
89
90 _routing_stats: Arc<RwLock<RoutingStats>>,
92
93 visualization_data: Arc<RwLock<VisualizationData>>,
95}
96
97#[derive(Debug, Clone)]
99pub struct AdjustmentParameters {
100 base_rate: f64,
102 current_rate: f64,
104 min_rate: f64,
106 max_rate: f64,
108 hysteresis_factor: f64,
110}
111
112impl Default for AdjustmentParameters {
113 fn default() -> Self {
114 Self {
115 base_rate: 0.01,
116 current_rate: 0.01,
117 min_rate: 0.001,
118 max_rate: 0.1,
119 hysteresis_factor: HYSTERESIS_DAMPING,
120 }
121 }
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct VisualizationData {
127 pub nodes: HashMap<NodeId, VisualizationNode>,
129 pub paths: Vec<RoutingPath>,
131 pub metrics: NetworkMetrics,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct VisualizationNode {
137 pub id: NodeId,
138 pub coordinate: HyperbolicCoordinate,
139 pub label: String,
140 pub degree: usize,
141 pub trust_score: f64,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct RoutingPath {
146 pub source: NodeId,
147 pub target: NodeId,
148 pub hops: Vec<NodeId>,
149 pub success: bool,
150 pub total_distance: f64,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct NetworkMetrics {
155 pub total_nodes: usize,
156 pub average_degree: f64,
157 pub clustering_coefficient: f64,
158 pub average_path_length: f64,
159}
160
161impl Default for EnhancedHyperbolicSpace {
162 fn default() -> Self {
163 Self::new()
164 }
165}
166
167impl EnhancedHyperbolicSpace {
168 pub fn new() -> Self {
170 let initial_r = 0.5;
171 let initial_theta = rand::random::<f64>() * 2.0 * std::f64::consts::PI;
172
173 Self {
174 my_coordinate: RwLock::new(EnhancedHyperbolicCoordinate::from_float(
175 initial_r,
176 initial_theta,
177 )),
178 previous_coordinate: RwLock::new(None),
179 neighbor_coordinates: Arc::new(RwLock::new(HashMap::new())),
180 adjustment_params: AdjustmentParameters::default(),
181 _routing_stats: Arc::new(RwLock::new(RoutingStats::default())),
182 visualization_data: Arc::new(RwLock::new(VisualizationData {
183 nodes: HashMap::new(),
184 paths: Vec::new(),
185 metrics: NetworkMetrics {
186 total_nodes: 0,
187 average_degree: 0.0,
188 clustering_coefficient: 0.0,
189 average_path_length: 0.0,
190 },
191 })),
192 }
193 }
194
195 pub fn distance_fixed(
197 a: &EnhancedHyperbolicCoordinate,
198 b: &EnhancedHyperbolicCoordinate,
199 ) -> f64 {
200 let r1 = a.r();
201 let r2 = b.r();
202 let theta1 = a.theta();
203 let theta2 = b.theta();
204
205 let cos_angle_diff = (theta1 - theta2).cos();
207
208 if r1 > 0.999 || r2 > 0.999 {
210 return f64::INFINITY;
211 }
212
213 let numerator = (r1 - r2).powi(2) + 4.0 * r1 * r2 * (1.0 - cos_angle_diff);
215 let denominator = (1.0 - r1.powi(2)) * (1.0 - r2.powi(2));
216
217 if denominator <= 0.0 {
218 return f64::INFINITY;
219 }
220
221 let cosh_dist = 1.0 + numerator / denominator;
222 cosh_dist.acosh()
223 }
224
225 pub async fn adjust_coordinate_with_hysteresis(
227 &self,
228 neighbor_coords: &[(NodeId, EnhancedHyperbolicCoordinate)],
229 ) {
230 let mut my_coord = self.my_coordinate.write().await;
231 let mut prev_coord_guard = self.previous_coordinate.write().await;
232
233 let degree = neighbor_coords.len();
235 let target_r = 1.0 - (2.0 / (degree as f64 + 2.0));
236
237 let (sin_sum, cos_sum) =
239 neighbor_coords
240 .iter()
241 .fold((0.0, 0.0), |(sin_acc, cos_acc), (_, coord)| {
242 let theta = coord.theta();
243 (sin_acc + theta.sin(), cos_acc + theta.cos())
244 });
245
246 let target_theta = sin_sum.atan2(cos_sum);
247
248 let mut params = self.adjustment_params.clone();
250
251 if let Some(prev_coord) = prev_coord_guard.as_ref() {
252 let prev_movement = Self::distance_fixed(&my_coord, prev_coord);
253
254 if prev_movement < HYSTERESIS_THRESHOLD {
256 params.current_rate *= params.hysteresis_factor;
258 } else {
259 params.current_rate = params.base_rate;
261 }
262
263 params.current_rate = params.current_rate.clamp(params.min_rate, params.max_rate);
265 }
266
267 *prev_coord_guard = Some(*my_coord);
269
270 let current_r = my_coord.r();
272 let current_theta = my_coord.theta();
273
274 let new_r = current_r + params.current_rate * (target_r - current_r);
275 let angle_diff = angle_difference(target_theta, current_theta);
276 let new_theta = current_theta + params.current_rate * angle_diff;
277
278 my_coord.set_r(new_r.clamp(0.0, 0.999));
280
281 let normalized_theta = if new_theta < 0.0 {
283 new_theta + 2.0 * std::f64::consts::PI
284 } else if new_theta >= 2.0 * std::f64::consts::PI {
285 new_theta - 2.0 * std::f64::consts::PI
286 } else {
287 new_theta
288 };
289
290 my_coord.set_theta(normalized_theta);
291 }
292
293 pub async fn update_visualization(&self) {
295 let neighbors = self.neighbor_coordinates.read().await;
296 let mut viz_data = self.visualization_data.write().await;
297
298 viz_data.nodes.clear();
300
301 let my_coord = self.my_coordinate.read().await;
303 let my_id = generate_local_node_id(); viz_data.nodes.insert(
306 my_id.clone(),
307 VisualizationNode {
308 id: my_id.clone(),
309 coordinate: HyperbolicCoordinate {
310 r: my_coord.r(),
311 theta: my_coord.theta(),
312 },
313 label: "Local Node".to_string(),
314 degree: neighbors.len(),
315 trust_score: 1.0,
316 },
317 );
318
319 for (node_id, coord) in neighbors.iter() {
321 viz_data.nodes.insert(
322 node_id.clone(),
323 VisualizationNode {
324 id: node_id.clone(),
325 coordinate: HyperbolicCoordinate {
326 r: coord.r(),
327 theta: coord.theta(),
328 },
329 label: format!("Node {:?}", node_id),
330 degree: 0, trust_score: 0.5, },
333 );
334 }
335
336 viz_data.metrics.total_nodes = viz_data.nodes.len();
338 viz_data.metrics.average_degree = neighbors.len() as f64;
339 }
340
341 pub async fn export_visualization_json(&self) -> Result<String> {
343 let viz_data = self.visualization_data.read().await;
344 serde_json::to_string_pretty(&*viz_data).map_err(|e| {
345 AdaptiveNetworkError::Other(format!("Failed to serialize visualization: {}", e))
346 })
347 }
348
349 pub async fn export_visualization_svg(&self) -> Result<String> {
351 let viz_data = self.visualization_data.read().await;
352 let mut svg = String::new();
353
354 svg.push_str(
356 r#"<svg width="800" height="800" xmlns="http://www.w3.org/2000/svg">
357 <circle cx="400" cy="400" r="380" fill="none" stroke="black" stroke-width="2"/>
358 "#,
359 );
360
361 for node in viz_data.nodes.values() {
363 let (x, y) = polar_to_cartesian(
364 node.coordinate.r,
365 node.coordinate.theta,
366 400.0,
367 400.0,
368 380.0,
369 );
370 svg.push_str(&format!(
371 r#"<circle cx="{}" cy="{}" r="5" fill="blue" stroke="black" stroke-width="1"/>"#,
372 x, y
373 ));
374 }
375
376 for path in &viz_data.paths {
378 if let (Some(source), Some(target)) = (
379 viz_data.nodes.get(&path.source),
380 viz_data.nodes.get(&path.target),
381 ) {
382 let (x1, y1) = polar_to_cartesian(
383 source.coordinate.r,
384 source.coordinate.theta,
385 400.0,
386 400.0,
387 380.0,
388 );
389 let (x2, y2) = polar_to_cartesian(
390 target.coordinate.r,
391 target.coordinate.theta,
392 400.0,
393 400.0,
394 380.0,
395 );
396
397 let color = if path.success { "green" } else { "red" };
398 svg.push_str(&format!(
399 r#"<line x1="{}" y1="{}" x2="{}" y2="{}" stroke="{}" stroke-width="2" opacity="0.5"/>"#,
400 x1, y1, x2, y2, color
401 ));
402 }
403 }
404
405 svg.push_str("</svg>");
406 Ok(svg)
407 }
408}
409
410fn polar_to_cartesian(r: f64, theta: f64, cx: f64, cy: f64, radius: f64) -> (f64, f64) {
412 let x = cx + r * radius * theta.cos();
413 let y = cy + r * radius * theta.sin();
414 (x, y)
415}
416
417fn generate_local_node_id() -> NodeId {
419 use rand::RngCore;
420 let mut hash = [0u8; 32];
421 rand::thread_rng().fill_bytes(&mut hash);
422 NodeId::from_bytes(hash)
423}
424
425pub struct EnhancedHyperbolicRoutingStrategy {
427 space: Arc<EnhancedHyperbolicSpace>,
429
430 local_id: NodeId,
432
433 max_hops: usize,
435
436 enable_visualization: bool,
438}
439
440impl EnhancedHyperbolicRoutingStrategy {
441 pub fn new(local_id: NodeId, space: Arc<EnhancedHyperbolicSpace>) -> Self {
443 Self {
444 space,
445 local_id,
446 max_hops: 10,
447 enable_visualization: true,
448 }
449 }
450
451 async fn find_enhanced_path(&self, target: &NodeId) -> Result<Vec<NodeId>> {
453 let target_coord = {
454 let neighbors = self.space.neighbor_coordinates.read().await;
455 neighbors.get(target).cloned()
456 };
457
458 let target_coord = match target_coord {
459 Some(coord) => coord,
460 None => {
461 return Err(AdaptiveNetworkError::Routing(
462 "Target coordinate unknown".to_string(),
463 ));
464 }
465 };
466
467 let mut path = Vec::new();
468 let mut visited = std::collections::HashSet::<NodeId>::new();
469 visited.insert(self.local_id.clone());
470
471 let mut total_distance = 0.0;
472 let _start_time = std::time::Instant::now();
473
474 for hop in 0..self.max_hops {
476 let my_coord = self.space.my_coordinate.read().await;
477 let my_distance = EnhancedHyperbolicSpace::distance_fixed(&my_coord, &target_coord);
478
479 let neighbors = self.space.neighbor_coordinates.read().await;
480 let next_hop = neighbors
481 .iter()
482 .filter(|(id, _)| !visited.contains(id))
483 .filter(|(_, coord)| {
484 EnhancedHyperbolicSpace::distance_fixed(coord, &target_coord) < my_distance
485 })
486 .min_by(|(_, a), (_, b)| {
487 let dist_a = EnhancedHyperbolicSpace::distance_fixed(a, &target_coord);
488 let dist_b = EnhancedHyperbolicSpace::distance_fixed(b, &target_coord);
489 dist_a
490 .partial_cmp(&dist_b)
491 .unwrap_or(std::cmp::Ordering::Equal)
492 })
493 .map(|(id, coord)| (id.clone(), *coord));
494
495 match next_hop {
496 Some((next_id, next_coord)) => {
497 if next_id == *target {
498 path.push(next_id);
500 total_distance +=
501 EnhancedHyperbolicSpace::distance_fixed(&my_coord, &next_coord);
502
503 if self.enable_visualization {
505 let mut viz_data = self.space.visualization_data.write().await;
506 viz_data.paths.push(RoutingPath {
507 source: self.local_id.clone(),
508 target: target.clone(),
509 hops: path.clone(),
510 success: true,
511 total_distance,
512 });
513 }
514
515 return Ok(path);
516 }
517
518 path.push(next_id.clone());
519 visited.insert(next_id);
520 total_distance +=
521 EnhancedHyperbolicSpace::distance_fixed(&my_coord, &next_coord);
522 }
523 None => {
524 if self.enable_visualization {
526 let mut viz_data = self.space.visualization_data.write().await;
527 viz_data.paths.push(RoutingPath {
528 source: self.local_id.clone(),
529 target: target.clone(),
530 hops: path.clone(),
531 success: false,
532 total_distance,
533 });
534 }
535
536 return Err(AdaptiveNetworkError::Routing(format!(
537 "No closer neighbor found after {} hops",
538 hop
539 )));
540 }
541 }
542 }
543
544 Err(AdaptiveNetworkError::Routing(
546 "Maximum hop count exceeded".to_string(),
547 ))
548 }
549}
550
551#[async_trait]
552impl RoutingStrategy for EnhancedHyperbolicRoutingStrategy {
553 async fn find_path(&self, target: &NodeId) -> Result<Vec<NodeId>> {
554 self.find_enhanced_path(target).await
555 }
556
557 fn route_score(&self, _neighbor: &NodeId, _target: &NodeId) -> f64 {
558 0.5
559 }
560
561 fn update_metrics(&mut self, _path: &[NodeId], _success: bool) {
562 }
564}
565
566#[cfg(test)]
567mod tests {
568 use super::*;
569
570 #[test]
571 fn test_fixed_point_conversion() {
572 let coord = EnhancedHyperbolicCoordinate::from_float(0.5, std::f64::consts::PI);
573 assert!((coord.r() - 0.5).abs() < 1e-6);
574 assert!((coord.theta() - std::f64::consts::PI).abs() < 1e-6);
575 }
576
577 #[test]
578 fn test_enhanced_distance_calculation() {
579 let a = EnhancedHyperbolicCoordinate::from_float(0.0, 0.0);
580 let b = EnhancedHyperbolicCoordinate::from_float(0.5, std::f64::consts::PI);
581
582 let dist = EnhancedHyperbolicSpace::distance_fixed(&a, &b);
583 assert!(dist > 0.0);
584 assert!(dist.is_finite());
585
586 let boundary = EnhancedHyperbolicCoordinate::from_float(0.9999, 0.0);
588 let dist_boundary = EnhancedHyperbolicSpace::distance_fixed(&a, &boundary);
589 assert!(dist_boundary > 5.0); }
591
592 #[tokio::test]
593 async fn test_hysteresis_adjustment() {
594 let space = EnhancedHyperbolicSpace::new();
595
596 let neighbors = vec![
598 (
599 generate_local_node_id(),
600 EnhancedHyperbolicCoordinate::from_float(0.8, 0.0),
601 ),
602 (
603 generate_local_node_id(),
604 EnhancedHyperbolicCoordinate::from_float(0.8, std::f64::consts::PI),
605 ),
606 ];
607
608 let mut movements = vec![];
610 for _i in 0..10 {
611 let coord_before = space.my_coordinate.read().await.clone();
612 space.adjust_coordinate_with_hysteresis(&neighbors).await;
613 let coord_after = space.my_coordinate.read().await.clone();
614
615 let movement = EnhancedHyperbolicSpace::distance_fixed(&coord_before, &coord_after);
616 movements.push(movement);
617
618 tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
620 }
621
622 for i in 1..movements.len() {
624 assert!(movements[i] <= movements[i - 1] * 1.1); }
626 }
627
628 #[tokio::test]
629 async fn test_visualization_export() {
630 let space = Arc::new(EnhancedHyperbolicSpace::new());
631
632 let mut neighbors = space.neighbor_coordinates.write().await;
634 for i in 0..5 {
635 let angle = (i as f64) * 2.0 * std::f64::consts::PI / 5.0;
636 neighbors.insert(
637 generate_local_node_id(),
638 EnhancedHyperbolicCoordinate::from_float(0.5, angle),
639 );
640 }
641 drop(neighbors);
642
643 space.update_visualization().await;
645
646 let json = space.export_visualization_json().await.unwrap();
648 assert!(json.contains("nodes"));
649 assert!(json.contains("metrics"));
650
651 let svg = space.export_visualization_svg().await.unwrap();
653 assert!(svg.contains("<svg"));
654 assert!(svg.contains("<circle"));
655 }
656}