Skip to content

Commit 3f0ebb1

Browse files
Added TEBD and state vector simulation
1 parent ac5974f commit 3f0ebb1

File tree

2 files changed

+189
-11
lines changed

2 files changed

+189
-11
lines changed

src/yaqs/noise_char/BFGS_tjm.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,6 @@ def loss_function_char(state, H_0, sim_params, noise_model, ref_traj, traj_der):
195195

196196
if __name__ == '__main__':
197197

198-
# @dataclass
199-
# class SimulationParameters:
200-
# T: float = 1
201-
# dt: float = 0.1
202-
# L: int = 2
203-
# J: float = 1
204-
# g: float = 0.5
205-
# gamma_rel: float = 0.1
206-
# gamma_deph: float = 0.1
207198

208199

209200
L = 4
@@ -218,14 +209,14 @@ def loss_function_char(state, H_0, sim_params, noise_model, ref_traj, traj_der):
218209

219210
# Define the noise model
220211
gamma = 0.1
221-
noise_model = NoiseModel(['relaxation', 'dephasing'], [gamma, gamma])
212+
noise_model = NoiseModel(['relaxation', 'dephasing'], [0.2, 0.01])
222213

223214

224215
# Define the simulation parameters
225216
T = 5
226217
dt = 0.1
227218
sample_timesteps = True
228-
N = 100
219+
N = 500
229220
max_bond_dim = 4
230221
threshold = 1e-6
231222
order = 1
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
4+
from qiskit import QuantumCircuit, transpile
5+
from qiskit_aer import AerSimulator
6+
import qiskit.quantum_info as qi
7+
8+
9+
10+
'''This file contains
11+
12+
-TEBD simulation of quantum circuits (including hard/soft truncation)
13+
14+
-statevector simulation of quantum circuits
15+
16+
both methods are implemented using qiskit-aer simulator.'''
17+
18+
def expectation_value(rho, op):
19+
"""Compute the expectation value of observable op given a density matrix rho."""
20+
return np.real(np.trace(rho.data @ op))
21+
22+
23+
24+
25+
26+
def TEBD_evolve(initial_state, circuit, observables, max_bond=8, threshold=1e-10):
27+
"""
28+
Evolves an initial state through a circuit using TEBD and snapshots.
29+
30+
Parameters:
31+
initial_state (array-like): The statevector for the initial state.
32+
circuit (QuantumCircuit): A QuantumCircuit object (without snapshots).
33+
observables (dict): A dictionary of observables (name: 2x2 numpy array).
34+
35+
36+
Returns:
37+
snapshot_labels (list): List of snapshot labels corresponding to time steps.
38+
expectations (dict): Dictionary mapping snapshot labels to a dictionary of
39+
qubit expectation values for each observable.
40+
Format: { snapshot_label: { qubit_index: {obs_name: value, ...}, ... }, ... }
41+
"""
42+
n = circuit.num_qubits
43+
# Create a new circuit that will include initialization and snapshots.
44+
evolved_circuit = QuantumCircuit(n)
45+
snapshot_labels = []
46+
47+
# If an initial state is provided, initialize the qubits.
48+
if initial_state is not None:
49+
evolved_circuit.initialize(initial_state, range(n))
50+
# Snapshot the initial state.
51+
label = "t0"
52+
evolved_circuit.save_statevector(label=label)
53+
snapshot_labels.append(label)
54+
55+
# Append every instruction from the input circuit and insert a snapshot after each.
56+
for i, (instr, qargs, cargs) in enumerate(circuit.data):
57+
evolved_circuit.append(instr, qargs, cargs)
58+
label = f"t{i+1}"
59+
evolved_circuit.save_statevector(label=label)
60+
snapshot_labels.append(label)
61+
62+
# Transpile and simulate the circuit with the desired backend.
63+
simulator = AerSimulator(method='matrix_product_state', matrix_product_state_max_bond_dimension = max_bond, matrix_product_state_truncation_threshold = threshold)
64+
evolved_circuit = transpile(evolved_circuit, simulator)
65+
result = simulator.run(evolved_circuit).result()
66+
states_data = result.data(0) # Dictionary mapping snapshot labels to statevectors.
67+
68+
# Compute expectation values.
69+
expectations = {}
70+
for label in snapshot_labels:
71+
state = states_data[label]
72+
rho = qi.DensityMatrix(state)
73+
expectations[label] = {}
74+
for qubit in range(n):
75+
# Trace out all qubits except the current one.
76+
traced_out = [i for i in range(n) if i != qubit]
77+
rho_reduced = qi.partial_trace(rho, traced_out)
78+
expectations[label][qubit] = {}
79+
for obs_name, op in observables.items():
80+
expectations[label][qubit][obs_name] = expectation_value(rho_reduced, op)
81+
return snapshot_labels, expectations
82+
83+
84+
85+
86+
87+
def statevector_evolve(initial_state, circuit, observables):
88+
"""
89+
Evolves an initial state through a circuit using TEBD and snapshots.
90+
91+
Parameters:
92+
initial_state (array-like): The statevector for the initial state.
93+
circuit (QuantumCircuit): A QuantumCircuit object (without snapshots).
94+
observables (dict): A dictionary of observables (name: 2x2 numpy array).
95+
simulator_method (str): The simulation method; default is 'matrix_product_state'.
96+
97+
Returns:
98+
snapshot_labels (list): List of snapshot labels corresponding to time steps.
99+
expectations (dict): Dictionary mapping snapshot labels to a dictionary of
100+
qubit expectation values for each observable.
101+
Format: { snapshot_label: { qubit_index: {obs_name: value, ...}, ... }, ... }
102+
"""
103+
n = circuit.num_qubits
104+
# Create a new circuit that will include initialization and snapshots.
105+
evolved_circuit = QuantumCircuit(n)
106+
snapshot_labels = []
107+
108+
# If an initial state is provided, initialize the qubits.
109+
if initial_state is not None:
110+
evolved_circuit.initialize(initial_state, range(n))
111+
# Snapshot the initial state.
112+
label = "t0"
113+
evolved_circuit.save_statevector(label=label)
114+
snapshot_labels.append(label)
115+
116+
# Append every instruction from the input circuit and insert a snapshot after each.
117+
for i, (instr, qargs, cargs) in enumerate(circuit.data):
118+
evolved_circuit.append(instr, qargs, cargs)
119+
label = f"t{i+1}"
120+
evolved_circuit.save_statevector(label=label)
121+
snapshot_labels.append(label)
122+
123+
# Transpile and simulate the circuit with the desired backend.
124+
simulator = AerSimulator(method='statevector')
125+
evolved_circuit = transpile(evolved_circuit, simulator)
126+
result = simulator.run(evolved_circuit).result()
127+
states_data = result.data(0) # Dictionary mapping snapshot labels to statevectors.
128+
129+
# Compute expectation values.
130+
expectations = {}
131+
for label in snapshot_labels:
132+
state = states_data[label]
133+
rho = qi.DensityMatrix(state)
134+
expectations[label] = {}
135+
for qubit in range(n):
136+
# Trace out all qubits except the current one.
137+
traced_out = [i for i in range(n) if i != qubit]
138+
rho_reduced = qi.partial_trace(rho, traced_out)
139+
expectations[label][qubit] = {}
140+
for obs_name, op in observables.items():
141+
expectations[label][qubit][obs_name] = expectation_value(rho_reduced, op)
142+
return snapshot_labels, expectations
143+
144+
if __name__ == '__main__':
145+
# Define Pauli matrices as observables.
146+
X = np.array([[0, 1], [1, 0]])
147+
Y = np.array([[0, -1j], [1j, 0]])
148+
Z = np.array([[1, 0], [0, -1]])
149+
observables = {'X': X, 'Y': Y, 'Z': Z}
150+
151+
# Define the initial state for 2 qubits: |00>
152+
initial_state = [1, 0, 0, 0]
153+
154+
# Create an example circuit (without measurements).
155+
circuit = QuantumCircuit(2)
156+
circuit.h(0)
157+
circuit.cx(0, 1)
158+
circuit.ry(0.5, 0)
159+
circuit.rx(0.7, 1)
160+
circuit.cz(0, 1)
161+
162+
# Evolve the circuit using TEBD_evolve with the MPS backend.
163+
snapshot_labels, expectations = TEBD_evolve(initial_state, circuit, observables, 4)
164+
165+
# Print the computed expectation values per timestep.
166+
print("Expectation values per timestep:")
167+
for label in snapshot_labels:
168+
print(f"Time step '{label}':")
169+
for qubit in expectations[label]:
170+
print(f" Qubit {qubit}: {expectations[label][qubit]}")
171+
172+
# Plot the expectation values.
173+
steps = np.arange(len(snapshot_labels))
174+
plt.figure(figsize=(10, 6))
175+
num_qubits = circuit.num_qubits
176+
for qubit in range(num_qubits):
177+
for obs_name in observables.keys():
178+
values = [expectations[label][qubit][obs_name] for label in snapshot_labels]
179+
plt.plot(steps, values, marker='o', label=f"Qubit {qubit} {obs_name}")
180+
plt.xticks(steps, snapshot_labels)
181+
plt.xlabel("Time step")
182+
plt.ylabel("Expectation value")
183+
plt.title("Expectation values of observables for all qubits (MPS Backend)")
184+
plt.legend()
185+
plt.tight_layout()
186+
plt.show()
187+

0 commit comments

Comments
 (0)