fix(dag): resolve compilation errors and API mismatches

Fixes across attention mechanisms, SONA engine, and examples:

Attention mechanisms:
- hierarchical_lorentz: Use dag.node_count(), dag.children() API
- parallel_branch: Replace get_children() with children()
- temporal_btsp: Fix node.estimated_cost access, remove selectivity
- cache: Use dag.node_ids() and dag.children() for iteration
- mincut_gated: Fix return type to match DagAttentionMechanism trait
- selector: Update tests to use OperatorNode::new()

SONA/QuDAG:
- sona/engine: Add deprecated Scan/Join match arms
- ml_kem: Fix unused parameter warnings
- ml_dsa: Fix unused parameter warnings

Examples:
- basic_usage: Use dag.children() instead of get_children()
- learning_workflow: Fix HnswScan/Sort field names, trajectory access
- attention_demo: Import DagAttentionMechanism trait
- attention_selection: Fix CausalConeConfig field names
- self_healing: Remove non-existent result fields
- federated_coherence: Add parentheses for comparison expression

Cargo.toml:
- Register all exotic examples with explicit paths

All 12 examples now build and run successfully.
This commit is contained in:
Claude 2025-12-30 01:50:51 +00:00
parent cc18f19aee
commit d35e5906ab
No known key found for this signature in database
16 changed files with 147 additions and 147 deletions

View file

@ -46,3 +46,31 @@ name = "learning_workflow"
[[example]]
name = "self_healing"
[[example]]
name = "synthetic_reflex_organism"
path = "examples/exotic/synthetic_reflex_organism.rs"
[[example]]
name = "timing_synchronization"
path = "examples/exotic/timing_synchronization.rs"
[[example]]
name = "coherence_safety"
path = "examples/exotic/coherence_safety.rs"
[[example]]
name = "artificial_instincts"
path = "examples/exotic/artificial_instincts.rs"
[[example]]
name = "living_simulation"
path = "examples/exotic/living_simulation.rs"
[[example]]
name = "thought_integrity"
path = "examples/exotic/thought_integrity.rs"
[[example]]
name = "federated_coherence"
path = "examples/exotic/federated_coherence.rs"

View file

