Skip to content

Commit 6531566

Browse files
authored
Merge pull request #124 from YousefElbrolosy/implement-grape-cnot-tutorial
Migrate optimal control notebook to qutip-tutorials
2 parents b24e4ca + cead2b9 commit 6531566

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
---
2+
jupyter:
3+
jupytext:
4+
text_representation:
5+
extension: .md
6+
format_name: markdown
7+
format_version: '1.3'
8+
jupytext_version: 1.17.0
9+
kernelspec:
10+
display_name: qiskit-stable8
11+
language: python
12+
name: python3
13+
---
14+
15+
### GRAPE calculation of control fields for cnot implementation
16+
17+
[This is an updated implementation based on the deprecated notebook of GRAPE CNOT implementation by Robert Johansson](https://nbviewer.org/github/qutip/qutip-notebooks/blob/master/examples/control-grape-cnot.ipynb)
18+
19+
```python
20+
import matplotlib.pyplot as plt
21+
import numpy as np
22+
import qutip as qt
23+
# the library for quantum control
24+
import qutip_qtrl.pulseoptim as cpo
25+
```
26+
27+
```python
28+
# total duration
29+
T = 2 * np.pi
30+
# number of time steps
31+
times = np.linspace(0, T, 500)
32+
```
33+
34+
```python
35+
U_0 = qt.operators.identity(4)
36+
U_target = qt.core.gates.cnot()
37+
```
38+
39+
### Starting Point
40+
41+
```python
42+
U_0
43+
```
44+
45+
### Target Operator
46+
47+
```python
48+
U_target
49+
```
50+
51+
```python
52+
# Drift Hamiltonian
53+
g = 0
54+
H_drift = g * (
55+
qt.tensor(qt.sigmax(), qt.sigmax()) + qt.tensor(qt.sigmay(), qt.sigmay())
56+
)
57+
```
58+
59+
```python
60+
H_ctrl = [
61+
qt.tensor(qt.sigmax(), qt.identity(2)),
62+
qt.tensor(qt.sigmay(), qt.identity(2)),
63+
qt.tensor(qt.sigmaz(), qt.identity(2)),
64+
qt.tensor(qt.identity(2), qt.sigmax()),
65+
qt.tensor(qt.identity(2), qt.sigmay()),
66+
qt.tensor(qt.identity(2), qt.sigmaz()),
67+
qt.tensor(qt.sigmax(), qt.sigmax()),
68+
qt.tensor(qt.sigmay(), qt.sigmay()),
69+
qt.tensor(qt.sigmaz(), qt.sigmaz()),
70+
]
71+
```
72+
73+
```python
74+
H_labels = [
75+
r"$u_{1x}$",
76+
r"$u_{1y}$",
77+
r"$u_{1z}$",
78+
r"$u_{2x}$",
79+
r"$u_{2y}$",
80+
r"$u_{2z}$",
81+
r"$u_{xx}$",
82+
r"$u_{yy}$",
83+
r"$u_{zz}$",
84+
]
85+
```
86+
87+
## GRAPE
88+
89+
```python
90+
result = cpo.optimize_pulse_unitary(
91+
H_drift,
92+
H_ctrl,
93+
U_0,
94+
U_target,
95+
num_tslots=500,
96+
evo_time=(2 * np.pi),
97+
# this attribute is crucial for convergence!!
98+
amp_lbound=-(2 * np.pi * 0.05),
99+
amp_ubound=(2 * np.pi * 0.05),
100+
fid_err_targ=1e-9,
101+
max_iter=500,
102+
max_wall_time=60,
103+
alg="GRAPE",
104+
optim_method="FMIN_L_BFGS_B",
105+
method_params={
106+
"disp": True,
107+
"maxiter": 1000,
108+
},
109+
)
110+
```
111+
112+
```python
113+
for attr in dir(result):
114+
if not attr.startswith("_"):
115+
print(f"{attr}: {getattr(result, attr)}")
116+
117+
print(np.shape(result.final_amps))
118+
```
119+
120+
## Plot control fields for cnot gate in the presense of single-qubit tunnelling
121+
122+
```python
123+
def plot_control_amplitudes(times, final_amps, labels):
124+
num_controls = final_amps.shape[1]
125+
126+
y_max = 0.1 # Fixed y-axis scale
127+
y_min = -0.1
128+
129+
for i in range(num_controls):
130+
fig, ax = plt.subplots(figsize=(8, 3))
131+
132+
for j in range(num_controls):
133+
# Highlight the current control
134+
color = "black" if i == j else "gray"
135+
alpha = 1.0 if i == j else 0.1
136+
ax.plot(
137+
times,
138+
final_amps[:, j],
139+
label=labels[j],
140+
color=color,
141+
alpha=alpha
142+
)
143+
ax.set_title(f"Control Fields Highlighting: {labels[i]}")
144+
ax.set_xlabel("Time")
145+
ax.set_ylabel(labels[i])
146+
ax.set_ylim(y_min, y_max) # Set fixed y-axis limits
147+
ax.grid(True)
148+
ax.legend()
149+
plt.tight_layout()
150+
plt.show()
151+
152+
153+
plot_control_amplitudes(times, result.final_amps / (2 * np.pi), H_labels)
154+
```
155+
156+
## Fidelity/overlap
157+
158+
```python
159+
U_target
160+
```
161+
162+
```python
163+
U_f = result.evo_full_final
164+
U_f.dims = [[2, 2], [2, 2]]
165+
```
166+
167+
```python
168+
U_f
169+
```
170+
171+
```python
172+
print(f"Fidelity: {qt.process_fidelity(U_f, U_target)}")
173+
```
174+
175+
## Proceess tomography
176+
177+
178+
Quantum Process Tomography (QPT) is a technique used to characterize an unknown quantum operation by reconstructing its process matrix (also called the χ (chi) matrix). This matrix describes how an input quantum state is transformed by the operation.
179+
180+
181+
Defines the basis operators
182+
{
183+
𝐼
184+
,
185+
𝑋
186+
,
187+
𝑌
188+
,
189+
𝑍
190+
}
191+
for the two-qubit system.
192+
193+
These operators form a complete basis to describe any quantum operation in the Pauli basis.
194+
195+
196+
### Ideal cnot gate
197+
198+
```python
199+
op_basis = [[qt.qeye(2), qt.sigmax(), qt.sigmay(), qt.sigmaz()]] * 2
200+
op_label = [["i", "x", "y", "z"]] * 2
201+
```
202+
203+
U_target is the ideal CNOT gate.
204+
205+
qt.to_super(U_target) converts it into superoperator form, which is necessary for QPT.
206+
207+
qt.qpt(U_i_s, op_basis) computes the χ matrix for the ideal gate.
208+
209+
```python
210+
fig = plt.figure(figsize=(12, 6))
211+
212+
U_i_s = qt.to_super(U_target)
213+
214+
chi = qt.qpt(U_i_s, op_basis)
215+
216+
fig = qt.qpt_plot_combined(chi, op_label, fig=fig, threshold=0.001)
217+
```
218+
219+
```python
220+
op_basis = [[qt.qeye(2), qt.sigmax(), qt.sigmay(), qt.sigmaz()]] * 2
221+
op_label = [["i", "x", "y", "z"]] * 2
222+
```
223+
224+
```python
225+
fig = plt.figure(figsize=(12, 6))
226+
227+
U_f_s = qt.to_super(U_f)
228+
229+
chi = qt.qpt(U_f_s, op_basis)
230+
231+
fig = qt.qpt_plot_combined(chi, op_label, fig=fig, threshold=0.01)
232+
```
233+
234+
## Versions
235+
236+
237+
```python
238+
qt.about()
239+
```

0 commit comments

Comments
 (0)