Code Walkthrough
1. Initialization of Quantum Registers
The experiment uses a quantum register with 127 qubits, denoted as q_0, q_1, …, q_126.
A corresponding classical register is initialized to store the measurement results of the 127 qubits.
2. Bloch Clock Initialization
The first qubit q_0 is designated as the Bloch clock qubit.
The Bloch clock qubit is placed in a superposition state using the Hadamard gate:
H∣0⟩ = 1/sqrt(2) * (∣0⟩ + ∣1⟩)
The circuit applies the Hadamard gate to q_0, transforming its state into ∣+⟩, which lies on the equator of the Bloch sphere.
3. Superposition of the Remaining Qubits
Each of the remaining 126 qubits q_1, q_2, …, q_126 is placed into a superposition state using Hadamard gates:
H∣0⟩ = 1/sqrt(2) * (∣0⟩ + ∣1⟩)
After applying the Hadamard gates, each qubit is in a superposition of ∣0⟩ and ∣1⟩, creating a highly entangled system across the entire register.
4. Entanglement with the Bloch Clock
The Bloch clock qubit q_0 is entangled with each of the remaining 126 qubits using controlled-NOT gates. The operation for each qubit q_i is:
CNOT(q_0, q_i)
This operation entangles q_0 with all other qubits, meaning the state of q_0 influences the state of the entire system.
5. Bloch Clock Evolution
The Bloch clock qubit undergoes a series of rotations around the X, Y, and Z axes to simulate the passage of quantum 'time':
RX(θ) = e^(−i(θ/2)X)
RY(θ) = e^(−i(θ/2)Y)
RZ(θ) = e^(−i(θ/2)Z)
In this experiment, the angles for each rotation are set to π/4:
RX(π/4)
RY(π/4)
RZ(π/4)
These rotations move the Bloch clock qubit to different positions on the Bloch sphere, simulating the ticks of a clock.
6. Measurement of All Qubits
All 127 qubits are measured in the computational basis {∣0⟩, ∣1⟩}. The results of the measurement are stored in the classical register, collapsing the superposition of the 126 qubits and finalizing the state of the Bloch clock.
7. Transpilation and Execution on ibm_brisbane
The quantum circuit is transpiled to match the constraints of ibm_brisbane. The transpiled circuit is executed on IBM's 127-qubit quantum computer using the SamplerV2 primitive. The job is run with 8192 shots to gather sufficient data. The results are collected, and the counts for each measurement outcome are stored in a JSON.
8. Visualization
A histogram is generated to visualize the distribution of measurement outcomes across the 127 qubits. The final state of the Bloch clock qubit is shown separately to visualize its position on the Bloch sphere.
Code:
# imports
import numpy as np
import json
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, transpile
from qiskit_ibm_runtime import QiskitRuntimeService, Session, SamplerV2
from qiskit.visualization import plot_histogram, plot_bloch_multivector
from qiskit.quantum_info import Statevector
import matplotlib.pyplot as plt
# Initialize quantum register
qr = QuantumRegister(127) # 1 qubit for the Bloch clock, 126 qubits for the superposition
cr = ClassicalRegister(127) # Classical register to store the results
qc = QuantumCircuit(qr, cr)
# Step 1: Initialize the Bloch clock qubit (qr[0])
qc.h(qr[0]) # Start the Bloch clock in superposition (|+> state)
# Step 2: Create a superposition state across the 126 qubits
for i in range(1, 127):
qc.h(qr[i]) # Apply Hadamard gate to create superposition
# Step 3: Apply a quantum algorithm that will eventually lead to collapse
# Example: Entangling the Bloch clock with all other qubits
for i in range(1, 127):
qc. cx(qr[0], qr[i]) # Entangle the Bloch clock with all other qubits
# Step 4: Evolve the Bloch clock through some quantum gates
qc.rx(np.pi / 4, qr[0]) # Rotate Bloch clock around X-axis
qc.ry(np.pi / 4, qr[0]) # Rotate Bloch clock around Y-axis
qc.rz(np.pi / 4, qr[0]) # Rotate Bloch clock around Z-axis
# Step 5: Measure all qubits
qc.measure(qr, cr)
# Set up the IBMQ runtime service
service = QiskitRuntimeService(
channel='ibm_quantum',
instance='ibm-q/open/main',
token='YOUR_IBMQ_KEY_O-`'
)
# Define the backend
backend = service.backend('ibm_brisbane')
# Transpile the circuit to match the target backend
qc_transpiled = transpile(qc, backend)
# Execute the circuit on the backend with SamplerV2
with Session(service=service, backend=backend) as session:
sampler = SamplerV2(session=session)
# Run the transpiled circuit with the specified number of shots
job = sampler. run([qc_transpiled], shots=8192)
job_result = job.result()
# Retrieve the classical register name
classical_register = qc.cregs[0].name
# Extract counts for the first (and only) pub result
pub_result = job_result[0].data[classical_register].get_counts()
# Save the results to JSON
results_data = {
"raw_counts": pub_result
}
file_path = '/Users/Documents/quantum_clock_state_collapse_results_1.json'
with open(file_path, 'w') as f:
json.dump(results_data, f, indent=4)
# Plotting the results
plot_histogram(pub_result)
plt. show()
# Extract the operations that were applied to the Bloch clock qubit (qr[0])
qc_bloch_clock = QuantumCircuit(1)
qc_bloch_clock.h(0)
qc_bloch_clock.rx(np.pi / 4, 0)
qc_bloch_clock.ry(np.pi / 4, 0)
qc_bloch_clock.rz(np.pi / 4, 0)
# Simulate the state of the Bloch clock qubit
state_bloch_clock = Statevector.from_instruction(qc_bloch_clock)
# Plot the Bloch sphere for the Bloch clock qubit
plot_bloch_multivector(state_bloch_clock)
plt. show()
////////////////////////////////////////////////////////////////
Code for Color-Coded 3D Trajectory of Bloch Vector Over Time with Path Counts
# imports
import json
import base64
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
# Path to JSON files
result_path = '/Users/Documents/job-cv13d1mg9ymg0081fz0g quantum_clock_state_collapse_results_1 Run Data/job-cv13d1mg9ymg0081fz0g-result.json'
# Load the results from JSON files
with open(result_path, 'r') as file:
result_data = json.load(file)
# Extract and decode the bitstring data
bitstring_base64 = result_data["__value__"]["pub_results"][0]["__value__"]["data"]["__value__"]["fields"]["c0"]["__value__"]["array"]["__value__"]
bitstring_bytes = base64.b64decode(bitstring_base64)
bitstrings = [int(b) for b in bitstring_bytes]
# Convert the 8-bit values into binary strings
binary_bitstrings = [format(value, '08b') for value in bitstrings]
# Initialize lists to store the trajectory coordinates
x_coords = []
y_coords = []
z_coords = []
# Compute the Bloch vector for each measurement and store the coordinates
for binary_string in binary_bitstrings:
prob_0 = binary_string.count('0') / 8
theta = 2 * np.arccos(np.sqrt(prob_0))
phi = 0 # assuming no phase for simplicity
x_coords.append(np.sin(theta) * np.cos(phi))
y_coords.append(np.sin(theta) * np.sin(phi))
z_coords.append(np.cos(theta))
# Normalize the time steps for color mapping
time_steps = np.linspace(0, 1, len(x_coords)) # Normalize from 0 to 1 for colormap
# Set up the color map
colors = cm.viridis(time_steps) # Using the 'viridis' colormap
# Plot the 3D trajectory with color-coded time evolution
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# Plot the Bloch sphere
u, v = np.mgrid[0:2*np.pi:100j, 0:np.pi:50j]
x = np.sin(v) * np.cos(u)
y = np.sin(v) * np.sin(u)
z = np.cos(v)
ax.plot_wireframe(x, y, z, color="lightgrey", alpha=0.5)
# Plot the trajectory, using color coding for time evolution
num_paths = 0
for i in range(1, len(x_coords)):
ax.plot(x_coords[i-1:i+1], y_coords[i-1:i+1], z_coords[i-1:i+1], color=colors[i], linewidth=2)
num_paths += 1 # Count each path segment
# Print the number of paths
print(f"Number of paths counted: {num_paths}")
# Setting labels and title
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title("Color-Coded 3D Trajectory of Bloch Vector Over Time")
plt. show()
////////////////////////////////////////////////////////////////
Code for Heatmap of Collapse Probabilities vs. Quantum Clock State
# imports
import json
import zlib
import base64
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Paths to JSON files
backend_results_path = '/Users/Documents/job-cv13d1mg9ymg0081fz0g quantum_clock_state_collapse_results_1 Run Data/job-cv13d1mg9ymg0081fz0g-result.json'
# Load JSON data
with open(backend_results_path) as f:
backend_results = json.load(f)
# Navigate to encoded data
encoded_data = backend_results['__value__']['pub_results'][0]['__value__']['data']['__value__']['fields']['c0']['__value__']['array']['__value__']
# Decode the base64-encoded and compressed data
compressed_data = base64.b64decode(encoded_data)
decompressed_data = zlib.decompress(compressed_data)
# Skip the header and load the numpy array
header_length = 128 # Assuming the header is 128 bytes long based on typical .npy headers
probabilities = np.frombuffer(decompressed_data[header_length:], dtype=np.uint8).reshape(8192, 16)
# Normalize the probabilities for visualization
probabilities = probabilities.astype(np.float64)
probabilities /= probabilities.sum(axis=1, keepdims=True)
# Create a heatmap
plt.figure(figsize=(12, 8))
sns.heatmap(probabilities, xticklabels=False, yticklabels=False, cmap='coolwarm')
plt.title("Heatmap of Collapse Probabilities vs. Quantum Clock State")
plt.xlabel("Qubit State Index")
plt.ylabel("Quantum Clock Phase")
# Save the heatmap
plt.savefig('/Users/Documents/job-cv13d1mg9ymg0081fz0g quantum_clock_state_collapse_results_1 Run Data/collapse_probabilities_heatmap.png')
plt. show()
////////////////////////////////////////////////////////////////
Code for Probability Distribution Over Time Visual
import json
import base64
import numpy as np
import matplotlib.pyplot as plt
# Path to JSON files
result_path = '/Users/Documents/job-cv13d1mg9ymg0081fz0g quantum_clock_state_collapse_results_1 Run Data/job-cv13d1mg9ymg0081fz0g-result.json'
# Load the results from JSON
with open(result_path, 'r') as file:
result_data = json.load(file)
# Extract and decode the bitstring data
bitstring_base64 = result_data["__value__"]["pub_results"][0]["__value__"]["data"]["__value__"]["fields"]["c0"]["__value__"]["array"]["__value__"]
bitstring_bytes = base64.b64decode(bitstring_base64)
bitstrings = [int(b) for b in bitstring_bytes]
# Convert the 8-bit values into binary strings
binary_bitstrings = [format(value, '08b') for value in bitstrings]
# Initialize lists to store the probabilities
probabilities_0 = []
probabilities_1 = []
# Compute the probabilities for each measurement
for binary_string in binary_bitstrings:
prob_0 = binary_string.count('0') / 8
prob_1 = 1 - prob_0 # Since prob_0 + prob_1 = 1
probabilities_0.append(prob_0)
probabilities_1.append(prob_1)
# Number of time slices
time_slices = 10
slice_indices = np.linspace(0, len(probabilities_0)-1, time_slices, dtype=int)
# Create subplots for histograms
fig, axes = plt.subplots(2, time_slices//2, figsize=(16, 6))
for i, ax in enumerate(axes.flat):
index = slice_indices[i]
ax. bar([0, 1], [probabilities_0[index], probabilities_1[index]], color=['blue', 'red'])
ax.set_ylim(0, 1)
ax.set_xticks([0, 1])
ax.set_xticklabels(['P(0)', 'P(1)'])
ax.set_title(f'Time Slice {i+1}')
plt.suptitle('Probability Distribution Over Time')
plt.tight_layout()
plt. show()
////////////////////////////////////////////////////////////////
Code for First 10 Quantum State Changes on the Bloch Sphere
import json
import base64
import numpy as np
from qiskit.visualization import plot_bloch_multivector
from qiskit.quantum_info import Statevector
import matplotlib.pyplot as plt
from PIL import Image
import io
# Load the JSON data
file_path = '/Users/Documents/job-cv13d1mg9ymg0081fz0g quantum_clock_state_collapse_results_1 Run Data/job-cv13d1mg9ymg0081fz0g-result.json'
with open(file_path, 'r') as file:
data = json.load(file)
# Decode the base64 string
bitarray_base64 = data['__value__']['pub_results'][0]['__value__']['data']['__value__']['fields']['c0']['__value__']['array']['__value__']
bitarray_bytes = base64.b64decode(bitarray_base64)
# Convert to binary representation
bitstrings = [format(byte, '08b') for byte in bitarray_bytes]
bitstring = ''.join(bitstrings)[:len(bitarray_bytes) * 8]
# Initialize a list to store images
images = []
# Start with the |0⟩ state (north pole)
state = Statevector([1, 0])
# Collect the first 10 state changes and generate images
for i, bit in enumerate(bitstring[:10]):
if bit == '0':
state = Statevector([1, 0]) # |0⟩ state
elif bit == '1':
state = Statevector([0, 1]) # |1⟩ state
# Generate the Bloch sphere plot and save it to an image in memory
img_buf = io.BytesIO()
plot_bloch_multivector(state).savefig(img_buf, format='png')
img_buf.seek(0)
images.append(Image. open(img_buf))
# Create a new figure for the grid of subplots
fig, axes = plt.subplots(2, 5, figsize=(20, 10))
# Arrange the images on the grid
for i, ax in enumerate(axes.flat):
ax.imshow(images[i])
ax.axis('off')
ax.set_title(f'State at tick {i+1}: |{bitstring[i]}⟩')
plt.suptitle('First 10 Quantum State Changes on the Bloch Sphere')
plt. show()
# End