Skip to content

Commit 64e2366

Browse files
committed
added codes
1 parent 5cc3732 commit 64e2366

File tree

3 files changed

+314
-0
lines changed

3 files changed

+314
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import numpy as np
2+
from scipy.linalg import expm
3+
4+
# Define constants
5+
ħ = 1 # Planck's constant (for simplicity, set ħ = 1)
6+
7+
# Pauli matrices
8+
X = np.array([[0, 1], [1, 0]], dtype=complex)
9+
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
10+
Z = np.array([[1, 0], [0, -1]], dtype=complex)
11+
I = np.eye(2, dtype=complex)
12+
13+
# Function to create an entangled Bell state
14+
def create_bell_state():
15+
return (1/np.sqrt(2)) * (np.kron(np.array([[1], [0]]), np.array([[1], [0]])) + np.kron(np.array([[0], [1]]), np.array([[0], [1]])))
16+
17+
# Function to create the Hamiltonian for a magnetic field
18+
def hamiltonian(B, t):
19+
# B: magnetic field (3D vector)
20+
# Heaviside-like treatment of the magnetic field
21+
22+
H = -ħ * (B[0] * X + B[1] * Y + B[2] * Z)
23+
return H
24+
25+
# Function to evolve the state
26+
def evolve_state(state, H, time):
27+
U = expm(-1j * H * time)
28+
return U @ state
29+
30+
# Function to measure the state and project it to the standard basis
31+
def measure(state):
32+
probabilities = np.abs(state.flatten())**2
33+
outcome = np.random.choice(range(len(probabilities)), p=probabilities)
34+
return outcome, state.flatten()[outcome]
35+
36+
# Main program
37+
if __name__ == "__main__":
38+
# Create initial entangled state
39+
initial_state = create_bell_state()
40+
print("Initial State:\n", initial_state)
41+
42+
# Time-dependent magnetic field (example: oscillating field)
43+
time_points = np.linspace(0, 10, 100)
44+
B = np.array([np.cos(time_points), np.sin(time_points), np.zeros_like(time_points)]) # Magnetic field oscillating in XY-plane
45+
46+
# Simulate evolution
47+
for t in time_points:
48+
H = hamiltonian(B[:, int(t)], t) # Hamiltonian for current time point
49+
evolved_state = evolve_state(initial_state, H, 0.1) # Evolve for a small time step
50+
51+
# Measure the final state
52+
outcome, final_state = measure(evolved_state)
53+
print("Measurement Outcome:", outcome)
54+
print("Final State After Measurement:\n", final_state)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
from scipy.linalg import expm
4+
5+
class QuantumSensor:
6+
def __init__(self, shots=1000, time_steps=100):
7+
self.shots = shots
8+
self.time_steps = time_steps
9+
self.state = self.create_bell_state()
10+
self.measurement_results = np.zeros(shots)
11+
self.time_points = np.linspace(0, 10, self.time_steps)
12+
# B is a 3xN array where N is time_steps. B[:, t] gives the magnetic field vector at time t.
13+
self.B = np.array([np.cos(self.time_points), np.sin(self.time_points), np.zeros_like(self.time_points)])
14+
15+
@staticmethod
16+
def create_bell_state():
17+
"""Create an entangled Bell state (|00> + |11>)/sqrt(2)."""
18+
# Representing states in the computational basis |00>, |01>, |10>, |11>
19+
return (1/np.sqrt(2)) * (np.array([[1], [0], [0], [0]]) +
20+
np.array([[0], [0], [0], [1]]))
21+
22+
@staticmethod
23+
def hamiltonian(B):
24+
"""Create the Hamiltonian for the current magnetic field for a two-qubit system."""
25+
ħ = 1 # Planck's constant
26+
X = np.array([[0, 1], [1, 0]], dtype=complex)
27+
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
28+
Z = np.array([[1, 0], [0, -1]], dtype=complex)
29+
I = np.eye(2, dtype=complex) # 2x2 Identity matrix
30+
31+
# Hamiltonian for two independent qubits interacting with the magnetic field
32+
# H = H1 + H2, where H1 = -ħ * B . sigma_1 and H2 = -ħ * B . sigma_2
33+
# In the two-qubit space (4x4 matrix):
34+
# H = -ħ * (Bx * (sigma_x tensor I) + By * (sigma_y tensor I) + Bz * (sigma_z tensor I) +
35+
# Bx * (I tensor sigma_x) + By * (I tensor sigma_y) + Bz * (I tensor sigma_z))
36+
H1 = -ħ * (B[0] * np.kron(X, I) + B[1] * np.kron(Y, I) + B[2] * np.kron(Z, I))
37+
H2 = -ħ * (B[0] * np.kron(I, X) + B[1] * np.kron(I, Y) + B[2] * np.kron(I, Z))
38+
39+
return H1 + H2
40+
41+
@staticmethod
42+
def evolve_state(state, H, time):
43+
"""Evolve the state using the unitary operator."""
44+
U = expm(-1j * H * time)
45+
return U @ state
46+
47+
def measure(self, state):
48+
"""Measure the state in the standard basis {|00>, |01>, |10>, |11>}."""
49+
# Ensure state is a column vector for probability calculation
50+
state_vector = state.flatten()
51+
probabilities = np.abs(state_vector)**2
52+
# Ensure probabilities sum to 1 (due to potential floating point inaccuracies)
53+
probabilities /= np.sum(probabilities)
54+
# Choose outcome based on probabilities. outcomes correspond to indices 0, 1, 2, 3
55+
outcome = np.random.choice(range(len(probabilities)), p=probabilities)
56+
# Return the outcome (index) and the corresponding state vector component
57+
return outcome, state_vector[outcome]
58+
59+
60+
def simulate(self):
61+
"""Run the simulation for a given number of shots."""
62+
for shot in range(self.shots):
63+
evolved_state = self.state # Start each shot with the initial Bell state
64+
# The Hamiltonian is time-dependent, so we need to apply the evolution operator
65+
# for each small time step. The total evolution U(T) = U(dt_N) * ... * U(dt_1).
66+
# We are assuming a small constant time step dt = 0.1.
67+
for t in range(self.time_steps):
68+
# Get the magnetic field vector at the current time point
69+
current_B = self.B[:, t]
70+
# Calculate the Hamiltonian for the current magnetic field
71+
H = self.hamiltonian(current_B)
72+
# Evolve the state for this small time step
73+
evolved_state = self.evolve_state(evolved_state, H, 0.1)
74+
75+
# Measure the final state after the total evolution time
76+
outcome, _ = self.measure(evolved_state)
77+
self.measurement_results[shot] = outcome
78+
79+
def plot_results(self):
80+
"""Plot the histogram of measurement outcomes."""
81+
plt.figure(figsize=(10, 6))
82+
# The possible outcomes for a two-qubit measurement are 0, 1, 2, 3
83+
plt.hist(self.measurement_results, bins=np.arange(5) - 0.5, density=True, rwidth=0.8)
84+
plt.xticks(range(4))
85+
plt.xlabel('Measurement Outcome (|00>, |01>, |10>, |11>)')
86+
plt.ylabel('Probability')
87+
plt.title(f'Histogram of Measurement Outcomes over {self.shots} Shots')
88+
plt.grid(axis='y', alpha=0.75)
89+
plt.show()
90+
91+
# Main execution
92+
if __name__ == "__main__":
93+
# Make sure expm is available, it's from scipy.linalg
94+
try:
95+
from scipy.linalg import expm
96+
except ImportError:
97+
print("Please install scipy: !pip install scipy")
98+
exit()
99+
100+
sensor = QuantumSensor(shots=1000, time_steps=100)
101+
sensor.simulate()
102+
sensor.plot_results()
103+
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
from scipy.linalg import expm
4+
5+
class QuantumSensor:
6+
def __init__(self, shots=1000, time_steps=100):
7+
self.shots = shots
8+
self.time_steps = time_steps
9+
self.state = self.create_bell_state()
10+
self.measurement_results = np.zeros(shots)
11+
self.time_points = np.linspace(0, 10, self.time_steps)
12+
# Original magnetic field B is still a 3x100 array representing Bx, By, Bz over time
13+
self.B = np.array([np.cos(self.time_points), np.sin(self.time_points), np.zeros_like(self.time_points)])
14+
self.estimated_Bx = None
15+
self.estimated_By = None
16+
self.estimated_Bz = None
17+
18+
@staticmethod
19+
def create_bell_state():
20+
"""Create an entangled Bell state."""
21+
# Returns a 4x1 column vector
22+
return (1/np.sqrt(2)) * (np.kron(np.array([[1], [0]]), np.array([[1], [0]])) +
23+
np.kron(np.array([[0], [1]]), np.array([[0], [1]])))
24+
25+
@staticmethod
26+
def single_qubit_hamiltonian(B):
27+
"""Create the Hamiltonian for a single qubit in a magnetic field B."""
28+
ħ = 1 # Planck's constant
29+
X = np.array([[0, 1], [1, 0]], dtype=complex)
30+
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
31+
Z = np.array([[1, 0], [0, -1]], dtype=complex)
32+
33+
return -ħ * (B[0] * X + B[1] * Y + B[2] * Z)
34+
35+
@staticmethod
36+
def two_qubit_hamiltonian(B):
37+
"""Create the Hamiltonian for a two-qubit system."""
38+
# Identity matrix for a single qubit
39+
I = np.array([[1, 0], [0, 1]], dtype=complex)
40+
# Single qubit Hamiltonian
41+
H_single = QuantumSensor.single_qubit_hamiltonian(B)
42+
43+
# Total Hamiltonian is the sum of the Hamiltonians on each qubit (assuming no interaction)
44+
# H_total = H_single (on qubit 1) + H_single (on qubit 2)
45+
# In tensor product notation: H_total = H_single \otimes I + I \otimes H_single
46+
return np.kron(H_single, I) + np.kron(I, H_single)
47+
48+
49+
@staticmethod
50+
def evolve_state(state, H, time):
51+
"""Evolve the state using the unitary operator."""
52+
# H should now be a 4x4 matrix
53+
U = expm(-1j * H * time)
54+
# state is a 4x1 vector
55+
# U @ state will result in a 4x1 vector
56+
return U @ state
57+
58+
def measure(self, state):
59+
"""Measure the state in the standard basis."""
60+
probabilities = np.abs(state.flatten())**2
61+
# Ensure probabilities sum to 1 to avoid issues with floating point inaccuracies
62+
probabilities /= np.sum(probabilities)
63+
outcome = np.random.choice(range(len(probabilities)), p=probabilities)
64+
return outcome, state.flatten()[outcome]
65+
66+
67+
def simulate(self):
68+
"""Run the simulation for a given number of shots."""
69+
for shot in range(self.shots):
70+
evolved_state = self.state
71+
for t in range(self.time_steps):
72+
# Use the two-qubit Hamiltonian
73+
H = self.two_qubit_hamiltonian(self.B[:, t])
74+
# Evolve the 4-dimensional state with the 4x4 Hamiltonian
75+
evolved_state = self.evolve_state(evolved_state, H, 0.1)
76+
77+
# Measure the final state
78+
outcome, _ = self.measure(evolved_state)
79+
self.measurement_results[shot] = outcome
80+
81+
def estimate_magnetic_field(self):
82+
"""Estimate the magnetic field from measurement outcomes."""
83+
84+
# Take the average of the measurement results to infer the magnetic field
85+
n_0 = np.sum(self.measurement_results == 0) # Number of outcomes corresponding to |00>
86+
n_1 = np.sum(self.measurement_results == 1) # Number of outcomes corresponding to |01>
87+
n_2 = np.sum(self.measurement_results == 2) # Number of outcomes corresponding to |10>
88+
n_3 = np.sum(self.measurement_results == 3) # Number of outcomes corresponding to |11>
89+
90+
counts = np.array([n_0, n_1, n_2, n_3])
91+
probabilities = counts / self.shots
92+
93+
# Using probabilities to estimate the components of the magnetic field
94+
# These simplified estimations are likely based on the expected probabilities
95+
# of measuring |01> and |10> states for a Bell state evolving under Bx and By fields.
96+
# A more rigorous estimation might involve a maximum likelihood estimation or similar.
97+
self.estimated_Bx = 2 * (probabilities[1] - probabilities[2]) # Simplified estimation
98+
self.estimated_By = 2 * (probabilities[3] - probabilities[0]) # Simplified estimation
99+
self.estimated_Bz = 0 # Assuming Bz doesn't cause |00> or |11> to change in this simplified model
100+
101+
102+
def plot_results(self):
103+
"""Plot the histogram of measurement outcomes."""
104+
plt.figure(figsize=(10, 6))
105+
# Use align='left' and add 0.5 to bins for proper alignment with xticks
106+
plt.hist(self.measurement_results, bins=np.arange(5) - 0.5, density=True, alpha=0.7, color='blue', edgecolor='black', align='left')
107+
plt.xticks(range(4))
108+
plt.xlabel('Measurement Outcome')
109+
plt.ylabel('Probability')
110+
plt.title(f'Histogram of Measurement Outcomes over {self.shots} Shots')
111+
plt.grid()
112+
plt.show()
113+
114+
def plot_estimated_field(self):
115+
"""Plot the estimated magnetic field against the actual magnetic field."""
116+
plt.figure(figsize=(10, 6))
117+
118+
plt.subplot(3, 1, 1)
119+
plt.plot(self.time_points, self.B[0], 'r-', label='Actual Bx')
120+
# Estimated Bx is a single value, plot as a horizontal line
121+
plt.axhline(self.estimated_Bx, color='blue', linestyle='--', label=f'Estimated Bx = {self.estimated_Bx:.2f}')
122+
plt.title('Estimated vs Actual Magnetic Field')
123+
plt.ylabel('Bx')
124+
plt.legend()
125+
plt.grid()
126+
127+
plt.subplot(3, 1, 2)
128+
plt.plot(self.time_points, self.B[1], 'g-', label='Actual By')
129+
# Estimated By is a single value, plot as a horizontal line
130+
plt.axhline(self.estimated_By, color='blue', linestyle='--', label=f'Estimated By = {self.estimated_By:.2f}')
131+
plt.ylabel('By')
132+
plt.legend()
133+
plt.grid()
134+
135+
plt.subplot(3, 1, 3)
136+
# Estimated Bz is fixed at 0 in this model, plot as a horizontal line
137+
plt.axhline(self.estimated_Bz, color='blue', linestyle='--', label='Estimated Bz = 0')
138+
plt.ylabel('Bz')
139+
plt.xlabel('Time')
140+
plt.legend()
141+
plt.grid()
142+
143+
plt.tight_layout()
144+
plt.show()
145+
146+
# Main execution
147+
if __name__ == "__main__":
148+
sensor = QuantumSensor(shots=1000, time_steps=100)
149+
sensor.simulate()
150+
sensor.plot_results()
151+
sensor.estimate_magnetic_field()
152+
153+
estimated_Bx, estimated_By, estimated_Bz = sensor.estimated_Bx, sensor.estimated_By, sensor.estimated_Bz
154+
print(f"Estimated Magnetic Field: Bx = {estimated_Bx:.2f}, By = {estimated_By:.2f}, Bz = {estimated_Bz:.2f}")
155+
156+
sensor.plot_estimated_field()
157+

0 commit comments

Comments
 (0)