or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdoperators.mdphase-space.mdprocess-tomography.mdquantum-gates.mdquantum-information.mdquantum-objects.mdrandom-objects.mdsolvers.mdstates.mdsuperoperators.mdtensor-operations.mdutilities.mdvisualization.md

process-tomography.mddocs/

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

```