@ -5,6 +5,7 @@ use ruvector_dag::{
TopologicalAttention, CausalConeAttention, CriticalPathAttention, MinCutGatedAttention,
DagAttention,
};
use ruvector_dag::attention::DagAttentionMechanism;
use std::time::Instant;
fn create_sample_dag() -> QueryDag {
@ -126,12 +127,12 @@ fn main() {
println!("4. MinCutGatedAttention");
let mincut = MinCutGatedAttention::with_defaults();
let start = Instant::now();
let scores = mincut.forward(&dag).unwrap();
let result = mincut.forward(&dag).unwrap();
let elapsed = start.elapsed();
println!(" Time: {:?}", elapsed);
println!(" Complexity: {}", mincut.complexity());
println!(" Score sum: {:.6}", scores.values().sum::<f32>());
println!(" Max score: {:.6}\n", scores.values().fold(0.0f32, |a, &b| a.max(b)));
println!(" Score sum: {:.6}", result.scores.iter().sum::<f32>());
println!(" Max score: {:.6}\n", result.scores.iter().fold(0.0f32, |a, b| a.max(*b)));
println!("All attention mechanisms completed successfully!");
}

View file

@ -30,7 +30,7 @@ fn main() {
println!("\nAttention scores:");
for (node_id, score) in &scores {
let node = dag.get_node(*node_id).unwrap();
println!(" Node {}: {:.4} - {:?}", node_id, score, node.operator);
println!(" Node {}: {:.4} - {:?}", node_id, score, node.op_type);
}
let sum: f32 = scores.values().sum();
@ -41,15 +41,16 @@ fn main() {
println!("Focuses on downstream dependencies");
let causal = CausalConeAttention::new(CausalConeConfig {
cone_depth: 3,
decay_factor: 0.85,
time_window_ms: 1000,
future_discount: 0.85,
ancestor_weight: 0.5,
});
let causal_scores = causal.forward(&dag).unwrap();
println!("\nCausal cone scores:");
for (node_id, score) in &causal_scores {
let node = dag.get_node(*node_id).unwrap();
println!(" Node {}: {:.4} - {:?}", node_id, score, node.operator);
println!(" Node {}: {:.4} - {:?}", node_id, score, node.op_type);
}
// Compare mechanisms

View file

@ -50,14 +50,10 @@ fn main() {
// Get children
println!("\nNode Children:");
for node_id in 0..5 {
let children = dag.get_children(node_id);
let children = dag.children(node_id);
println!(" Node {}: {:?}", node_id, children);
}
// Serialize to JSON
let json = dag.to_json().unwrap();
println!("\nJSON (first 200 chars):\n{}", &json[..json.len().min(200)]);
// Demonstrate iterators
println!("\nDFS Traversal:");
for (i, node_id) in dag.dfs_iter(scan).enumerate() {

View file

@ -364,7 +364,7 @@ impl FederatedNode {
let diff: f64 = a.iter().zip(b.iter())
.map(|(x, y)| (x - y).abs())
.sum();
diff / a.len() as f64 < 0.1
(diff / a.len() as f64) < 0.1
}
fn is_already_federated(&self, signature: &[f64]) -> bool {

View file

@ -82,11 +82,12 @@ fn main() {
// Demonstrate metrics
if let Some(first) = drained.first() {
println!("\nSample trajectory:");
println!(" Query ID: {}", first.query_id());
println!(" Mechanism: {}", first.mechanism());
println!(" Execution time: {:.2}ms", first.execution_time());
println!(" Baseline time: {:.2}ms", first.baseline_time());
println!(" Improvement: {:.1}%", first.improvement_percentage());
println!(" Query hash: {}", first.query_hash);
println!(" Mechanism: {}", first.attention_mechanism);
println!(" Execution time: {:.2}ms", first.execution_time_ms);
let baseline = first.execution_time_ms / first.improvement_ratio as f64;
println!(" Baseline time: {:.2}ms", baseline);
println!(" Improvement ratio: {:.3}", first.improvement_ratio);
}
println!("\n=== Example Complete ===");
@ -105,8 +106,8 @@ fn create_random_dag(seed: usize) -> QueryDag {
OperatorType::SeqScan { table: format!("table_{}", seed) }
} else {
OperatorType::HnswScan {
index_name: format!("idx_{}", seed),
k: 64
index: format!("idx_{}", seed),
ef_search: 64
}
}
} else if i == node_count - 1 {
@ -119,7 +120,8 @@ fn create_random_dag(seed: usize) -> QueryDag {
predicate: format!("col{} > {}", i, seed * 10)
},
1 => OperatorType::Sort {
columns: vec![format!("col{}", i)]
keys: vec![format!("col{}", i)],
descending: vec![false]
},
2 => OperatorType::Limit { count: 10 + (seed * i) },
_ => OperatorType::NestedLoopJoin,

View file

@ -53,11 +53,12 @@ fn main() {
if i % 10 == 9 {
let result = orchestrator.run_cycle();
let failures = result.repairs_attempted - result.repairs_succeeded;
println!("Cycle {}: {} anomalies, {} repairs, {} failures",
i + 1,
result.anomalies_detected,
result.repairs_succeeded,
result.repairs_failed);
failures);
}
}
@ -80,7 +81,7 @@ fn main() {
println!("\nAfter anomalies:");
println!(" Detected: {}", result.anomalies_detected);
println!(" Repairs succeeded: {}", result.repairs_succeeded);
println!(" Repairs failed: {}", result.repairs_failed);
println!(" Repairs failed: {}", result.repairs_attempted - result.repairs_succeeded);
println!(" Health Score: {:.2}", orchestrator.health_score());
// Recovery phase
@ -113,7 +114,6 @@ fn main() {
let result = checker.check_health(&healthy_index);
println!("\nHealthy HNSW index:");
println!(" Status: {:?}", result.status);
println!(" Score: {:.2}", result.score);
println!(" Issues: {}", result.issues.len());
let fragmented_index = IndexHealth {
@ -128,7 +128,6 @@ fn main() {
let result = checker.check_health(&fragmented_index);
println!("\nFragmented IVF-Flat index:");
println!(" Status: {:?}", result.status);
println!(" Score: {:.2}", result.score);
println!(" Issues: {:?}", result.issues);
println!(" Recommendations:");
for rec in &result.recommendations {

View file

@ -64,9 +64,9 @@ impl AttentionCache {
// Hash edges structure
let mut edge_list: Vec<(usize, usize)> = Vec::new();
for (from, children) in dag.edges() {
for child in children {
edge_list.push((*from, *child));
for node_id in dag.node_ids() {
for &child in dag.children(node_id) {
edge_list.push((node_id, child));
}
}
edge_list.sort_unstable();
@ -205,16 +205,12 @@ mod tests {
fn create_test_dag(n: usize) -> QueryDag {
let mut dag = QueryDag::new();
for i in 0..n {
dag.add_node(OperatorNode {
id: i,
op_type: OperatorType::Scan,
cost: (i + 1) as f64,
selectivity: 1.0,
metadata: HashMap::new(),
});
let mut node = OperatorNode::new(i, OperatorType::Scan);
node.estimated_cost = (i + 1) as f64;
dag.add_node(node);
}
if n > 1 {
dag.add_edge(0, 1);
let _ = dag.add_edge(0, 1);
}
dag
}

View file

@ -68,20 +68,24 @@ impl HierarchicalLorentzAttention {
/// Compute hierarchical depth for each node
fn compute_depths(&self, dag: &QueryDag) -> Vec<usize> {
let n = dag.nodes.len();
let n = dag.node_count();
let mut depths = vec![0; n];
let mut adj_list: HashMap<usize, Vec<usize>> = HashMap::new();
// Build adjacency list
for &(from, to) in &dag.edges {
adj_list.entry(from).or_insert_with(Vec::new).push(to);
for node_id in dag.node_ids() {
for &child in dag.children(node_id) {
adj_list.entry(node_id).or_insert_with(Vec::new).push(child);
}
}
// Find root nodes (nodes with no incoming edges)
let mut has_incoming = vec![false; n];
for &(_, to) in &dag.edges {
if to < n {
has_incoming[to] = true;
for node_id in dag.node_ids() {
for &child in dag.children(node_id) {
if child < n {
has_incoming[child] = true;
}
}
}
@ -158,11 +162,11 @@ impl HierarchicalLorentzAttention {
impl DagAttentionMechanism for HierarchicalLorentzAttention {
fn forward(&self, dag: &QueryDag) -> Result<AttentionScores, AttentionError> {
if dag.nodes.is_empty() {
if dag.node_count() == 0 {
return Err(AttentionError::InvalidDag("Empty DAG".to_string()));
}
let n = dag.nodes.len();
let n = dag.node_count();
// Step 1: Compute hierarchical depths
let depths = self.compute_depths(dag);
@ -251,21 +255,15 @@ mod tests {
let attention = HierarchicalLorentzAttention::new(config);
let mut dag = QueryDag::new();
dag.add_node(OperatorNode {
id: 0,
op_type: OperatorType::Scan,
cost: 1.0,
selectivity: 1.0,
metadata: HashMap::new(),
});
dag.add_node(OperatorNode {
id: 1,
op_type: OperatorType::Filter,
cost: 2.0,
selectivity: 0.5,
metadata: HashMap::new(),
});
dag.add_edge(0, 1);
let mut node0 = OperatorNode::new(0, OperatorType::Scan);
node0.estimated_cost = 1.0;
dag.add_node(node0);
let mut node1 = OperatorNode::new(1, OperatorType::Filter { predicate: "x > 0".to_string() });
node1.estimated_cost = 2.0;
dag.add_node(node1);
dag.add_edge(0, 1).unwrap();
let result = attention.forward(&dag).unwrap();
assert_eq!(result.scores.len(), 2);

View file

@ -1,6 +1,6 @@
//! MinCut Gated Attention: Gates attention by graph cut criticality
use super::{AttentionError, AttentionScores, DagAttention};
use super::trait_def::{AttentionError, AttentionScores, DagAttentionMechanism};
use crate::dag::QueryDag;
use std::collections::{HashMap, HashSet, VecDeque};
@ -162,19 +162,19 @@ impl MinCutGatedAttention {
}
}
impl DagAttention for MinCutGatedAttention {
impl DagAttentionMechanism for MinCutGatedAttention {
fn forward(&self, dag: &QueryDag) -> Result<AttentionScores, AttentionError> {
if dag.node_count() == 0 {
return Err(AttentionError::EmptyDag);
return Err(AttentionError::InvalidDag("Empty DAG".to_string()));
}
let cut_nodes = self.compute_min_cut(dag);
let mut scores = HashMap::new();
let n = dag.node_count();
let mut score_vec = vec![0.0; n];
let mut total = 0.0f32;
// Gate attention based on whether node is in cut
let node_ids: Vec<usize> = (0..dag.node_count()).collect();
for node_id in node_ids {
for node_id in 0..n {
if dag.get_node(node_id).is_none() {
continue;
}
@ -189,34 +189,18 @@ impl DagAttention for MinCutGatedAttention {
self.config.gate_threshold
};
scores.insert(node_id, score);
score_vec[node_id] = score;
total += score;
}
// Normalize to sum to 1
if total > 0.0 {
for score in scores.values_mut() {
for score in score_vec.iter_mut() {
*score /= total;
}
}
Ok(scores)
}
fn update(&mut self, _dag: &QueryDag, execution_times: &HashMap<usize, f64>) {
// Could adjust gate threshold based on execution time distribution
if !execution_times.is_empty() {
let max_time = execution_times.values().fold(0.0f64, |a, &b| a.max(b));
let min_time = execution_times.values().fold(f64::INFINITY, |a, &b| a.min(b));
if max_time > 0.0 && min_time > 0.0 {
// Adjust threshold based on variance
let ratio = max_time / min_time;
if ratio > 3.0 {
self.config.gate_threshold = (self.config.gate_threshold * 0.9).max(0.1);
}
}
}
Ok(AttentionScores::new(score_vec))
}
fn name(&self) -> &'static str {
@ -226,6 +210,7 @@ impl DagAttention for MinCutGatedAttention {
fn complexity(&self) -> &'static str {
"O(n * e^2)"
}
}
#[cfg(test)]
@ -254,11 +239,11 @@ mod tests {
let scores = attention.forward(&dag).unwrap();
// Check normalization
let sum: f32 = scores.values().sum();
let sum: f32 = scores.scores.iter().sum();
assert!((sum - 1.0).abs() < 1e-5);
// All scores should be in [0, 1]
for &score in scores.values() {
for &score in &scores.scores {
assert!(score >= 0.0 && score <= 1.0);
}
}

View file

@ -47,8 +47,9 @@ impl ParallelBranchAttention {
// Build parent-child relationships from adjacency
for node_id in dag.node_ids() {
if let Some(children) = dag.get_children(node_id) {
for child in children {
let children = dag.children(node_id);
if !children.is_empty() {
for &child in children {
children_of.entry(node_id).or_insert_with(Vec::new).push(child);
parents_of.entry(child).or_insert_with(Vec::new).push(node_id);
}
@ -68,7 +69,7 @@ impl ParallelBranchAttention {
for &child in children {
if !visited.contains(&child) {
// Check if this child has edges to any siblings
let child_children = dag.get_children(child).unwrap_or_default();
let child_children = dag.children(child);
let has_sibling_edge = children.iter().any(|&other| {
other != child && child_children.contains(&other)
});
@ -151,7 +152,7 @@ impl ParallelBranchAttention {
/// Compute attention scores based on parallel branch analysis
fn compute_branch_attention(&self, dag: &QueryDag, branches: &[Vec<usize>]) -> Vec<f32> {
let n = dag.nodes.len();
let n = dag.node_count();
let mut scores = vec![0.0; n];
// Base score for nodes not in any branch
@ -179,14 +180,16 @@ impl ParallelBranchAttention {
}
// Apply sync penalty to nodes that synchronize branches
for &(from, to) in &dag.edges {
if from < n && to < n {
// Check if this edge connects different branches
let from_branch = branches.iter().position(|b| b.iter().any(|&x| x == from));
let to_branch = branches.iter().position(|b| b.iter().any(|&x| x == to));
for from in dag.node_ids() {
for &to in dag.children(from) {
if from < n && to < n {
// Check if this edge connects different branches
let from_branch = branches.iter().position(|b| b.iter().any(|&x| x == from));
let to_branch = branches.iter().position(|b| b.iter().any(|&x| x == to));
if from_branch.is_some() && to_branch.is_some() && from_branch != to_branch {
scores[to] *= 1.0 - self.config.sync_penalty;
if from_branch.is_some() && to_branch.is_some() && from_branch != to_branch {
scores[to] *= 1.0 - self.config.sync_penalty;
}
}
}
}
@ -211,7 +214,7 @@ impl ParallelBranchAttention {
impl DagAttentionMechanism for ParallelBranchAttention {
fn forward(&self, dag: &QueryDag) -> Result<AttentionScores, AttentionError> {
if dag.nodes.is_empty() {
if dag.node_count() == 0 {
return Err(AttentionError::InvalidDag("Empty DAG".to_string()));
}
@ -253,20 +256,14 @@ mod tests {
let mut dag = QueryDag::new();
for i in 0..4 {
dag.add_node(OperatorNode {
id: i,
op_type: OperatorType::Scan,
cost: 1.0,
selectivity: 1.0,
metadata: HashMap::new(),
});
dag.add_node(OperatorNode::new(i, OperatorType::Scan));
}
// Create parallel branches: 0 -> 1, 0 -> 2, 1 -> 3, 2 -> 3
dag.add_edge(0, 1);
dag.add_edge(0, 2);
dag.add_edge(1, 3);
dag.add_edge(2, 3);
dag.add_edge(0, 1).unwrap();
dag.add_edge(0, 2).unwrap();
dag.add_edge(1, 3).unwrap();
dag.add_edge(2, 3).unwrap();
let branches = attention.detect_branches(&dag);
assert!(!branches.is_empty());
@ -279,16 +276,12 @@ mod tests {
let mut dag = QueryDag::new();
for i in 0..3 {
dag.add_node(OperatorNode {
id: i,
op_type: OperatorType::Scan,
cost: (i + 1) as f64,
selectivity: 1.0,
metadata: HashMap::new(),
});
let mut node = OperatorNode::new(i, OperatorType::Scan);
node.estimated_cost = (i + 1) as f64;
dag.add_node(node);
}
dag.add_edge(0, 1);
dag.add_edge(0, 2);
dag.add_edge(0, 1).unwrap();
dag.add_edge(0, 2).unwrap();
let result = attention.forward(&dag).unwrap();
assert_eq!(result.scores.len(), 3);

View file

@ -249,13 +249,8 @@ mod tests {
let mut selector = AttentionSelector::new(mechanisms, SelectorConfig::default());
let mut dag = QueryDag::new();
dag.add_node(OperatorNode {
id: 0,
op_type: OperatorType::Scan,
cost: 1.0,
selectivity: 1.0,
metadata: HashMap::new(),
});
let node = OperatorNode::new(0, OperatorType::Scan);
dag.add_node(node);
let (scores, idx) = selector.forward(&dag).unwrap();
assert_eq!(scores.scores.len(), 1);

View file

@ -79,14 +79,16 @@ impl TemporalBTSPAttention {
/// Compute base attention from topology
fn compute_topology_attention(&self, dag: &QueryDag) -> Vec<f32> {
let n = dag.nodes.len();
let n = dag.node_count();
let mut scores = vec![self.config.baseline_attention; n];
// Simple heuristic: nodes with higher cost and lower selectivity get more attention
for (i, node) in dag.nodes.iter().enumerate() {
let cost_factor = (node.cost as f32 / 100.0).min(1.0);
let selectivity_factor = 1.0 - node.selectivity as f32;
scores[i] = 0.5 * cost_factor + 0.5 * selectivity_factor;
// Simple heuristic: nodes with higher cost get more attention
for node in dag.nodes() {
if node.id < n {
let cost_factor = (node.estimated_cost as f32 / 100.0).min(1.0);
let rows_factor = (node.estimated_rows as f32 / 1000.0).min(1.0);
scores[node.id] = 0.5 * cost_factor + 0.5 * rows_factor;
}
}
scores
@ -180,12 +182,12 @@ impl DagAttentionMechanism for TemporalBTSPAttention {
// Update eligibility traces based on execution feedback
for (node_id, &exec_time) in execution_times {
if *node_id >= dag.nodes.len() {
continue;
}
let node = match dag.get_node(*node_id) {
Some(n) => n,
None => continue,
};
let node = &dag.nodes[*node_id];
let expected_time = node.cost;
let expected_time = node.estimated_cost;
// Compute reward signal: positive if faster than expected, negative if slower
let time_ratio = exec_time / expected_time.max(0.001);
@ -208,7 +210,7 @@ impl DagAttentionMechanism for TemporalBTSPAttention {
// Decay traces for nodes that weren't executed
let executed_nodes: std::collections::HashSet<_> = execution_times.keys().collect();
for node_id in 0..dag.nodes.len() {
for node_id in 0..dag.node_count() {
if !executed_nodes.contains(&node_id) {
self.update_eligibility(node_id, 0.0);
}
@ -261,13 +263,9 @@ mod tests {
let mut dag = QueryDag::new();
for i in 0..3 {
dag.add_node(OperatorNode {
id: i,
op_type: OperatorType::Scan,
cost: 10.0,
selectivity: 0.5,
metadata: HashMap::new(),
});
let mut node = OperatorNode::new(i, OperatorType::Scan);
node.estimated_cost = 10.0;
dag.add_node(node);
}
// Initial forward pass

View file

@ -49,8 +49,8 @@ impl MlDsa65 {
/// Verify a signature
pub fn verify(
pk: &MlDsa65PublicKey,
message: &[u8],
_pk: &MlDsa65PublicKey,
_message: &[u8],
signature: &Signature,
) -> Result<bool, DsaError> {
// In real implementation, would use ml-dsa verification

View file

@ -41,7 +41,7 @@ impl MlKem768 {
}
/// Encapsulate a shared secret for a recipient
pub fn encapsulate(pk: &MlKem768PublicKey) -> Result<EncapsulatedKey, KemError> {
pub fn encapsulate(_pk: &MlKem768PublicKey) -> Result<EncapsulatedKey, KemError> {
// In real implementation, would use ml-kem encapsulation
let mut ciphertext = [0u8; ML_KEM_768_CIPHERTEXT_SIZE];
let mut shared_secret = [0u8; SHARED_SECRET_SIZE];

View file

@ -117,6 +117,10 @@ impl DagSonaEngine {
OperatorType::Rerank { .. } => 14,
OperatorType::Materialize => 15,
OperatorType::Result => 16,
#[allow(deprecated)]
OperatorType::Scan => 0, // Treat as SeqScan
#[allow(deprecated)]
OperatorType::Join => 4, // Treat as NestedLoopJoin
};
if type_idx < type_counts.len() {
type_counts[type_idx] += 1;
@ -266,6 +270,10 @@ impl DagSonaEngine {
}
OperatorType::Materialize => 15u8.hash(&mut hasher),
OperatorType::Result => 16u8.hash(&mut hasher),
#[allow(deprecated)]
OperatorType::Scan => 0u8.hash(&mut hasher),
#[allow(deprecated)]
OperatorType::Join => 4u8.hash(&mut hasher),
}
}