0
# Process Tomography and Characterization
1
2
Quantum process tomography tools for characterizing quantum operations and noise processes.
3
4
## Capabilities
5
6
### Quantum Process Tomography
7
8
Reconstruct quantum processes from measurement data.
9
10
```python { .api }
11
def qpt(U: Qobj, op_basis: list = None) -> Qobj:
12
"""
13
Calculate quantum process tomography chi-matrix from unitary.
14
15
Parameters:
16
- U: Unitary operator or superoperator to characterize
17
- op_basis: Operator basis for process representation (default: Pauli basis)
18
19
Returns:
20
- Qobj: Chi-matrix representation of quantum process
21
"""
22
23
def qpt_plot(chi: Qobj, lbls_list: list = None, title: str = None,
24
fig: object = None, threshold: float = None) -> None:
25
"""
26
Plot quantum process tomography chi-matrix.
27
28
Parameters:
29
- chi: Chi-matrix from QPT
30
- lbls_list: Labels for process basis elements
31
- title: Plot title
32
- fig: Matplotlib figure object
33
- threshold: Minimum value to display
34
"""
35
36
def qpt_plot_combined(chi: Qobj, lbls_list: list = None, title: str = None,
37
fig: object = None, threshold: float = 0.01) -> None:
38
"""
39
Plot combined real and imaginary parts of chi-matrix.
40
41
Parameters:
42
- chi: Chi-matrix from QPT
43
- lbls_list: Labels for basis elements
44
- title: Plot title
45
- fig: Matplotlib figure
46
- threshold: Display threshold for matrix elements
47
"""
48
```
49
50
### Process Characterization
51
52
Analyze and characterize quantum processes and channels.
53
54
```python { .api }
55
def process_fidelity(chi1: Qobj, chi2: Qobj) -> float:
56
"""
57
Calculate fidelity between two quantum processes.
58
59
Parameters:
60
- chi1: First process chi-matrix
61
- chi2: Second process chi-matrix
62
63
Returns:
64
- float: Process fidelity (0 to 1)
65
"""
66
67
def average_gate_fidelity(chi: Qobj, target_U: Qobj = None) -> float:
68
"""
69
Calculate average gate fidelity of quantum process.
70
71
Parameters:
72
- chi: Process chi-matrix
73
- target_U: Target unitary (identity if None)
74
75
Returns:
76
- float: Average gate fidelity
77
"""
78
```
79
80
### Pauli Transfer Matrix
81
82
Pauli transfer matrix representation of quantum channels.
83
84
```python { .api }
85
def chi_to_pauli_transfer(chi: Qobj) -> np.ndarray:
86
"""
87
Convert chi-matrix to Pauli transfer matrix representation.
88
89
Parameters:
90
- chi: Chi-matrix in Pauli basis
91
92
Returns:
93
- ndarray: Pauli transfer matrix
94
"""
95
96
def pauli_transfer_to_chi(R: np.ndarray) -> Qobj:
97
"""
98
Convert Pauli transfer matrix to chi-matrix.
99
100
Parameters:
101
- R: Pauli transfer matrix
102
103
Returns:
104
- Qobj: Chi-matrix representation
105
"""
106
```
107
108
### Usage Examples
109
110
```python
111
import qutip as qt
112
import numpy as np
113
import matplotlib.pyplot as plt
114
115
# Single-qubit process tomography examples
116
117
# 1. Perfect gates
118
print("=== Perfect Gate Process Tomography ===")
119
120
# Identity gate
121
I_gate = qt.qeye(2)
122
chi_I = qt.qpt(I_gate)
123
print(f"Identity gate chi-matrix:")
124
print(f" Shape: {chi_I.shape}")
125
print(f" Real part diagonal: {np.diag(chi_I.full().real)}")
126
127
# Pauli-X gate
128
X_gate = qt.sigmax()
129
chi_X = qt.qpt(X_gate)
130
131
# Pauli-Y gate
132
Y_gate = qt.sigmay()
133
chi_Y = qt.qpt(Y_gate)
134
135
# Pauli-Z gate
136
Z_gate = qt.sigmaz()
137
chi_Z = qt.qpt(Z_gate)
138
139
# Hadamard gate
140
H_gate = (qt.sigmax() + qt.sigmaz()).unit()
141
chi_H = qt.qpt(H_gate)
142
143
# Process fidelities with perfect gates
144
perfect_gates = {
145
'I': (I_gate, chi_I),
146
'X': (X_gate, chi_X),
147
'Y': (Y_gate, chi_Y),
148
'Z': (Z_gate, chi_Z),
149
'H': (H_gate, chi_H)
150
}
151
152
print("Perfect gate process fidelities (should be 1.0):")
153
for name, (gate, chi) in perfect_gates.items():
154
# Compare with itself
155
fid = qt.process_fidelity(chi, chi)
156
print(f" {name} gate: {fid:.6f}")
157
158
# Cross-fidelities between different gates
159
print("Cross-fidelities between different perfect gates:")
160
gate_names = list(perfect_gates.keys())
161
for i, name1 in enumerate(gate_names):
162
for j, name2 in enumerate(gate_names):
163
if i < j: # Only upper triangle
164
chi1 = perfect_gates[name1][1]
165
chi2 = perfect_gates[name2][1]
166
fid = qt.process_fidelity(chi1, chi2)
167
print(f" {name1}-{name2}: {fid:.3f}")
168
169
# 2. Noisy gates (depolarizing noise)
170
print("\n=== Noisy Gate Process Tomography ===")
171
172
def depolarizing_noise(U, p):
173
"""Add depolarizing noise to unitary gate."""
174
# Kraus operators for depolarizing channel after unitary
175
I = qt.qeye(2)
176
X = qt.sigmax()
177
Y = qt.sigmay()
178
Z = qt.sigmaz()
179
180
K0 = np.sqrt(1 - 3*p/4) * U
181
K1 = np.sqrt(p/4) * X * U
182
K2 = np.sqrt(p/4) * Y * U
183
K3 = np.sqrt(p/4) * Z * U
184
185
return [K0, K1, K2, K3]
186
187
# Noisy X gate
188
p_noise = 0.1 # 10% depolarizing noise
189
noisy_X_kraus = depolarizing_noise(X_gate, p_noise)
190
191
# Convert Kraus to superoperator for QPT
192
def kraus_to_super(kraus_ops):
193
"""Convert Kraus operators to superoperator."""
194
N = kraus_ops[0].shape[0]
195
S = qt.Qobj(np.zeros((N**2, N**2)), dims=[[[N],[N]], [[N],[N]]])
196
197
for K in kraus_ops:
198
S += qt.sprepost(K, K.dag())
199
200
return S
201
202
S_noisy_X = kraus_to_super(noisy_X_kraus)
203
chi_noisy_X = qt.qpt(S_noisy_X)
204
205
# Compare noisy vs perfect X gate
206
fid_noisy = qt.process_fidelity(chi_X, chi_noisy_X)
207
print(f"Noisy X gate (p={p_noise}) vs perfect X gate fidelity: {fid_noisy:.3f}")
208
209
# Average gate fidelity
210
avg_fid = qt.average_gate_fidelity(chi_noisy_X, X_gate)
211
print(f"Average gate fidelity of noisy X gate: {avg_fid:.3f}")
212
213
# 3. Two-qubit process tomography
214
print("\n=== Two-Qubit Process Tomography ===")
215
216
# CNOT gate
217
CNOT = qt.cnot()
218
chi_CNOT = qt.qpt(CNOT)
219
print(f"CNOT chi-matrix shape: {chi_CNOT.shape}")
220
221
# Controlled-Z gate
222
CZ = qt.cz_gate()
223
chi_CZ = qt.qpt(CZ)
224
225
# Process fidelity between CNOT and CZ
226
fid_CNOT_CZ = qt.process_fidelity(chi_CNOT, chi_CZ)
227
print(f"CNOT vs CZ process fidelity: {fid_CNOT_CZ:.3f}")
228
229
# 4. Amplitude damping channel
230
print("\n=== Amplitude Damping Channel ===")
231
232
def amplitude_damping_kraus(gamma):
233
"""Amplitude damping Kraus operators."""
234
K0 = qt.Qobj([[1, 0], [0, np.sqrt(1-gamma)]])
235
K1 = qt.Qobj([[0, np.sqrt(gamma)], [0, 0]])
236
return [K0, K1]
237
238
gamma = 0.2
239
AD_kraus = amplitude_damping_kraus(gamma)
240
S_AD = kraus_to_super(AD_kraus)
241
chi_AD = qt.qpt(S_AD)
242
243
print(f"Amplitude damping (γ={gamma}) chi-matrix computed")
244
245
# Test on different input states
246
test_states = [
247
qt.basis(2, 0), # |0⟩
248
qt.basis(2, 1), # |1⟩
249
(qt.basis(2,0) + qt.basis(2,1)).unit() # |+⟩
250
]
251
252
print("Amplitude damping effect on different states:")
253
for i, psi in enumerate(test_states):
254
rho_in = psi * psi.dag()
255
256
# Apply channel using Kraus operators
257
rho_out = sum(K * rho_in * K.dag() for K in AD_kraus)
258
259
# Calculate excited state population
260
pop_in = qt.expect(qt.num(2), rho_in)
261
pop_out = qt.expect(qt.num(2), rho_out)
262
263
state_names = ['|0⟩', '|1⟩', '|+⟩']
264
print(f" {state_names[i]}: population {pop_in:.1f} → {pop_out:.3f}")
265
266
# 5. Process tomography visualization
267
print("\n=== Process Visualization ===")
268
269
# Generate Pauli basis labels for single qubit
270
pauli_labels = ['I', 'X', 'Y', 'Z']
271
272
print("Chi-matrix elements for different processes:")
273
274
# Perfect X gate
275
print("Perfect X gate (should have chi_XX = 1):")
276
chi_X_full = chi_X.full()
277
for i, label_i in enumerate(pauli_labels):
278
for j, label_j in enumerate(pauli_labels):
279
element = chi_X_full[i, j]
280
if abs(element) > 0.01: # Only show significant elements
281
print(f" χ_{label_i}{label_j} = {element:.3f}")
282
283
# Noisy X gate
284
print(f"\nNoisy X gate (p={p_noise}):")
285
chi_noisy_X_full = chi_noisy_X.full()
286
for i, label_i in enumerate(pauli_labels):
287
for j, label_j in enumerate(pauli_labels):
288
element = chi_noisy_X_full[i, j]
289
if abs(element) > 0.01:
290
print(f" χ_{label_i}{label_j} = {element:.3f}")
291
292
# 6. Pauli transfer matrix representation
293
print("\n=== Pauli Transfer Matrix ===")
294
295
# Convert chi-matrix to Pauli transfer matrix
296
R_X = qt.chi_to_pauli_transfer(chi_X)
297
print("Perfect X gate Pauli transfer matrix:")
298
print("(Maps Pauli expectation values: ⟨σᵢ⟩_out = Σⱼ Rᵢⱼ ⟨σⱼ⟩_in)")
299
300
pauli_ops = [qt.qeye(2), qt.sigmax(), qt.sigmay(), qt.sigmaz()]
301
for i, op_i in enumerate(pauli_ops):
302
for j, op_j in enumerate(pauli_ops):
303
if abs(R_X[i, j]) > 0.01:
304
print(f" R_{pauli_labels[i]}{pauli_labels[j]} = {R_X[i, j]:6.3f}")
305
306
# Verify: X gate should map σz → -σz, σy → -σy, σx → σx, I → I
307
print("Expected: X maps σz→-σz, σy→-σy, σx→σx, I→I")
308
309
# Convert back to chi-matrix
310
chi_X_reconstructed = qt.pauli_transfer_to_chi(R_X)
311
reconstruction_fidelity = qt.process_fidelity(chi_X, chi_X_reconstructed)
312
print(f"PTM reconstruction fidelity: {reconstruction_fidelity:.6f}")
313
314
# 7. Process tomography from experimental data (simulation)
315
print("\n=== Experimental Process Tomography Simulation ===")
316
317
def simulate_qpt_experiment(true_process_kraus, n_measurements=1000):
318
"""
319
Simulate QPT experiment with finite measurement statistics.
320
"""
321
# Input states for process tomography (Pauli eigenstates)
322
input_states = [
323
qt.basis(2, 0), # |0⟩ (σz eigenstate)
324
qt.basis(2, 1), # |1⟩ (σz eigenstate)
325
(qt.basis(2,0) + qt.basis(2,1)).unit(), # |+⟩ (σx eigenstate)
326
(qt.basis(2,0) - qt.basis(2,1)).unit(), # |-⟩ (σx eigenstate)
327
(qt.basis(2,0) + 1j*qt.basis(2,1)).unit(), # |+i⟩ (σy eigenstate)
328
(qt.basis(2,0) - 1j*qt.basis(2,1)).unit(), # |-i⟩ (σy eigenstate)
329
]
330
331
# Measurement operators (Pauli measurements)
332
measurement_ops = [qt.qeye(2), qt.sigmax(), qt.sigmay(), qt.sigmaz()]
333
334
print(f"Simulating QPT with {n_measurements} measurements per configuration...")
335
336
# For each input state, apply process and measure
337
results = []
338
for psi_in in input_states:
339
rho_in = psi_in * psi_in.dag()
340
341
# Apply process
342
rho_out = sum(K * rho_in * K.dag() for K in true_process_kraus)
343
344
# Measure expectation values
345
expectations = []
346
for M in measurement_ops:
347
# True expectation value
348
exp_true = qt.expect(M, rho_out)
349
350
# Add statistical noise (simulate finite measurements)
351
measurement_noise = np.random.normal(0, 1/np.sqrt(n_measurements))
352
exp_measured = exp_true + measurement_noise
353
354
expectations.append(exp_measured)
355
356
results.append(expectations)
357
358
return results
359
360
# Simulate experiment for noisy X gate
361
experimental_data = simulate_qpt_experiment(noisy_X_kraus, n_measurements=5000)
362
363
print("Experimental QPT simulation completed")
364
print("(In real experiment, this data would be used to reconstruct chi-matrix)")
365
print("Sample expectation values for first input state:")
366
for i, exp_val in enumerate(experimental_data[0]):
367
print(f" ⟨{pauli_labels[i]}⟩ = {exp_val:.3f}")
368
369
# 8. Gate set tomography concept (simplified)
370
print("\n=== Gate Set Analysis ===")
371
372
# Analyze a set of gates for process tomography
373
gate_set = {
374
'I': qt.qeye(2),
375
'X': qt.sigmax(),
376
'Y': qt.sigmay(),
377
'Z': qt.sigmaz(),
378
'H': (qt.sigmax() + qt.sigmaz()).unit(),
379
'S': qt.phasegate(np.pi/2)
380
}
381
382
print("Gate set process fidelity matrix:")
383
gate_names = list(gate_set.keys())
384
chi_matrices = {name: qt.qpt(gate) for name, gate in gate_set.items()}
385
386
# Create fidelity matrix
387
fidelity_matrix = np.zeros((len(gate_names), len(gate_names)))
388
for i, name1 in enumerate(gate_names):
389
for j, name2 in enumerate(gate_names):
390
fid = qt.process_fidelity(chi_matrices[name1], chi_matrices[name2])
391
fidelity_matrix[i, j] = fid
392
393
print("Process fidelity matrix (1.0 = identical, 0.0 = orthogonal):")
394
print(" ", " ".join(f"{name:^6}" for name in gate_names))
395
for i, name in enumerate(gate_names):
396
row_str = f"{name:>3} "
397
row_str += " ".join(f"{fidelity_matrix[i,j]:6.3f}" for j in range(len(gate_names)))
398
print(row_str)
399
```
400
401
## Types
402
403
```python { .api }
404
# Process tomography functions return:
405
# - qpt(): Qobj representing chi-matrix
406
# - process_fidelity(): float (0 to 1)
407
# - average_gate_fidelity(): float (0 to 1)
408
# - chi_to_pauli_transfer(): numpy ndarray
409
# - Plotting functions return None (display plots)
410
```