Bigboyvince

Vincent quantum final code

May 27th, 2025
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.54 KB | Cybersecurity | 0 0
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3.  
  4. """
  5. This script simulates an EAQEC code with a single-parameter recovery gate.
  6. It uses a depolarizing noise model and implements a grid search over rotation angles
  7. to find the optimal recovery angle that maximizes state fidelity.
  8.  
  9.  
  10.  
  11. """
  12.  
  13. import numpy as np
  14. import matplotlib.pyplot as plt
  15. from qiskit import QuantumCircuit, transpile
  16. from qiskit.quantum_info import Statevector, state_fidelity
  17. from qiskit_aer import AerSimulator
  18. from qiskit_aer.noise import NoiseModel, depolarizing_error
  19. from qiskit.visualization import plot_histogram
  20. from scipy.signal import find_peaks # Import find_peaks
  21.  
  22. # Set random seed for reproducibility (only affects NumPy, not AerSimulator unless seeded)
  23. np.random.seed(42)
  24.  
  25. class EAQECSimulator:
  26. """
  27. A class to simulate Entanglement-Assisted Quantum Error Correction (EAQEC) codes
  28. with a single-parameter recovery gate and depolarizing noise.
  29. """
  30.  
  31. def __init__(self, data_qubits=1, ancilla_qubits=2, noise_strength=0.05):
  32. """
  33. Initialize the EAQEC simulator.
  34.  
  35. Args:
  36. data_qubits (int): Number of data qubits
  37. ancilla_qubits (int): Number of ancilla qubits (including entangled qubits)
  38. noise_strength (float): Strength of the depolarizing noise (0 to 1)
  39. """
  40. self.data_qubits = data_qubits
  41. self.ancilla_qubits = ancilla_qubits
  42. self.total_qubits = data_qubits + ancilla_qubits
  43. self.noise_strength = noise_strength
  44. # Use unseeded simulator for fluctuations
  45. self.simulator = AerSimulator()
  46. self.noise_model = self._create_noise_model()
  47.  
  48. def _create_noise_model(self):
  49. """
  50. Create a depolarizing noise model for the simulation.
  51.  
  52. Returns:
  53. NoiseModel: A Qiskit noise model with depolarizing errors
  54. """
  55. noise_model = NoiseModel()
  56.  
  57. # Add depolarizing error to all single-qubit gates
  58. error = depolarizing_error(self.noise_strength, 1)
  59. noise_model.add_all_qubit_quantum_error(error, ["rx", "ry", "rz", "h", "x", "y", "z"])
  60.  
  61. # Add depolarizing error to all two-qubit gates
  62. error = depolarizing_error(self.noise_strength, 2)
  63. noise_model.add_all_qubit_quantum_error(error, ["cx", "cz", "swap"])
  64.  
  65. return noise_model
  66.  
  67. def create_encoding_circuit(self, initial_state=None):
  68. """
  69. Create the encoding circuit for the EAQEC code.
  70.  
  71. Args:
  72. initial_state (list, optional): Initial state amplitudes for data qubits
  73.  
  74. Returns:
  75. QuantumCircuit: The encoding circuit
  76. """
  77. # Create a quantum circuit with data and ancilla qubits
  78. qc = QuantumCircuit(self.total_qubits)
  79.  
  80. # Prepare the initial state if provided
  81. if initial_state is not None:
  82. # Initialize the data qubit to the specified state
  83. qc.initialize(initial_state, 0)
  84. else:
  85. # Default to |+⟩ state
  86. qc.h(0)
  87.  
  88. # Create entanglement between ancilla qubits (Bell pair)
  89. qc.h(1)
  90. qc.cx(1, 2)
  91.  
  92. # Entangle data qubit with ancilla qubits
  93. qc.cx(0, 1)
  94. qc.cx(0, 2)
  95.  
  96. return qc
  97.  
  98. def apply_error_correction(self, circuit, recovery_angle):
  99. """
  100. Apply error correction to the circuit with a parameterized recovery gate.
  101.  
  102. Args:
  103. circuit (QuantumCircuit): The quantum circuit to apply error correction to
  104. recovery_angle (float): The angle for the recovery rotation gate
  105.  
  106. Returns:
  107. QuantumCircuit: The circuit with error correction applied
  108. """
  109. # Create a new circuit with the same qubits
  110. qc = circuit.copy()
  111.  
  112. # Decode the EAQEC code
  113. qc.cx(0, 2)
  114. qc.cx(0, 1)
  115.  
  116. # Apply the recovery gate (Y-axis rotation) to the data qubit
  117. qc.ry(recovery_angle, 0)
  118.  
  119. return qc
  120.  
  121. def simulate_ideal_circuit(self, initial_state=None):
  122. """
  123. Simulate the ideal circuit without noise.
  124.  
  125. Args:
  126. initial_state (list, optional): Initial state amplitudes for data qubits
  127.  
  128. Returns:
  129. Statevector: The final state vector
  130. """
  131. # Create the encoding circuit
  132. qc = self.create_encoding_circuit(initial_state)
  133.  
  134. # Apply error correction with no recovery (angle=0)
  135. qc = self.apply_error_correction(qc, 0)
  136.  
  137. # Simulate the circuit
  138. qc_transpiled = transpile(qc, self.simulator)
  139. # Save statevector is needed for Statevector.from_instruction
  140. qc_transpiled.save_statevector(label="ideal_statevector")
  141. result = self.simulator.run(qc_transpiled).result()
  142.  
  143. # Get the final state vector from result
  144. state = result.data()["ideal_statevector"]
  145. state = Statevector(state)
  146.  
  147. return state
  148.  
  149. def simulate_noisy_circuit(self, recovery_angle, initial_state=None):
  150. """
  151. Simulate the circuit with noise and recovery.
  152.  
  153. Args:
  154. recovery_angle (float): The angle for the recovery rotation gate
  155. initial_state (list, optional): Initial state amplitudes for data qubits
  156.  
  157. Returns:
  158. Statevector: The final state vector
  159. """
  160. # Create the encoding circuit
  161. qc = self.create_encoding_circuit(initial_state)
  162.  
  163. # Apply error correction with the specified recovery angle
  164. qc = self.apply_error_correction(qc, recovery_angle)
  165.  
  166. # Transpile the circuit first
  167. qc_transpiled = transpile(qc, self.simulator)
  168.  
  169. # Save statevector before running
  170. qc_transpiled.save_statevector(label="final_statevector")
  171.  
  172. # Simulate the circuit with noise
  173. result = self.simulator.run(
  174. qc_transpiled,
  175. noise_model=self.noise_model,
  176. # Ensure the simulator is not seeded by default to keep fluctuations
  177. # seed_simulator=None # Explicitly None or omit
  178. ).result()
  179.  
  180. # Get the final state vector from the result data
  181. state = result.data()["final_statevector"]
  182.  
  183. # Convert result to Statevector object for fidelity calculation
  184. state = Statevector(state)
  185.  
  186. return state
  187.  
  188. def grid_search(self, angle_range=(0, 2*np.pi), num_steps=40, initial_state=None):
  189. """
  190. Perform a grid search over recovery angles to find the optimal angle.
  191.  
  192. Args:
  193. angle_range (tuple): Range of angles to search (min, max)
  194. num_steps (int): Number of steps in the grid search
  195. initial_state (list, optional): Initial state amplitudes for data qubits
  196.  
  197. Returns:
  198. tuple: (angles, fidelities, optimal_angle, max_fidelity)
  199. """
  200. # Generate angles for grid search
  201. angles = np.linspace(angle_range[0], angle_range[1], num_steps)
  202. fidelities = []
  203.  
  204. # Get the ideal state
  205. ideal_state = self.simulate_ideal_circuit(initial_state)
  206.  
  207. # Perform grid search
  208. for angle in angles:
  209. # Simulate the noisy circuit with the current recovery angle
  210. noisy_state = self.simulate_noisy_circuit(angle, initial_state)
  211.  
  212. # Calculate the fidelity between the noisy and ideal states
  213. fidelity = state_fidelity(noisy_state, ideal_state)
  214. fidelities.append(fidelity)
  215.  
  216. # Find the optimal angle (global max)
  217. max_idx = np.argmax(fidelities)
  218. optimal_angle = angles[max_idx]
  219. max_fidelity = fidelities[max_idx]
  220.  
  221. # Return global max info along with angles/fidelities for plotting
  222. return angles, np.array(fidelities), optimal_angle, max_fidelity
  223.  
  224. def plot_fidelity_vs_angle(self, angles, fidelities, optimal_angle, max_fidelity):
  225. """
  226. Plot the fidelity vs recovery angle, marking local peaks.
  227.  
  228. Args:
  229. angles (array): Array of angles
  230. fidelities (array): Array of fidelities
  231. optimal_angle (float): The optimal recovery angle (global max, not plotted)
  232. max_fidelity (float): The maximum fidelity achieved (global max, not plotted)
  233.  
  234. Returns:
  235. matplotlib.figure.Figure: The figure object
  236. """
  237. fig, ax = plt.subplots(figsize=(10, 6))
  238.  
  239. # Plot the fidelity vs angle
  240. ax.plot(angles, fidelities, "b-", label="Fidelity")
  241.  
  242. # Find and plot local peaks
  243. # Use a small height threshold to avoid marking tiny noise fluctuations as peaks
  244. # Adjust height/distance as needed based on visual inspection
  245. peaks, _ = find_peaks(fidelities, height=np.min(fidelities) + 0.01 * (np.max(fidelities) - np.min(fidelities)), distance=2)
  246. if len(peaks) > 0:
  247. ax.plot(angles[peaks], fidelities[peaks], "ro", label="Local Peaks")
  248. else:
  249. # If no peaks found, maybe mark the global max as fallback?
  250. # Or just show the line plot. Let's just show the line for now.
  251. pass
  252.  
  253. # Set labels and title
  254. ax.set_xlabel("Recovery Angle (radians)")
  255. ax.set_ylabel("State Fidelity")
  256. ax.set_title("Fidelity vs Recovery Angle (Local Peaks Marked)")
  257.  
  258. # Add grid and legend
  259. ax.grid(True, alpha=0.3)
  260. ax.legend()
  261.  
  262. # Set y-axis limits (optional, can adjust)
  263. # ax.set_ylim(min(fidelities) * 0.95, 1.05)
  264.  
  265. return fig
  266.  
  267. def visualize_circuit(self, recovery_angle=0):
  268. """
  269. Visualize the quantum circuit with the specified recovery angle.
  270.  
  271. Args:
  272. recovery_angle (float): The angle for the recovery rotation gate
  273.  
  274. Returns:
  275. matplotlib.figure.Figure: The figure object
  276. """
  277. # Create the encoding circuit
  278. qc = self.create_encoding_circuit()
  279.  
  280. # Apply error correction with the specified recovery angle
  281. qc = self.apply_error_correction(qc, recovery_angle)
  282.  
  283. # Draw the circuit
  284. fig = qc.draw(output="mpl", style={"backgroundcolor": "#EEEEEE"})
  285.  
  286. return fig
  287.  
  288. def main():
  289. """
  290. Main function to run the EAQEC simulation.
  291. """
  292. print("Starting EAQEC Simulation...")
  293.  
  294. # Create the EAQEC simulator (using the adjusted noise strength)
  295. eaqec = EAQECSimulator(data_qubits=1, ancilla_qubits=2, noise_strength=0.07)
  296.  
  297. # Define the initial state (|+⟩ state)
  298. initial_state = [1/np.sqrt(2), 1/np.sqrt(2)]
  299.  
  300. # Perform grid search
  301. print("Performing grid search over recovery angles...")
  302. # Increase num_steps for better peak resolution if needed
  303. angles, fidelities, optimal_angle, max_fidelity = eaqec.grid_search(
  304. angle_range=(0, 2*np.pi),
  305. num_steps=80, # Increased steps for potentially more peaks
  306. initial_state=initial_state
  307. )
  308.  
  309. # Print the results (global max is still calculated but not primary focus of plot)
  310. print(f"Global Optimal recovery angle: {optimal_angle:.4f} radians")
  311. print(f"Global Maximum fidelity: {max_fidelity:.4f}")
  312.  
  313. # Plot the fidelity vs angle (now plotting local peaks)
  314. fig_fidelity = eaqec.plot_fidelity_vs_angle(angles, fidelities, optimal_angle, max_fidelity)
  315. fig_fidelity.savefig("fidelity_vs_angle_peaks.png", dpi=300, bbox_inches="tight")
  316.  
  317.  
  318.  
  319. # print("Simulation completed. Results saved to 'fidelity_vs_angle_peaks.png' and 'optimal_circuit_peaks.png'.")
  320. print("Simulation completed. Fidelity plot saved to 'fidelity_vs_angle_peaks.png'.")
  321.  
  322. if __name__ == "__main__":
  323. main()
  324.  
  325.  
Advertisement
Add Comment
Please, Sign In to add comment