File size: 3,588 Bytes
80d7559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// CARRY Quantum Execution DAG Module
// DAG representation of quantum multi-agent computation with strict node provenance.

use std::collections::HashMap;

/// Quantum DAG Node Type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum QuantumDAGNodeType {
    Input,
    StatePreparation,
    Entanglement,
    AgentComputation,
    PartnerVerification,
    QuantumOperation,
    Measurement,
    ICPGate,
    Commit,
}

/// Quantum DAG Node with provenance and metadata.
#[derive(Debug, Clone)]
pub struct QuantumDAGNode {
    pub id: usize,
    pub node_type: QuantumDAGNodeType,
    pub label: String,
    pub agent_id: String,
    pub target_qubits: Vec<usize>,
    pub provenance_hash: String,
    pub parent_ids: Vec<usize>,
}

/// Quantum DAG Graph structure.
#[derive(Debug, Clone)]
pub struct QuantumDAG {
    pub nodes: HashMap<usize, QuantumDAGNode>,
    pub next_node_id: usize,
    pub execution_order: Vec<usize>,
}

impl QuantumDAG {
    pub fn new() -> Self {
        Self {
            nodes: HashMap::new(),
            next_node_id: 1,
            execution_order: Vec::new(),
        }
    }

    /// Add a node to the DAG with edge provenance validation.
    pub fn add_node(
        &mut self,
        node_type: QuantumDAGNodeType,
        label: impl Into<String>,
        agent_id: impl Into<String>,
        target_qubits: Vec<usize>,
        parent_ids: Vec<usize>,
    ) -> Result<usize, String> {
        let label_str = label.into();
        let agent_str = agent_id.into();

        // Validate parents exist
        for &parent_id in &parent_ids {
            if !self.nodes.contains_key(&parent_id) {
                return Err(format!("DAG_ERROR: Parent node {} does not exist", parent_id));
            }
        }

        // Validate canonical DAG sequence invariants
        if node_type == QuantumDAGNodeType::Commit {
            let has_icp_parent = parent_ids.iter().any(|&p| {
                self.nodes.get(&p).map(|n| n.node_type) == Some(QuantumDAGNodeType::ICPGate)
            });
            if !has_icp_parent {
                return Err("INVALID_DAG_PATH: Commit node must be preceded by an ICP Gate node".into());
            }
        }

        let id = self.next_node_id;
        self.next_node_id += 1;

        // Compute provenance hash
        let provenance_hash = format!(
            "NODE_{:?}_AG_{}_Q{:?}_P{:?}",
            node_type, agent_str, target_qubits, parent_ids
        );

        let node = QuantumDAGNode {
            id,
            node_type,
            label: label_str,
            agent_id: agent_str,
            target_qubits,
            provenance_hash,
            parent_ids,
        };

        self.nodes.insert(id, node);
        self.execution_order.push(id);
        Ok(id)
    }

    /// Validate complete execution path from Input to Commit.
    pub fn validate_path(&self) -> Result<(), String> {
        if self.execution_order.is_empty() {
            return Err("DAG is empty".into());
        }

        let first = self.nodes.get(&self.execution_order[0]).unwrap();
        if first.node_type != QuantumDAGNodeType::Input {
            return Err("DAG path must start with Input node".into());
        }

        let last = self.nodes.get(self.execution_order.last().unwrap()).unwrap();
        if last.node_type != QuantumDAGNodeType::Commit {
            return Err("DAG path must terminate with Commit node".into());
        }

        Ok(())
    }
}