|
| 1 | +import numpy as np |
| 2 | +import matplotlib.pyplot as plt |
| 3 | + |
| 4 | +class QuantumSensor: |
| 5 | + def __init__(self, n_qubits=3, gamma=1.0, T2=3.0, sigma_noise=0.05, shots=100): |
| 6 | + self.n_qubits = n_qubits |
| 7 | + self.gamma = gamma |
| 8 | + self.T2 = T2 |
| 9 | + self.sigma_noise = sigma_noise |
| 10 | + self.shots = shots |
| 11 | + |
| 12 | + self.times = np.linspace(0.1, 5, 100) |
| 13 | + |
| 14 | + # True field parameters |
| 15 | + self.B0_true = 0.8 |
| 16 | + self.omega_true = 1.0 |
| 17 | + self.phi0_true = 0.0 |
| 18 | + |
| 19 | + # Bayesian grid |
| 20 | + self.B0_vals = np.linspace(0.5, 1.1, 60) |
| 21 | + self.omega_vals = np.linspace(0.7, 1.3, 60) |
| 22 | + self.phi0_vals = np.linspace(-np.pi, np.pi, 60) |
| 23 | + |
| 24 | + self.posterior = None |
| 25 | + self.posterior_B0 = None |
| 26 | + self.posterior_omega = None |
| 27 | + self.posterior_phi0 = None |
| 28 | + self.map_estimates = None |
| 29 | + |
| 30 | + def B_field(self, t, B0, omega): |
| 31 | + return B0 * np.sin(omega * t) |
| 32 | + |
| 33 | + def ideal_expectation(self, t, B0, omega, phi0): |
| 34 | + phase = self.gamma * self.n_qubits * self.B_field(t, B0, omega) * t + phi0 |
| 35 | + return np.cos(phase) |
| 36 | + |
| 37 | + def decohered_expectation(self, t, B0, omega, phi0): |
| 38 | + return self.ideal_expectation(t, B0, omega, phi0) * np.exp(-t / self.T2) |
| 39 | + |
| 40 | + def noisy_measurement(self, expectation): |
| 41 | + p = (1 + expectation) / 2 |
| 42 | + counts = np.random.binomial(self.shots, p) |
| 43 | + mean = 2 * (counts / self.shots) - 1 |
| 44 | + return mean + np.random.normal(0, self.sigma_noise) |
| 45 | + |
| 46 | + def generate_measurements(self): |
| 47 | + self.measurements = [] |
| 48 | + for t in self.times: |
| 49 | + exp_val = self.decohered_expectation(t, self.B0_true, self.omega_true, self.phi0_true) |
| 50 | + meas = self.noisy_measurement(exp_val) |
| 51 | + self.measurements.append(meas) |
| 52 | + self.measurements = np.array(self.measurements) |
| 53 | + |
| 54 | + def compute_posterior(self): |
| 55 | + B0_vals, omega_vals, phi0_vals = self.B0_vals, self.omega_vals, self.phi0_vals |
| 56 | + posterior = np.zeros((len(B0_vals), len(omega_vals), len(phi0_vals))) |
| 57 | + |
| 58 | + for i, B0 in enumerate(B0_vals): |
| 59 | + for j, omega in enumerate(omega_vals): |
| 60 | + for k, phi0 in enumerate(phi0_vals): |
| 61 | + preds = self.decohered_expectation(self.times, B0, omega, phi0) |
| 62 | + log_like = -np.sum((self.measurements - preds)**2) / (2 * self.sigma_noise**2) |
| 63 | + posterior[i, j, k] = np.exp(log_like) |
| 64 | + |
| 65 | + posterior /= np.sum(posterior) |
| 66 | + self.posterior = posterior |
| 67 | + |
| 68 | + self.posterior_B0 = np.sum(posterior, axis=(1, 2)) |
| 69 | + self.posterior_omega = np.sum(posterior, axis=(0, 2)) |
| 70 | + self.posterior_phi0 = np.sum(posterior, axis=(0, 1)) |
| 71 | + |
| 72 | + i_max, j_max, k_max = np.unravel_index(np.argmax(posterior), posterior.shape) |
| 73 | + self.map_estimates = ( |
| 74 | + B0_vals[i_max], |
| 75 | + omega_vals[j_max], |
| 76 | + phi0_vals[k_max] |
| 77 | + ) |
| 78 | + |
| 79 | + def print_results(self): |
| 80 | + B0_map, omega_map, phi0_map = self.map_estimates |
| 81 | + print("MAP Estimates:") |
| 82 | + print(f" B₀ = {B0_map:.3f} (true = {self.B0_true})") |
| 83 | + print(f" ω = {omega_map:.3f} (true = {self.omega_true})") |
| 84 | + print(f" φ₀ = {phi0_map:.3f} (true = {self.phi0_true})") |
| 85 | + |
| 86 | + def plot_posteriors(self): |
| 87 | + fig, axs = plt.subplots(3, 1, figsize=(8, 8)) |
| 88 | + axs[0].plot(self.B0_vals, self.posterior_B0, label='Posterior p(B₀)', color='navy') |
| 89 | + axs[0].axvline(self.B0_true, color='green', linestyle='--', label='True B₀') |
| 90 | + axs[0].axvline(self.map_estimates[0], color='red', linestyle=':', label='MAP B₀') |
| 91 | + axs[0].legend() |
| 92 | + axs[0].set_title("Posterior Distribution for B₀") |
| 93 | + |
| 94 | + axs[1].plot(self.omega_vals, self.posterior_omega, label='Posterior p(ω)', color='purple') |
| 95 | + axs[1].axvline(self.omega_true, color='green', linestyle='--', label='True ω') |
| 96 | + axs[1].axvline(self.map_estimates[1], color='red', linestyle=':', label='MAP ω') |
| 97 | + axs[1].legend() |
| 98 | + axs[1].set_title("Posterior Distribution for ω") |
| 99 | + |
| 100 | + axs[2].plot(self.phi0_vals, self.posterior_phi0, label='Posterior p(φ₀)', color='darkorange') |
| 101 | + axs[2].axvline(self.phi0_true, color='green', linestyle='--', label='True φ₀') |
| 102 | + axs[2].axvline(self.map_estimates[2], color='red', linestyle=':', label='MAP φ₀') |
| 103 | + axs[2].legend() |
| 104 | + axs[2].set_title("Posterior Distribution for φ₀") |
| 105 | + |
| 106 | + plt.tight_layout() |
| 107 | + plt.show() |
| 108 | + |
| 109 | + def estimate_fidelity(self): |
| 110 | + def evolved_state_vector(B0, omega, phi0, t): |
| 111 | + phase = self.gamma * self.n_qubits * B0 * np.sin(omega * t) * t + phi0 |
| 112 | + return np.array([np.cos(phase), np.sin(phase)]) |
| 113 | + |
| 114 | + fidelities = [] |
| 115 | + for t in self.times: |
| 116 | + true_state = evolved_state_vector(self.B0_true, self.omega_true, self.phi0_true, t) |
| 117 | + est_state = evolved_state_vector(*self.map_estimates, t) |
| 118 | + fid = np.abs(np.dot(true_state, est_state))**2 |
| 119 | + fidelities.append(fid) |
| 120 | + |
| 121 | + avg_fidelity = np.mean(fidelities) |
| 122 | + print(f"Average Fidelity between true and estimated quantum state: {avg_fidelity:.4f}") |
| 123 | + |
| 124 | + # Optional: plot fidelity over time |
| 125 | + plt.figure(figsize=(7, 3)) |
| 126 | + plt.plot(self.times, fidelities, label="Fidelity over time", color="teal") |
| 127 | + plt.xlabel("Time") |
| 128 | + plt.ylabel("Fidelity") |
| 129 | + plt.title("Quantum State Fidelity vs Time") |
| 130 | + plt.ylim(0, 1.05) |
| 131 | + plt.grid(True) |
| 132 | + plt.legend() |
| 133 | + plt.tight_layout() |
| 134 | + plt.show() |
| 135 | + |
| 136 | + |
| 137 | +# -------------------- Run the Sensor Simulation -------------------- |
| 138 | +sensor = QuantumSensor() |
| 139 | +sensor.generate_measurements() |
| 140 | +sensor.compute_posterior() |
| 141 | +sensor.print_results() |
| 142 | +sensor.plot_posteriors() |
| 143 | +sensor.estimate_fidelity() |
0 commit comments