QMem/
lib.rs

1//! # Quantum Memory Simulator
2//! 
3//! A simple library for simulating quantum memory operations
4//! including superposition, entanglement, and quantum gates.
5
6use rand::Rng;
7use std::collections::{HashMap, HashSet};
8
9/// Simulates a 64-bit quantum memory register with superposition and entanglement capabilities
10pub struct QMem {
11    /// Stores the collapsed bits (0s and 1s)
12    state: u64,
13    /// 1 if bit is in superposition (both 0 and 1), 0 otherwise
14    superposition: u64,
15    /// Entangled pairs (index -> index)
16    entangled: HashMap<usize, usize>,
17    /// Entanglement group mapping
18    entangled_groups: HashMap<usize, HashSet<usize>>,
19}
20
21impl QMem {
22    /// Creates a new quantum memory register with all 64 bits in superposition
23    pub fn new() -> Self {
24        QMem {
25            state: 0,
26            superposition: u64::MAX, // All 64 bits in superposition
27            entangled: HashMap::new(),
28            entangled_groups: HashMap::new(),
29        }
30    }
31
32    /// Sets a qubit to either 0, 1, or superposition
33    ///
34    /// * `index` - The index of the qubit (0-63)
35    /// * `value` - Some(true) for 1, Some(false) for 0, None for superposition
36    pub fn set_bit(&mut self, index: usize, value: Option<bool>) {
37        if index >= 64 {
38            return; // Prevent out-of-bounds access
39        }
40
41        if let Some(v) = value {
42            // Collapse to a fixed value (0 or 1)
43            self.superposition &= !(1 << index); // Clear the superposition bit
44            if v {
45                self.state |= 1 << index; // Set to 1
46            } else {
47                self.state &= !(1 << index); // Set to 0
48            }
49
50            // Collapse entangled groups if they exist
51            self.collapse_entangled_group(index, v);
52        } else {
53            // Set to superposition (both 0 and 1)
54            self.superposition |= 1 << index;
55        }
56    }
57
58    /// Applies the Hadamard Gate (H) to place a qubit in superposition
59    ///
60    /// * `index` - The index of the qubit (0-63)
61    pub fn hadamard(&mut self, index: usize) {
62        self.set_bit(index, None);
63    }
64
65    /// Applies the CNOT Gate: If control is 1, flip the target bit
66    ///
67    /// * `control` - The control qubit index
68    /// * `target` - The target qubit index
69    pub fn cnot(&mut self, control: usize, target: usize) {
70        if self.measure(control) {
71            let target_value = !self.measure(target); // Flip target
72            self.set_bit(target, Some(target_value));
73        }
74    }
75
76    /// Applies the Pauli-X Gate (NOT) to flip the value of a qubit
77    ///
78    /// * `index` - The index of the qubit to flip
79    pub fn pauli_x(&mut self, index: usize) {
80        let current_value = self.measure(index);
81        self.set_bit(index, Some(!current_value));
82    }
83
84    /// Applies the Swap Gate to exchange the values of two qubits
85    ///
86    /// * `a` - The first qubit index
87    /// * `b` - The second qubit index
88    pub fn swap(&mut self, a: usize, b: usize) {
89        if a == b {
90            return; // No need to swap
91        }
92        
93        let temp_a = self.measure(a);
94        let temp_b = self.measure(b);
95        self.set_bit(a, Some(temp_b));
96        self.set_bit(b, Some(temp_a));
97    }
98
99    /// Entangles two qubits so their states will always correlate
100    ///
101    /// * `a` - The first qubit index
102    /// * `b` - The second qubit index
103    pub fn entangle(&mut self, a: usize, b: usize) {
104        if a != b {
105            self.entangled.insert(a, b);
106            self.entangled.insert(b, a);
107        }
108    }
109
110    /// Entangles multiple qubits together in a group
111    ///
112    /// * `indices` - Array of qubit indices to entangle
113    pub fn entangle_group(&mut self, indices: &[usize]) {
114        if indices.len() < 2 {
115            return; // Need at least 2 qubits to entangle
116        }
117
118        let mut group = HashSet::new();
119
120        // First collect all existing entanglements
121        for &index in indices {
122            group.insert(index);
123
124            // Merge existing groups if any qubit is already entangled
125            if let Some(existing) = self.entangled_groups.get(&index) {
126                for &member in existing {
127                    group.insert(member);
128                }
129            }
130        }
131        
132        // Update entanglement for all involved qubits
133        let group_clone = group.clone();
134        for &index in &group {
135            self.entangled_groups.insert(index, group_clone.clone());
136        }
137    }
138
139    /// Collapses all qubits in an entangled group to the same value
140    ///
141    /// * `index` - The index of the qubit that was measured
142    /// * `value` - The value to collapse all entangled qubits to
143    fn collapse_entangled_group(&mut self, index: usize, value: bool) {
144        if let Some(group) = self.entangled_groups.get(&index).cloned() {
145            for &entangled_bit in &group {
146                if entangled_bit != index && (self.superposition >> entangled_bit) & 1 == 1 {
147                    // Avoid recursion by directly setting
148                    self.superposition &= !(1 << entangled_bit);
149                    if value {
150                        self.state |= 1 << entangled_bit;
151                    } else {
152                        self.state &= !(1 << entangled_bit);
153                    }
154                }
155            }
156        }
157        // Handle paired entanglement separately from group entanglement
158        if let Some(&pair) = self.entangled.get(&index) {
159            if (self.superposition >> pair) & 1 == 1 {
160                self.superposition &= !(1 << pair);
161                if value {
162                    self.state |= 1 << pair;
163                } else {
164                    self.state &= !(1 << pair);
165                }
166            }
167        }
168    }
169
170    /// Measures a qubit, collapsing it if in superposition
171    ///
172    /// If in superposition, randomly chooses 0 or 1
173    ///
174    /// * `index` - The index of the qubit to measure
175    /// * Returns the measured value (true for 1, false for 0)
176    pub fn measure(&mut self, index: usize) -> bool {
177        if index >= 64 {
178            return false; // Prevent out-of-bounds access
179        }
180        
181        if (self.superposition >> index) & 1 == 1 {
182            // Randomly collapse to 0 or 1 if in superposition
183            let mut rng = rand::rng();
184            let value = rng.random_bool(0.5);
185            self.set_bit(index, Some(value));
186            value
187        } else {
188            // Already collapsed, return the value
189            (self.state >> index) & 1 == 1
190        }
191    }
192
193    /// Runs Bell's Test to check if entangled qubits collapse together
194    ///
195    /// * `a` - The first qubit index
196    /// * `b` - The second qubit index
197    /// * Returns a tuple with the measured values and whether they are correlated
198    pub fn bells_test(&mut self, a: usize, b: usize) -> (bool, bool, bool) {
199        let a_measured = self.measure(a);
200        let b_measured = self.measure(b);
201        let correlated = a_measured == b_measured;
202        
203        println!("\nRunning Bell's Test on qubits {} and {}:", a, b);
204        println!("Qubit {}: {}, Qubit {}: {}", a, a_measured, b, b_measured);
205        if correlated {
206            println!("✅ Correlated (Entanglement Verified)");
207        } else {
208            println!("❌ Not Correlated (Possible Decoherence)");
209        }
210        
211        (a_measured, b_measured, correlated)
212    }
213
214    /// Print the current state of the quantum memory
215    ///
216    /// Displays the state, superposition, and entanglement information
217    pub fn print(&self) {
218        println!("State: {:064b}", self.state);
219        println!("Superposition: {:064b}", self.superposition);
220        println!("Entanglements: {:?}", self.entangled);
221        println!("Entanglement groups: {:?}", self.entangled_groups);
222    }
223
224    /// Returns the current state value of the quantum register
225    pub fn get_state(&self) -> u64 {
226        self.state
227    }
228
229    /// Returns the current superposition mask of the quantum register
230    pub fn get_superposition(&self) -> u64 {
231        self.superposition
232    }
233
234    /// Returns a reference to the entanglement pairs
235    pub fn get_entangled_pairs(&self) -> &HashMap<usize, usize> {
236        &self.entangled
237    }
238
239    /// Returns a reference to the entanglement groups
240    pub fn get_entangled_groups(&self) -> &HashMap<usize, HashSet<usize>> {
241        &self.entangled_groups
242    }
243}
244
245// Implementing Default trait for QMem
246impl Default for QMem {
247    fn default() -> Self {
248        Self::new()
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255
256    #[test]
257    fn test_new_qmem() {
258        let qmem = QMem::new();
259        assert_eq!(qmem.state, 0);
260        assert_eq!(qmem.superposition, u64::MAX);
261        assert!(qmem.entangled.is_empty());
262        assert!(qmem.entangled_groups.is_empty());
263    }
264
265    #[test]
266    fn test_set_bit() {
267        let mut qmem = QMem::new();
268        qmem.set_bit(0, Some(true));
269        assert_eq!(qmem.state & 1, 1);
270        assert_eq!(qmem.superposition & 1, 0);
271    }
272
273    #[test]
274    fn test_entangle_and_measure() {
275        let mut qmem = QMem::new();
276        qmem.entangle(0, 1);
277        qmem.set_bit(0, Some(true));
278        assert_eq!(qmem.measure(1), true);
279    }
280}