Qutip Readthedocs Io en Qutip 5.0.x
Qutip Readthedocs Io en Qutip 5.0.x
Qutip Readthedocs Io en Qutip 5.0.x
Release 5.0.4
1 Frontmatter 3
1.1 About This Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Citing This Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Funding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 About QuTiP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.5 QuTiP Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.6 Libraries Using QuTiP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.7 Contributing to QuTiP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 Installation 9
2.1 Quick Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 General Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Installing with conda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3.1 Adding the conda-forge channel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3.2 New conda environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4 Installing from Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4.1 PEP 517 Source Builds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4.2 Direct Setuptools Source Builds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.5 Installation on Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.6 Verifying the Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7 Checking Version Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3 Users Guide 13
3.1 Guide Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1.1 Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Basic Operations on Quantum Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2.1 First things first . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2.2 The quantum object class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2.3 Functions operating on Qobj class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.3 Manipulating States and Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3.2 State Vectors (kets or bras) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3.3 Density matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.4 Qubit (two-level) systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.3.5 Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3.6 Expectation values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.3.7 Superoperators and Vectorized Operators . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.3.8 Choi, Kraus, Stinespring and 𝜒 Representations . . . . . . . . . . . . . . . . . . . . . . 37
3.3.9 Properties of Quantum Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.4 Using Tensor Products and Partial Traces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.4.1 Tensor products . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
3.4.2 Example: Constructing composite Hamiltonians . . . . . . . . . . . . . . . . . . . . . . 46
3.4.3 Partial trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
3.4.4 Superoperators and Tensor Manipulations . . . . . . . . . . . . . . . . . . . . . . . . . 49
3.5 Superoperators, Pauli Basis and Channel Contraction . . . . . . . . . . . . . . . . . . . . . . . . 50
3.5.1 Superoperator Representations and Plotting . . . . . . . . . . . . . . . . . . . . . . . . 51
3.5.2 Reduced Channels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
i
3.6 Time Evolution and Quantum System Dynamics . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.6.2 Dynamics Simulation Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.6.3 Lindblad Master Equation Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.6.4 Monte Carlo Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.6.5 Krylov Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3.6.6 Stochastic Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.6.7 Solving Problems with Time-dependent Hamiltonians . . . . . . . . . . . . . . . . . . . 80
3.6.8 Solver Class Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
3.6.9 Bloch-Redfield master equation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
3.6.10 Floquet Formalism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
3.6.11 Monte Carlo for Non-Markovian Dynamics . . . . . . . . . . . . . . . . . . . . . . . . 109
3.6.12 Setting Options for the Dynamics Solvers . . . . . . . . . . . . . . . . . . . . . . . . . 111
3.6.13 Computing propagators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
3.7 Hierarchical Equations of Motion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.7.2 Bosonic Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
3.7.3 Fermionic Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
3.7.4 Previous implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
3.7.5 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.8 Solving for Steady-State Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.8.2 Steady State solvers in QuTiP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.8.3 Using the Steadystate Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
3.8.4 Additional Solver Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
3.8.5 Example: Harmonic Oscillator in Thermal Bath . . . . . . . . . . . . . . . . . . . . . . 133
3.9 Permutational Invariance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
3.9.1 Permutational Invariant Quantum Solver (PIQS) . . . . . . . . . . . . . . . . . . . . . . 135
3.10 Two-time correlation functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
3.10.1 Steadystate correlation function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
3.10.2 Emission spectrum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
3.10.3 Non-steadystate correlation function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
3.11 Plotting on the Bloch Sphere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
3.11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
3.11.2 The Bloch Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
3.11.3 Configuring the Bloch sphere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
3.11.4 Animating with the Bloch sphere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
3.12 Visualization of quantum states and processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
3.12.1 Fock-basis probability distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
3.12.2 Quasi-probability distributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
3.12.3 Visualizing operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
3.12.4 Quantum process tomography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
3.13 Saving QuTiP Objects and Data Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
3.13.1 Storing and loading QuTiP objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
3.13.2 Storing and loading datasets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
3.14 Generating Random Quantum States & Operators . . . . . . . . . . . . . . . . . . . . . . . . . . 172
3.14.1 Random objects with a given eigen spectrum . . . . . . . . . . . . . . . . . . . . . . . 173
3.14.2 Composite random objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
3.14.3 Controlling the random number generator . . . . . . . . . . . . . . . . . . . . . . . . . 174
3.14.4 Internal matrix format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
3.15 Modifying Internal QuTiP Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
3.15.1 User Accessible Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
3.15.2 Example: Changing Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
3.16 Measurement of Quantum Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
3.16.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
3.16.2 Performing a basic measurement (Observable) . . . . . . . . . . . . . . . . . . . . . . . 175
3.16.3 Performing a basic measurement (Projective) . . . . . . . . . . . . . . . . . . . . . . . 177
3.16.4 Obtaining measurement statistics(Observable) . . . . . . . . . . . . . . . . . . . . . . . 178
ii
3.16.5 Obtaining measurement statistics(Projective) . . . . . . . . . . . . . . . . . . . . . . . 179
3.17 Quantum Optimal Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
3.17.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
3.17.2 Closed Quantum Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
3.17.3 The GRAPE algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
3.17.4 The CRAB Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
3.17.5 Optimal Quantum Control in QuTiP . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
4 Gallery 185
iii
6.5.13 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.6 QuTiP 5.0.0b1 (2024-03-04) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.6.1 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.6.2 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.6.3 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.7 QuTiP 5.0.0a2 (2023-09-06) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
6.7.1 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
6.7.2 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
6.7.3 Removals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
6.7.4 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
6.7.5 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
6.7.6 Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
6.7.7 Qobj changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
6.7.8 QobjEvo changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
6.7.9 Solver changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
6.7.10 QuTiP core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
6.7.11 QuTiP settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
6.7.12 Package reorganization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.7.13 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.7.14 Feature removals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.8 QuTiP 4.7.5 (2024-01-29) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.8.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.9 QuTiP 4.7.4 (2024-01-15) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.9.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
6.9.2 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.10 QuTiP 4.7.3 (2023-08-22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.10.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.10.2 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.11 QuTiP 4.7.2 (2023-06-28) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.11.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.11.2 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
6.11.3 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
6.11.4 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
6.11.5 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
6.11.6 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
6.11.7 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
6.11.8 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
6.11.9 Documentation Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
6.11.10 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
6.11.11 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
6.11.12 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
6.11.13 Documentation Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
6.11.14 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
6.11.15 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
6.11.16 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
6.11.17 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
6.11.18 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
6.11.19 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
6.11.20 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
6.11.21 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
6.11.22 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
6.11.23 Deprecations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
6.11.24 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
6.11.25 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
6.11.26 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
6.11.27 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
6.11.28 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
6.11.29 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
iv
6.11.30 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
6.11.31 Deprecations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
6.11.32 Developer Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
6.11.33 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
6.11.34 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
6.11.35 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
6.11.36 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
6.11.37 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
6.11.38 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
6.11.39 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
6.11.40 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
6.11.41 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
6.11.42 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
6.11.43 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
6.11.44 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
6.11.45 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
6.11.46 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
6.11.47 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
6.11.48 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
6.11.49 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
6.11.50 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
6.11.51 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
6.11.52 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
6.11.53 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
6.11.54 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
6.11.55 Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
6.11.56 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
6.11.57 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
6.11.58 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
6.11.59 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
6.11.60 New Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
6.11.61 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
6.11.62 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
6.11.63 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
6.11.64 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
6.11.65 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
6.11.66 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
6.11.67 New Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
6.11.68 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
7 Developers 435
7.1 Lead Developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
7.2 Past Lead Developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
7.3 Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436
v
8.3.2 Pulse level description of quantum circuits . . . . . . . . . . . . . . . . . . . . . . . . . 452
8.3.3 Quantum Error Mitigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
8.3.4 GPU implementation of the Hierarchical Equations of Motion . . . . . . . . . . . . . . 455
8.3.5 Google Summer of Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
8.3.6 Completed Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456
8.4 Working with the QuTiP Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
8.4.1 Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458
8.5 Release and Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
8.5.1 Preamble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
8.5.2 Setting Up The Release Branch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462
8.5.3 Build Release Distribution and Deploy . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
8.5.4 Making a Release on GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
8.5.5 Website . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
8.5.6 Conda Forge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
9 Bibliography 469
Bibliography 479
Index 483
vi
QuTiP: Quantum Toolbox in Python, Release 5.0.4
This documentation contains a user guide and automatically generated API documentation for QuTiP. For more
information see the QuTiP project web page. Here, you can also find a collection of tutorials for QuTiP.
Contents 1
QuTiP: Quantum Toolbox in Python, Release 5.0.4
2 Contents
Chapter 1
Frontmatter
This document contains a user guide and automatically generated API documentation for QuTiP. A PDF version
of this text is available at the documentation page.
For more information see the QuTiP project web page.
Author
J.R. Johansson
Author
P.D. Nation
Author
Alexander Pitchford
Author
Arne Grimsmo
Author
Chris Grenade
Author
Nathan Shammah
Author
Shahnawaz Ahmed
Author
Neill Lambert
Author
Eric Giguere
Author
Boxi Li
Author
Jake Lishman
Author
Simon Cross
Author
Asier Galicia
Author
Paul Menczel
3
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Author
Patrick Hopf
release
5.0.4
copyright
The text of this documentation is licensed under the Creative Commons Attribution 3.0 Unported
License. All contained code samples, and the source code of QuTiP, are licensed under the 3-
clause BSD licence. Full details of the copyright notices can be found on the Copyright and
Licensing page of this documentation.
1.3 Funding
4 Chapter 1. Frontmatter
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Every quantum system encountered in the real world is an open quantum system. For although much care is
taken experimentally to eliminate the unwanted influence of external interactions, there remains, if ever so slight,
a coupling between the system of interest and the external world. In addition, any measurement performed on
the system necessarily involves coupling to the measuring device, therefore introducing an additional source of
external influence. Consequently, developing the necessary tools, both theoretical and numerical, to account for
the interactions between a system and its environment is an essential step in understanding the dynamics of practical
quantum systems.
In general, for all but the most basic of Hamiltonians, an analytical description of the system dynamics is not
possible, and one must resort to numerical simulations of the equations of motion. In absence of a quantum
computer, these simulations must be carried out using classical computing techniques, where the exponentially
increasing dimensionality of the underlying Hilbert space severely limits the size of system that can be efficiently
simulated. However, in many fields such as quantum optics, trapped ions, superconducting circuit devices, and
most recently nanomechanical systems, it is possible to design systems using a small number of effective oscillator
and spin components, excited by a limited number of quanta, that are amenable to classical simulation in a truncated
Hilbert space.
The Quantum Toolbox in Python, or QuTiP, is an open-source framework written in the Python programming lan-
guage, designed for simulating the open quantum dynamics of systems such as those listed above. This framework
distinguishes itself from other available software solutions in providing the following advantages:
• QuTiP relies entirely on open-source software. You are free to modify and use it as you wish with no licensing
fees or limitations.
• QuTiP is based on the Python scripting language, providing easy to read, fast code generation without the
need to compile after modification.
• The numerics underlying QuTiP are time-tested algorithms that run at C-code speeds, thanks to the Numpy,
Scipy, and Cython libraries, and are based on many of the same algorithms used in propriety software.
• QuTiP allows for solving the dynamics of Hamiltonians with (almost) arbitrary time-dependence, including
collapse operators.
• Time-dependent problems can be automatically compiled into C++-code at run-time for increased perfor-
mance.
• Takes advantage of the multiple processing cores found in essentially all modern computers.
• QuTiP was designed from the start to require a minimal learning curve for those users who have experience
using the popular quantum optics toolbox by Sze M. Tan.
• Includes the ability to create high-quality plots, and animations, using the excellent Matplotlib package.
For detailed information about new features of each release of QuTiP, see the Change Log.
Several libraries rely on QuTiP for quantum physics or quantum information processing. Some of them are:
Krotov
Krotov focuses on the python implementation of Krotov’s method for quantum optimal control
pyEPR
pyEPR interfaces classical distributed microwave analysis with that of quantum structures and
hamiltonians by providing easy to use analysis function and automation for the design of quantum
chips
scQubits
scQubits is a Python library which provides a convenient way to simulate superconducting qubits
by providing an interface to QuTiP
SimulaQron
SimulaQron is a distributed simulation of the end nodes in a quantum internet with the specific
goal to explore application development
QInfer
QInfer is a library for working with sequential Monte Carlo methods for parameter estimation in
quantum information
QPtomographer
QPtomographer derive quantum error bars for quantum processes in terms of the diamond norm
to a reference quantum channel
QuNetSim
QuNetSim is a quantum networking simulation framework to develop and test protocols for quan-
tum networks
qupulse
qupulse is a toolkit to facilitate experiments involving pulse driven state manipulation of physical
qubits
Pulser
Pulser is a framework for composing, simulating and executing pulse sequences for neutral-atom
quantum devices.
6 Chapter 1. Frontmatter
QuTiP: Quantum Toolbox in Python, Release 5.0.4
We welcome anyone who is interested in helping us make QuTiP the best package for simulating quantum systems.
There are detailed instructions on how to contribute code and documentation in the developers’ section of this
guide. You can also help out our users by answering questions in the QuTiP discussion mailing list, or by raising
issues in the main GitHub repository if you find any bugs. Anyone who contributes code will be duly recognized.
Even small contributions are noted. See Contributors for a list of people who have helped in one way or another.
8 Chapter 1. Frontmatter
Chapter 2
Installation
From QuTiP version 4.6 onwards, you should be able to get a working version of QuTiP with the standard
It is not recommended to install any packages directly into the system Python environment; consider using pip or
conda virtual environments to keep your operating system space clean, and to have more control over Python and
other package versions.
You do not need to worry about the details on the rest of this page unless this command did not work, but do also
read the next section for the list of optional dependencies. The rest of this page covers installation directly from
conda, installation from source, and additional considerations when working on Windows.
QuTiP depends on several open-source libraries for scientific computing in the Python programming language.
The following packages are currently required:
In addition, there are several optional packages that provide additional functionality:
9
QuTiP: Quantum Toolbox in Python, Release 5.0.4
In addition, there are several additional packages that are not dependencies, but may give you a better programming
experience. IPython provides an improved text-based Python interpreter that is far more full-featured that the
default interpreter, and runs in a terminal. If you prefer a more graphical set-up, Jupyter provides a notebook-style
interface to mix code and mathematical notes together. Alternatively, Spyder is a free integrated development
environment for Python, with several nice features for debugging code. QuTiP will detect if it is being used within
one of these richer environments, and various outputs will have enhanced formatting.
If you already have your conda environment set up, and have the conda-forge channel available, then you can
install QuTiP using:
This will install the minimum set of dependences, but none of the optional packages.
To install QuTiP from conda, you will need to add the conda-forge channel. The following command adds this
channel with lowest priority, so conda will still try and install all other packages normally:
If you want to change the order of your channels later, you can edit your .condarc (user home folder) file manually,
but it is recommended to keep defaults as the highest priority.
The default Anaconda environment has all the Python packages needed for running QuTiP installed already, so you
will only need to add the conda-forge channel and then install the package. If you have only installed Miniconda,
or you want a completely clean virtual environment to install QuTiP in, the conda package manager provides a
convenient way to do this.
To create a conda environment for QuTiP called qutip-env:
This will automatically install all the necessary packages, and none of the optional packages. You activate the new
environment by running
You can also install any more optional packages you want with conda install, for example matplotlib,
ipython or jupyter.
10 Chapter 2. Installation
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Official releases of QuTiP are available from the download section on the project’s web pages, and the latest source
code is available in our GitHub repository. In general we recommend users to use the latest stable release of
QuTiP, but if you are interested in helping us out with development or wish to submit bug fixes, then use the latest
development version from the GitHub repository.
You can install from source by using the Python-recommended PEP 517 procedure, or if you want more control
or to have a development version, you can use the low-level build procedure with setuptools.
The easiest way to build QuTiP from source is to use a PEP-517-compatible builder such as the build package
available on pip. These will automatically install all build dependencies for you, and the pip installation step
afterwards will install the minimum runtime dependencies. You can do this by doing (for example)
The first command installs the reference PEP-517 build tool, the second effects the build and the third uses pip
to install the built package. You will need to replace <path to qutip> with the actual path to the QuTiP source
code. The string <version> will depend on the version of QuTiP, the version of Python and your operating system.
It will look something like 4.6.0-cp39-cp39-manylinux1_x86_64, but there should only be one .whl file in
the dist/ directory, which will be the correct one.
This is the method to have the greatest amount of control over the installation, but it the most error-prone and not
recommended unless you know what you are doing. You first need to have all the runtime dependencies installed.
The most up-to-date requirements will be listed in pyproject.toml file, in the build-system.requires key.
As of the 5.0.0 release, the build requirements can be installed with
or similar with conda if you prefer. You will also need to have a functional C++ compiler installed on your system.
This is likely already done for you if you are on Linux or macOS, but see the section on Windows installations if
that is your operating system.
To install QuTiP from the source code run:
pip install .
If you wish to contribute to the QuTiP project, then you will want to create your own fork of the QuTiP git repository,
clone this to a local folder, and install it into your Python environment using:
When you do import qutip in this environment, you will then load the code from your local fork, enabling you to
edit the Python files and have the changes immediately available when you restart your Python interpreter, without
needing to rebuild the package. Note that if you change any Cython files, you will need to rerun the build command.
You should not need to use sudo (or other superuser privileges) to install into a personal virtual environment; if it
feels like you need it, there is a good chance that you are installing into the system Python environment instead.
As with other operating systems, the easiest method is to use pip install qutip, or use the conda procedure
described above. If you want to build from source or use runtime compilation with Cython, you will need to have
a working C++ compiler.
You can download the Visual Studio IDE from Microsoft, which has a free Community edition containing a suffi-
cient C++ compiler. This is the recommended compiler toolchain on Windows. When installing, be sure to select
the following components:
• Windows “X” SDK (where “X” stands for your version: 7/8/8.1/10)
• Visual Studio C++ build tools
You can then follow the installation from source section as normal.
Important: In order to prevent issues with the PATH environment variable not containing the compiler and
associated libraries, it is recommended to use the developer command prompt in the Visual Studio installation
folder instead of the built-in command prompt.
The Community edition of Visual Studio takes around 10GB of disk space. If this is prohibitive for you, it is also
possible to install only the build tools and necessary SDKs instead, which should save about 2GB of space.
QuTiP includes a collection of built-in test scripts to verify that an installation was successful. To run the suite of
tests scripts you must also have the pytest testing library. After installing QuTiP, leave the installation directory
and call:
pytest qutip/qutip/tests
This will take between 10 and 30 minutes, depending on your computer. At the end, the testing report should
report a success; it is normal for some tests to be skipped, and for some to be marked “xfail” in yellow. Skips may
be tests that do not run on your operating system, or tests of optional components that you have not installed the
dependencies for. If any failures or errors occur, please check that you have installed all of the required modules.
See the next section on how to check the installed versions of the QuTiP dependencies. If these tests still fail, then
head on over to the QuTiP Discussion Board or the GitHub issues page and post a message detailing your particular
issue.
QuTiP includes an “about” function for viewing information about QuTiP and the important dependencies installed
on your system. To view this information:
import qutip
qutip.about()
12 Chapter 2. Installation
Chapter 3
Users Guide
The goal of this guide is to introduce you to the basic structures and functions that make up QuTiP. This guide
is divided up into several sections, each highlighting a specific set of functionalities. In combination with the
examples that can be found on the project web page https://qutip.org/tutorials.html, this guide should provide a
more or less complete overview of QuTip. We also provide the API documentation in API documentation.
3.1.1 Organization
QuTiP is designed to be a general framework for solving quantum mechanics problems such as systems composed
of few-level quantum systems and harmonic oscillators. To this end, QuTiP is built from a large (and ever growing)
library of functions and classes; from qutip.states.basis to qutip.wigner. The general organization of
QuTiP, highlighting the important API available to the user, is shown in the figure below.
13
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Fig. 1: Tree-diagram of the 468 user accessible functions and classes in QuTiP 4.6. A vector image of the code
tree is in qutip_tree.pdf.
This will load all of the user available functions. Often, we also need to import the NumPy and Matplotlib libraries
with:
import numpy as np
In the rest of the documentation, functions are written using qutip.module.function() notation which links to the
corresponding function in the QuTiP API: Functions. However, in calling import *, we have already loaded all of
the QuTiP modules. Therefore, we will only need the function name and not the complete path when calling the
function from the interpreter prompt, Python script, or Jupyter notebook.
Introduction
The key difference between classical and quantum mechanics is the use of operators instead of numbers as variables.
Moreover, we need to specify state vectors and their properties. Therefore, in computing the dynamics of quantum
systems, we need a data structure that encapsulates the properties of a quantum operator and ket/bra vectors. The
quantum object class, qutip.Qobj, accomplishes this using matrix representation.
To begin, let us create a blank Qobj:
print(Qobj())
Output:
Quantum object: dims = [[1], [1]], shape = (1, 1), type = bra
Qobj data =
[[0.]]
where we see the blank Qobj object with dimensions, shape, and data. Here the data corresponds to a 1x1-
dimensional matrix consisting of a single zero entry.
Hint: By convention, the names of Python classes, such as Qobj(), are capitalized whereas the names of functions
are not.
We can create a Qobj with a user defined data set by passing a list or array of data into the Qobj:
print(Qobj([[1],[2],[3],[4],[5]]))
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[1.]
[2.]
[3.]
[4.]
[5.]]
x = np.array([[1, 2, 3, 4, 5]])
print(Qobj(x))
Output:
Quantum object: dims = [[1], [5]], shape = (1, 5), type = bra
Qobj data =
[[1. 2. 3. 4. 5.]]
r = np.random.rand(4, 4)
print(Qobj(r))
Output:
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[0.37454012 0.95071431 0.73199394 0.59865848]
[0.15601864 0.15599452 0.05808361 0.86617615]
[0.60111501 0.70807258 0.02058449 0.96990985]
[0.83244264 0.21233911 0.18182497 0.18340451]]
Notice how both the dims and shape change according to the input data. Although dims and shape appear to be the
same, dims keep track of the shapes for individual components of a multipartite system, while shape does not. We
refer the reader to the section tensor products and partial traces for more information.
Note: If you are running QuTiP from a python script you must use the print function to view the Qobj attributes.
Manually specifying the data for each quantum object is inefficient. Even more so when most objects correspond to
commonly used types such as the ladder operators of a harmonic oscillator, the Pauli spin operators for a two-level
system, or state vectors such as Fock states. Therefore, QuTiP includes predefined objects for a variety of states
and operators:
>>> basis(5,3)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[1.]
[0.]]
>>> coherent(5,0.5-0.5j)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[ 0.7788017 +0.j ]
[ 0.38939142-0.38939142j]
[ 0. -0.27545895j]
[-0.07898617-0.07898617j]
[-0.04314271+0.j ]]
>>> destroy(4)
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
(continues on next page)
>>> sigmaz()
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[ 1. 0.]
[ 0. -1.]]
>>> jmat(5/2.0,'+')
Quantum object: dims = [[6], [6]], shape = (6, 6), type = oper, isherm = False
Qobj data =
[[0. 2.23606798 0. 0. 0. 0. ]
[0. 0. 2.82842712 0. 0. 0. ]
[0. 0. 0. 3. 0. 0. ]
[0. 0. 0. 0. 2.82842712 0. ]
[0. 0. 0. 0. 0. 2.23606798]
[0. 0. 0. 0. 0. 0. ]]
Qobj attributes
We have seen that a quantum object has several internal attributes, such as data, dims, and shape. These can be
accessed in the following way:
>>> q = destroy(4)
>>> q.dims
[[4], [4]]
>>> q.shape
(4, 4)
In general, the attributes (properties) of a Qobj object (or any Python object) can be retrieved using the Q.attribute
notation. In addition to the those shown with the print function, an instance of the Qobj class also has the
following attributes:
Fig. 2: The Qobj Class viewed as a container for the properties needed to characterize a quantum operator or state
vector.
>>> q.type
'oper'
>>> q.isherm
False
>>> q.data
Dia(shape=(4, 4), num_diag=1)
The data attribute returns a Qutip diagonal matrix. Qobj instances store their data in Qutip matrix format. In the
core qutip module, the Dense, CSR and Dia formats are available, but other packages can add other formats. For
example, the qutip-jax module adds the Jax and JaxDia formats. One can always access the underlying matrix
as a numpy array using Qobj.full. It is also possible to access the underlying data in a common format using
Qobj.data_as.
>>> q.data_as("dia_matrix")
<4x4 sparse matrix of type '<class 'numpy.complex128'>'
with 3 stored elements (1 diagonals) in DIAgonal format>
>>> q.to("CSR").data
CSR(shape=(4, 4), nnz=3)
>>> q.to("CSR").data_as("csr_matrix")
<4x4 sparse matrix of type '<class 'numpy.complex128'>'
with 3 stored elements in Compressed Sparse Row format>
Qobj Math
The rules for mathematical operations on Qobj instances are similar to standard matrix arithmetic:
>>> q = destroy(4)
>>> x = sigmax()
>>> q + 5
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[5. 1. 0. 0. ]
[0. 5. 1.41421356 0. ]
[0. 0. 5. 1.73205081]
[0. 0. 0. 5. ]]
>>> x * x
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[1. 0.]
[0. 1.]]
>>> q ** 3
Quantum object: dims = [[4], [4]], shape = (4, 4), type = oper, isherm = False
Qobj data =
[[0. 0. 0. 2.44948974]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]]
>>> x / np.sqrt(2)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.70710678]
[0.70710678 0. ]]
Of course, like matrices, multiplying two objects of incompatible shape throws an error:
>>> print(q * x)
------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-0b599f41213e> in <module>
----> 1 print(q * x)
In addition, the logic operators “is equal” == and “is not equal” != are also supported.
Like attributes, the quantum object class has defined functions (methods) that operate on Qobj class instances. For
a general quantum object Q:
>>> basis(5, 3)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[1.]
[0.]]
>>> coherent_dm(5, 1)
(continues on next page)
3.3.1 Introduction
In the previous guide section Basic Operations on Quantum Objects, we saw how to create states and operators,
using the functions built into QuTiP. In this portion of the guide, we will look at performing basic operations
with states and operators. For more detailed demonstrations on how to use and manipulate these objects, see the
examples on the tutorials web page.
Here we begin by creating a Fock basis vacuum state vector |0⟩ with in a Hilbert space with 5 number states, from
0 to 4:
vac = basis(5, 0)
print(vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[1.]
[0.]
[0.]
[0.]
[0.]]
a = destroy(5)
print(a)
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = False
Qobj data =
[[0. 1. 0. 0. 0. ]
[0. 0. 1.41421356 0. 0. ]
[0. 0. 0. 1.73205081 0. ]
[0. 0. 0. 0. 2. ]
[0. 0. 0. 0. 0. ]]
Now lets apply the destruction operator to our vacuum state vac,
print(a * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[0.]
[0.]]
We see that, as expected, the vacuum is transformed to the zero vector. A more interesting example comes from
using the adjoint of the lowering operator, the raising operator 𝑎
ˆ† :
print(a.dag() * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]
[0.]]
The raising operator has in indeed raised the state vec from the vacuum to the |1⟩ state. Instead of using the dagger
Qobj.dag() method to raise the state, we could have also used the built in create function to make a raising
operator:
c = create(5)
print(c * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]
[0.]]
which does the same thing. We can raise the vacuum state more than once by successively apply the raising
operator:
print(c * c * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0. ]
[0. ]
[1.41421356]
[0. ]
[0. ]]
(︀ † )︀2
or just taking the square of the raising operator 𝑎ˆ :
print(c ** 2 * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0. ]
[0. ]
(continues on next page)
print(c * a * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[0.]
[0.]]
print(c * a * (c * vac))
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]
[0.]]
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0. ]
[0. ]
[2.82842712]
[0. ]
[0. ]]
Notice how
√ in this last example, application of the number operator does not give√the expected value 𝑛 = 2, but
rather 2 2. This is because this last state is not normalized to unity as 𝑐 |𝑛⟩ = 𝑛 + 1 |𝑛 + 1⟩. Therefore, we
should normalize our vector first:
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
(continues on next page)
Since we are giving a demonstration of using states and operators, we have done a lot more work than we should
have. For example, we do not need to operate on the vacuum state to generate a higher number Fock state. Instead
we can use the basis (or fock) function to directly obtain the required state:
ket = basis(5, 2)
print(ket)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[1.]
[0.]
[0.]]
Notice how it is automatically normalized. We can also use the built in num operator:
n = num(5)
print(n)
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 2. 0. 0.]
[0. 0. 0. 3. 0.]
[0. 0. 0. 0. 4.]]
print(n * ket)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[2.]
[0.]
[0.]]
print(ket)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.70710678]
[0.70710678]
[0. ]
[0. ]
[0. ]]
where we have used the Qobj.unit method to again normalize the state. Operating with the number function
again:
print(n * ket)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0. ]
[0.70710678]
[0. ]
[0. ]
[0. ]]
We can also create coherent states and squeezed states by applying the displace and squeeze functions to the
vacuum state:
vac = basis(5, 0)
d = displace(5, 1j)
print(d * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[ 0.60655682+0.j ]
[ 0. +0.60628133j]
[-0.4303874 +0.j ]
[ 0. -0.24104351j]
[ 0.14552147+0.j ]]
print(d * s * vac)
Output:
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[ 0.65893786+0.08139381j]
(continues on next page)
Of course, displacing the vacuum gives a coherent state, which can also be generated using the built in coherent
function.
One of the main purpose of QuTiP is to explore the dynamics of open quantum systems, where the most general
state of a system is no longer a state vector, but rather a density matrix. Since operations on density matrices
operate identically to those of vectors, we will just briefly highlight creating and using these structures.
The simplest density matrix is created by forming the outer-product |𝜓⟩ ⟨𝜓| of a ket vector:
ket = basis(5, 2)
print(ket * ket.dag())
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
A similar task can also be accomplished via the fock_dm or ket2dm functions:
print(fock_dm(5, 2))
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
print(ket2dm(ket))
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
If we want to create a density matrix with equal classical probability of being found in the |2⟩ or |4⟩ number states
we can do the following:
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0. 0. 0. 0. 0. ]
[0. 0. 0. 0. 0. ]
[0. 0. 0.5 0. 0. ]
[0. 0. 0. 0. 0. ]
[0. 0. 0. 0. 0.5]]
or use 0.5 * fock_dm(5, 2) + 0.5 * fock_dm(5, 4). There are also several other built-in functions for
creating predefined density matrices, for example coherent_dm and thermal_dm which create coherent state
and thermal state density matrices, respectively.
print(coherent_dm(5, 1.25))
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0.20980701 0.26141096 0.23509686 0.15572585 0.13390765]
[0.26141096 0.32570738 0.29292109 0.19402805 0.16684347]
[0.23509686 0.29292109 0.26343512 0.17449684 0.1500487 ]
[0.15572585 0.19402805 0.17449684 0.11558499 0.09939079]
[0.13390765 0.16684347 0.1500487 0.09939079 0.0854655 ]]
print(thermal_dm(5, 1.25))
Output:
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0.46927974 0. 0. 0. 0. ]
[0. 0.26071096 0. 0. 0. ]
[0. 0. 0.14483942 0. 0. ]
[0. 0. 0. 0.08046635 0. ]
[0. 0. 0. 0. 0.04470353]]
QuTiP also provides a set of distance metrics for determining how close two density matrix distributions are to each
other. Included are the trace distance tracedist, fidelity fidelity, Hilbert-Schmidt distance hilbert_dist,
Bures distance bures_dist, Bures angle bures_angle, and quantum Hellinger distance hellinger_dist.
x = coherent_dm(5, 1.25)
z = thermal_dm(5, 0.125)
np.testing.assert_almost_equal(fidelity(x, x), 1)
√︁
2
the quantum Hellinger distance (QHE) between two pure states |𝜓⟩ and |𝜑⟩ is given by 𝑄𝐻𝐸 = 2 − 2 |⟨𝜓|𝜑⟩| .
For a pure state and a mixed state, 1 − 𝐹 2 ≤ 𝑇 which can also be verified:
Having spent a fair amount of time on basis states that represent harmonic oscillator states, we now move on to
qubit, or two-level quantum systems (for example a spin-1/2). To create a state vector corresponding to a qubit
system, we use the same basis, or fock, function with only two levels:
spin = basis(2, 0)
Now at this point one may ask how this state is different than that of a harmonic oscillator in the vacuum state
truncated to two energy levels?
vac = basis(2, 0)
At this stage, there is no difference. This should not be surprising as we called the exact same function twice. The
difference between the two comes from the action of the spin operators sigmax, sigmay, sigmaz, sigmap, and
sigmam on these two-level states. For example, if vac corresponds to the vacuum state of a harmonic oscillator,
then, as we have already seen, we can use the raising operator to get the |1⟩ state:
print(vac)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[1.]
[0.]]
c = create(2)
print(c * vac)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.]
[1.]]
For a spin system, the operator analogous to the raising operator is the sigma-plus operator sigmap. Operating on
the spin state gives:
print(spin)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[1.]
[0.]]
print(sigmap() * spin)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.]
[0.]]
Now we see the difference! The sigmap operator acting on the spin state returns the zero vector. Why is this? To
see what happened, let us use the sigmaz operator:
print(sigmaz())
Output:
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[ 1. 0.]
[ 0. -1.]]
print(sigmaz() * spin)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[1.]
[0.]]
spin2 = basis(2, 1)
print(spin2)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.]
[1.]]
print(sigmaz() * spin2)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[ 0.]
[-1.]]
The answer is now apparent. Since the QuTiP sigmaz function uses the standard z-basis representation of the
sigma-z spin operator, the spin state corresponds to the |↑⟩ state of a two-level spin system while spin2 gives the
|↓⟩ state. Therefore, in our previous example sigmap() * spin, we raised the qubit state out of the truncated
two-level Hilbert space resulting in the zero state.
While at first glance this convention might seem somewhat odd, it is in fact quite handy. For one, the spin operators
remain in the conventional form. Second, when the spin system is in the |↑⟩ state:
print(sigmaz() * spin)
Output:
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[1.]
[0.]]
the non-zero component is the zeroth-element of the underlying matrix (remember that python uses c-indexing,
and matrices start with the zeroth element). The |↓⟩ state therefore has a non-zero entry in the first index position.
This corresponds nicely with the quantum information definitions of qubit states, where the excited |↑⟩ state is label
as |0⟩, and the |↓⟩ state by |1⟩.
If one wants to create spin operators for higher spin systems, then the jmat function comes in handy.
3.3.5 Gates
H = gates.hadamard_transform()
print(H)
Output:
Some of the most important information about quantum systems comes from calculating the expectation value of
operators, both Hermitian and non-Hermitian, as the state or density matrix of the system varies in time. Therefore,
in this section we demonstrate the use of the expect function. To begin:
vac = basis(5, 0)
one = basis(5, 1)
c = create(5)
N = num(5)
np.testing.assert_almost_equal(expect(N, vac), 0)
np.testing.assert_almost_equal(expect(N, one), 1)
The expect function also accepts lists or arrays of state vectors or density matrices for the second input:
print(expect(N, states))
Output:
[0. 1. 2. 3. 4.]
print(expect(c, cat_list))
Output:
Notice how in this last example, all of the return values are complex numbers. This is because the expect function
looks to see whether the operator is Hermitian or not. If the operator is Hermitian, then the output will always be
real. In the case of non-Hermitian operators, the return values may be complex. Therefore, the expect function
will return an array of complex values for non-Hermitian operators when the input is a list/array of states or density
matrices.
Of course, the expect function works for spin states and operators:
up = basis(2, 0)
down = basis(2, 1)
np.testing.assert_almost_equal(expect(sigmaz(), up), 1)
as well as the composite objects discussed in the next section Using Tensor Products and Partial Traces:
spin1 = basis(2, 0)
spin2 = basis(2, 1)
np.testing.assert_almost_equal(expect(sz1, two_spins), 1)
In addition to state vectors and density operators, QuTiP allows for representing maps that act linearly on density
operators using the Kraus, Liouville supermatrix and Choi matrix formalisms. This support is based on the cor-
respondence between linear operators acting on a Hilbert space, and vectors in two copies of that Hilbert space,
vec : ℒ(ℋ) → ℋ ⊗ ℋ [Hav03], [Wat13].
This isomorphism is implemented in QuTiP by the operator_to_vector and vector_to_operator functions:
psi = basis(2, 0)
rho = ket2dm(psi)
print(rho)
Output:
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[1. 0.]
[0. 0.]]
vec_rho = operator_to_vector(rho)
print(vec_rho)
Output:
Quantum object: dims = [[[2], [2]], [1]], shape = (4, 1), type = operator-ket
Qobj data =
[[1.]
[0.]
[0.]
[0.]]
rho2 = vector_to_operator(vec_rho)
np.testing.assert_almost_equal((rho - rho2).norm(), 0)
The Qobj.type attribute indicates whether a quantum object is a vector corresponding to an operator
(operator-ket), or its Hermitian conjugate (operator-bra).
Note that QuTiP uses the column-stacking convention for the isomorphism between ℒ(ℋ) and ℋ ⊗ ℋ:
A = Qobj(np.arange(4).reshape((2, 2)))
print(A)
Output:
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = False
Qobj data =
[[0. 1.]
[2. 3.]]
print(operator_to_vector(A))
Output:
Quantum object: dims = [[[2], [2]], [1]], shape = (4, 1), type = operator-ket
Qobj data =
[[0.]
[2.]
[1.]
[3.]]
Since ℋ⊗ℋ is a vector space, linear maps on this space can be represented as matrices, often called superoperators.
Using the Qobj, the spre and spost functions, supermatrices corresponding to left- and right-multiplication
respectively can be quickly constructed.
X = sigmax()
Note that this is done automatically by the to_super function when given type='oper' input.
S2 = to_super(X)
np.testing.assert_almost_equal((S - S2).norm(), 0)
print(S)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True
Qobj data =
[[0. 0. 0. 1.]
[0. 0. 1. 0.]
[0. 1. 0. 0.]
[1. 0. 0. 0.]]
Information about superoperators, such as whether they represent completely positive maps, is exposed through
the Qobj.iscp, Qobj.istp and Qobj.iscptp attributes:
Output:
In addition, dynamical generators on this extended space, often called Liouvillian superoperators, can be created
using the liouvillian function. Each of these takes a Hamiltonian along with a list of collapse operators, and
returns a type="super" object that can be exponentiated to find the superoperator for that evolution.
H = 10 * sigmaz()
c1 = destroy(2)
L = liouvillian(H, [c1])
print(L)
S = (12 * L).expm()
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= False
Qobj data =
[[ 0. +0.j 0. +0.j 0. +0.j 1. +0.j]
[ 0. +0.j -0.5+20.j 0. +0.j 0. +0.j]
[ 0. +0.j 0. +0.j -0.5-20.j 0. +0.j]
[ 0. +0.j 0. +0.j 0. +0.j -1. +0.j]]
For qubits, a particularly useful way to visualize superoperators is to plot them in the Pauli basis, such that
𝑆𝜇,𝜈 = ⟨⟨𝜎𝜇 |𝑆[𝜎𝜈 ]⟩⟩. Because the Pauli basis is Hermitian, 𝑆𝜇,𝜈 is a real number for all Hermitian-preserving
superoperators 𝑆, allowing us to plot the elements of 𝑆 as a Hinton diagram. In such diagrams, positive elements
are indicated by white squares, and negative elements by black squares. The size of each element
{︃ is indicated by
+1 𝜇 = 0, 𝑥
the size of the corresponding square. For instance, let 𝑆[𝜌] = 𝜎𝑥 𝜌𝜎𝑥† . Then 𝑆[𝜎𝜇 ] = 𝜎𝜇 · . We
−1 𝜇 = 𝑦, 𝑧
can quickly see this by noting that the 𝑌 and 𝑍 elements of the Hinton diagram for 𝑆 are negative:
X = sigmax()
S = spre(X) * spost(X.dag())
(continues on next page)
hinton(S)
I X Y Z
I 1.0
0.5
X
0.0
Y 0.5
1.0
Z
In addition to the superoperator representation of quantum maps, QuTiP supports several other useful representa-
tions. First, the Choi matrix 𝐽(Λ) of a quantum map Λ is useful for working with ancilla-assisted process tomog-
raphy (AAPT), and for reasoning about properties of a map or channel. Up to normalization, the Choi matrix is
defined by acting Λ on half of an entangled pair. In the column-stacking convention,
𝐽(Λ) = (⊮ ⊗ Λ)[|⊮⟩⟩⟨⟨⊮|].
In QuTiP, 𝐽(Λ) can be found by calling the to_choi function on a type="super" Qobj.
X = sigmax()
S = sprepost(X, X)
J = to_choi(S)
print(J)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True, superrep = choi
print(to_choi(spre(qeye(2))))
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True, superrep = choi
Qobj data =
[[1. 0. 0. 1.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[1. 0. 0. 1.]]
If a Qobj instance is already in the Choi Qobj.superrep, then calling to_choi does nothing:
print(to_choi(J))
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True, superrep = choi
Qobj data =
[[0. 0. 0. 0.]
[0. 1. 1. 0.]
[0. 1. 1. 0.]
[0. 0. 0. 0.]]
To get back to the superoperator representation, simply use the to_super function. As with to_choi, to_super
is idempotent:
print(to_super(J) - S)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True
Qobj data =
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
print(to_super(S))
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True
Qobj data =
[[0. 0. 0. 1.]
[0. 0. 1. 0.]
(continues on next page)
We can quickly obtain another useful representation from the∑︀ Choi matrix by taking its eigendecomposition. In
particular, let {𝐴𝑖 } be a set of operators such that 𝐽(Λ) = 𝑖 |𝐴𝑖 ⟩⟩⟨⟨𝐴𝑖 |. We can write 𝐽(Λ) in this way for any
hermicity-preserving map; that is, for any map Λ such that 𝐽(Λ) = 𝐽 † (Λ). These operators then form the Kraus
representation of Λ. In particular, for any input 𝜌,
𝐴𝑖 𝜌𝐴†𝑖 .
∑︁
Λ(𝜌) =
𝑖
Notice using the column-stacking identity that (𝐶 T ⊗ 𝐴)|𝐵⟩⟩ = |𝐴𝐵𝐶⟩⟩, we have that
∑︁ ∑︁
(⊮ ⊗ 𝐴𝑖 )(⊮ ⊗ 𝐴𝑖 )† |⊮⟩⟩⟨⟨⊮| = |𝐴𝑖 ⟩⟩⟨⟨𝐴𝑖 | = 𝐽(Λ).
𝑖 𝑖
The Kraus representation of a hermicity-preserving map can be found in QuTiP using the to_kraus function.
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True
Qobj data =
[[0.5 0. 0. 0.5]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]
[0.5 0. 0. 0.5]]
J = to_choi(S)
print(J)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True, superrep = choi
Qobj data =
[[0.5 0. 0. 0. ]
[0. 0.5 0. 0. ]
[0. 0. 0.5 0. ]
[0. 0. 0. 0.5]]
print(J.eigenstates()[1])
Output:
[Quantum object: dims = [[[2], [2]], [1, 1]], shape = (4, 1), type = operator-ket
Qobj data =
[[1.]
[0.]
(continues on next page)
K = to_kraus(S)
print(K)
Output:
[Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0.70710678 0. ]
[0. 0. ]], Quantum object: dims = [[2], [2]], shape = (2, 2), type =␣
˓→oper, isherm = False
Qobj data =
[[0. 0. ]
[0.70710678 0. ]], Quantum object: dims = [[2], [2]], shape = (2, 2), type =␣
˓→oper, isherm = False
Qobj data =
[[0. 0.70710678]
[0. 0. ]], Quantum object: dims = [[2], [2]], shape = (2, 2), type =␣
˓→oper, isherm = True
Qobj data =
[[0. 0. ]
[0. 0.70710678]]]
As with the other representation conversion functions, to_kraus checks the Qobj.superrep attribute of its input,
and chooses an appropriate conversion method. Thus, in the above example, we can also call to_kraus on J.
KJ = to_kraus(J)
print(KJ)
Output:
[Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0.70710678 0. ]
[0. 0. ]], Quantum object: dims = [[2], [2]], shape = (2, 2), type =␣
˓→oper, isherm = False
Qobj data =
[[0. 0.70710678]
[0. 0. ]], Quantum object: dims = [[2], [2]], shape = (2, 2), type =␣
˓→oper, isherm = True
Qobj data =
[[0. 0. ]
[0. 0.70710678]]]
Output:
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.]
[0. 0.]]
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.]
[0. 0.]]
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.]
[0. 0.]]
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.]
[0. 0.]]
The Stinespring representation is closely related to the Kraus representation, and consists of a pair of operators 𝐴
and 𝐵 such that for all operators 𝑋 acting on ℋ,
where the partial trace is over a new index that corresponds to the index in the Kraus summation. Conversion to
Stinespring is handled by the to_stinespring function.
a = create(2).dag()
print(S)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= False
Qobj data =
[[1. 0. 0. 0.1]
[0. 0.9 0. 0. ]
(continues on next page)
A, B = to_stinespring(S)
print(A)
Output:
Quantum object: dims = [[2, 3], [2]], shape = (6, 2), type = oper, isherm = False
Qobj data =
[[-0.98845443 0. ]
[ 0. 0.31622777]
[ 0.15151842 0. ]
[ 0. -0.93506452]
[ 0. 0. ]
[ 0. -0.16016975]]
print(B)
Output:
Quantum object: dims = [[2, 3], [2]], shape = (6, 2), type = oper, isherm = False
Qobj data =
[[-0.98845443 0. ]
[ 0. 0.31622777]
[ 0.15151842 0. ]
[ 0. -0.93506452]
[ 0. 0. ]
[ 0. -0.16016975]]
Notice that a new index has been added, such that 𝐴 and 𝐵 have dimensions [[2, 3], [2]], with the length-3
index representing the fact that the Choi matrix is rank-3 (alternatively, that the map has three Kraus operators).
to_kraus(S)
print(to_choi(S).eigenenergies())
Output:
Finally, the last superoperator representation supported by QuTiP is the 𝜒-matrix representation,
𝜒𝛼,𝛽 𝐵𝛼 𝜌𝐵𝛽† ,
∑︁
Λ(𝜌) =
𝛼,𝛽
where {𝐵𝛼√
} is a basis for the space of matrices acting on ℋ. In QuTiP, this basis is taken to be the Pauli basis
𝐵𝛼 = 𝜎𝛼 / 2. Conversion to the 𝜒 formalism is handled by the to_chi function.
chi = to_chi(S)
print(chi)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= True, superrep = chi
Qobj data =
(continues on next page)
One convenient property of the 𝜒 matrix is that the average gate fidelity with the identity map can be read off
directly from the 𝜒00 element:
np.testing.assert_almost_equal(average_gate_fidelity(S), 0.9499999999999998)
print(chi[0, 0] / 4)
Output:
(0.925+0j)
Here, the factor of 4 comes from the dimension of the underlying Hilbert space ℋ. As with the superoperator
and Choi representations, the 𝜒 representation is denoted by the Qobj.superrep, such that to_super, to_choi,
to_kraus, to_stinespring and to_chi all convert from the 𝜒 representation appropriately.
In addition to converting between the different representations of quantum maps, QuTiP also provides attributes to
make it easy to check if a map is completely positive, trace preserving and/or hermicity preserving. Each of these
attributes uses Qobj.superrep to automatically perform any needed conversions.
In particular, a quantum map is said to be positive (but not necessarily completely positive) if it maps all positive
operators to positive operators. For instance, the transpose map Λ(𝜌) = 𝜌T is a positive map. We run into problems,
however, if we tensor Λ with the identity to get a partial transpose map.
rho = ket2dm(bell_state())
rho_out = partial_transpose(rho, [0, 1])
print(rho_out.eigenenergies())
Output:
Notice that even though we started with a positive map, we got an operator out with negative eigenvalues. Complete
positivity addresses this by requiring that a map returns positive operators for all positive operators, and does so even
under tensoring with another map. The Choi matrix is very useful here, as it can be shown that a map is completely
positive if and only if its Choi matrix is positive [Wat13]. QuTiP implements this check with the Qobj.iscp
attribute. As an example, notice that the snippet above already calculates the Choi matrix of the transpose map by
acting it on half of an entangled pair. We simply need to manually set the dims and superrep attributes to reflect
the structure of the underlying Hilbert space and the chosen representation.
J = rho_out
J.dims = [[[2], [2]], [[2], [2]]]
J.superrep = 'choi'
print(J.iscp)
Output:
False
This confirms that the transpose map is not completely positive. On the other hand, the transpose map does satisfy
a weaker condition, namely that it is hermicity preserving. That is, Λ(𝜌) = (Λ(𝜌))† for all 𝜌 such that 𝜌 = 𝜌† . To
see this, we note that (𝜌T )† = 𝜌* , the complex conjugate of 𝜌. By assumption, 𝜌 = 𝜌† = (𝜌* )T , though, such that
Λ(𝜌) = Λ(𝜌† ) = 𝜌* . We can confirm this by checking the Qobj.ishp attribute:
print(J.ishp)
Output:
True
Next, we note that the transpose map does preserve the trace of its inputs, such that Tr(Λ[𝜌]) = Tr(𝜌) for all 𝜌.
This can be confirmed by the Qobj.istp attribute:
print(J.istp)
Output:
False
Finally, a map is called a quantum channel if it always maps valid states to valid states. Formally, a map is a channel
if it is both completely positive and trace preserving. Thus, QuTiP provides a single attribute to quickly check that
this is true.
>>> print(J.iscptp)
False
>>> print(to_super(qeye(2)).iscptp)
True
To describe the states of multipartite quantum systems - such as two coupled qubits, a qubit coupled to an oscillator,
etc. - we need to expand the Hilbert space by taking the tensor product of the state vectors for each of the system
components. Similarly, the operators acting on the state vectors in the combined Hilbert space (describing the
coupled system) are formed by taking the tensor product of the individual operators.
In QuTiP the function tensor is used to accomplish this task. This function takes as argument a collection:
or a list:
of state vectors or operators and returns a composite quantum object for the combined Hilbert space. The function
accepts an arbitrary number of states or operators as argument. The type returned quantum object is the same as
that of the input(s).
For example, the state vector describing two qubits in their ground states is formed by taking the tensor product of
the two single-qubit ground state vectors:
Output:
Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket
Qobj data =
[[1.]
[0.]
[0.]
[0.]]
Output:
Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket
Qobj data =
[[1.]
[0.]
[0.]
[0.]]
This is straightforward to generalize to more qubits by adding more component state vectors in the argument list
to the tensor function, as illustrated in the following example:
Output:
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.5]
[0. ]
[0.5]
[0. ]
[0.5]
[0. ]
[0.5]
[0. ]]
This state is slightly more complicated, describing two qubits in a superposition between the up and down states,
while the third qubit is in its ground state.
To construct operators that act on an extended Hilbert space of a combined system, we similarly pass a list of
operators for each component system to the tensor function. For example, to form the operator that represents
the simultaneous action of the 𝜎𝑥 operator on two qubits:
print(tensor(sigmax(), sigmax()))
Output:
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm = True
Qobj data =
[[0. 0. 0. 1.]
[0. 0. 1. 0.]
[0. 1. 0. 0.]
[1. 0. 0. 0.]]
To create operators in a combined Hilbert space that only act on a single component, we take the tensor product of
the operator acting on the subspace of interest, with the identity operators corresponding to the components that
are to be unchanged. For example, the operator that represents 𝜎𝑧 on the first qubit in a two-qubit system, while
leaving the second qubit unaffected:
print(tensor(sigmaz(), identity(2)))
Output:
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm = True
Qobj data =
[[ 1. 0. 0. 0.]
[ 0. 1. 0. 0.]
[ 0. 0. -1. 0.]
[ 0. 0. 0. -1.]]
The tensor function is extensively used when constructing Hamiltonians for composite systems. Here we’ll look
at some simple examples.
First, let’s consider a system of two coupled qubits. Assume that both the qubits have equal energy splitting, and
that the qubits are coupled through a 𝜎𝑥 ⊗ 𝜎𝑥 interaction with strength g = 0.05 (in units where the bare qubit
energy splitting is unity). The Hamiltonian describing this system is:
print(H)
Output:
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm = True
Qobj data =
[[ 2. 0. 0. 0.05]
[ 0. 0. 0.05 0. ]
[ 0. 0.05 0. 0. ]
[ 0.05 0. 0. -2. ]]
print(H)
Output:
Quantum object: dims = [[2, 2, 2], [2, 2, 2]], shape = (8, 8), type = oper, isherm =␣
˓→True
Qobj data =
[[ 3. 0. 0. 0.25 0. 0. 0.5 0. ]
(continues on next page)
The simplest possible quantum mechanical description for light-matter interaction is encapsulated in the Jaynes-
Cummings model, which describes the coupling between a two-level atom and a single-mode electromagnetic field
(a cavity mode). Denoting the energy splitting of the atom and cavity omega_a and omega_c, respectively, and
the atom-cavity interaction strength g, the Jaynes-Cummings Hamiltonian can be constructed as:
N = 6
omega_a = 1.0
omega_c = 1.25
g = 0.75
a = tensor(identity(2), destroy(N))
sm = tensor(destroy(2), identity(N))
sz = tensor(sigmaz(), identity(N))
0, 0| 0, 1| 0, 2| 0, 3| 0, 4| 0, 5| 1, 0| 1, 1| 1, 2| 1, 3| 1, 4| 1, 5|
8
|0, 0
|0, 1 6
|0, 2
4
|0, 3
|0, 4 2
|0, 5
0
|1, 0
|1, 1 2
|1, 2
4
|1, 3
|1, 4 6
|1, 5
8
The partial trace is an operation that reduces the dimension of a Hilbert space by eliminating some degrees of
freedom by averaging (tracing). In this sense it is therefore the converse of the tensor product. It is useful when
one is interested in only a part of a coupled quantum system. For open quantum systems, this typically involves
tracing over the environment leaving only the system of interest. In QuTiP the class method ptrace is used to take
partial traces. ptrace acts on the Qobj instance for which it is called, and it takes one argument sel, which is a
list of integers that mark the component systems that should be kept. All other components are traced out.
For example, the density matrix describing a single qubit obtained from a coupled two-qubit system is obtained
via:
>>> psi.ptrace(0)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
(continues on next page)
>>> psi.ptrace(1)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0. 0.]
[0. 1.]]
Note that the partial trace always results in a density matrix (mixed state), regardless of whether the composite
system is a pure state (described by a state vector) or a mixed state (described by a density matrix):
>>> psi
Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket
Qobj data =
[[0.70710678]
[0. ]
[0.70710678]
[0. ]]
>>> psi.ptrace(0)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0.5 0.5]
[0.5 0.5]]
>>> rho
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm = True
Qobj data =
[[0.5 0. 0.5 0. ]
[0. 0. 0. 0. ]
[0.5 0. 0.5 0. ]
[0. 0. 0. 0. ]]
>>> rho.ptrace(0)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
Qobj data =
[[0.5 0.5]
[0.5 0.5]]
As described in Superoperators and Vectorized Operators, superoperators are operators that act on Liouville space,
the vectorspace of linear operators. Superoperators can be represented using the isomorphism vec : ℒ(ℋ) →
ℋ⊗ℋ [Hav03], [Wat13]. To represent superoperators acting on ℒ(ℋ1 ⊗ℋ2 ) thus takes some tensor rearrangement
to get the desired ordering ℋ1 ⊗ ℋ2 ⊗ ℋ1 ⊗ ℋ2 .
In particular, this means that tensor does not act as one might expect on the results of to_super:
>>> A = qeye([2])
>>> B = qeye([3])
In the former case, the result correctly has four copies of the compound index with dims [2, 3]. In the latter case,
however, each of the Hilbert space indices is listed independently and in the wrong order.
The super_tensor function performs the needed rearrangement, providing the most direct analog to tensor
on the underlying Hilbert space. In particular, for any two type="oper" Qobjs A and B, to_super(tensor(A,
B)) == super_tensor(to_super(A), to_super(B)) and operator_to_vector(tensor(A, B)) ==
super_tensor(operator_to_vector(A), operator_to_vector(B)). Returning to the previous example:
The composite function automatically switches between tensor and super_tensor based on the type of its
arguments, such that composite(A, B) returns an appropriate Qobj to represent the composition of two systems.
QuTiP also allows more general tensor manipulations that are useful for converting between superoperator repre-
sentations [WBC11]. In particular, the tensor_contract function allows for contracting one or more pairs of
indices. This can be used to find superoperators that represent partial trace maps. Using this functionality, we can
construct some quite exotic maps, such as a map from 3 × 3 operators to 2 × 2 operators:
We start off by first demonstrating plotting of superoperators, as this will be useful to us in visualizing the results
of a contracted channel.
In particular, we will use Hinton diagrams as implemented by hinton, which show the real parts of matrix elements
as squares whose size and color both correspond to the magnitude of each element. To illustrate, we first plot a few
density operators.
from qutip import hinton, identity, Qobj, to_super, sigmaz, tensor, tensor_contract
from qutip.core.gates import cnot, hadamard_transform
hinton(identity([2, 3]).unit())
hinton(Qobj([[1, 0.5], [0.5, 1]]).unit())
0, 0| 0, 1| 0, 2| 1, 0| 1, 1| 1, 2|
|0, 0 0.20
0.15
|0, 1
0.10
|0, 2 0.05
0.00
|1, 0 0.05
0.10
|1, 1 0.15
|1, 2 0.20
0| 1|
0.6
|0 0.4
0.2
0.0
0.2
|1 0.4
0.6
We show superoperators as matrices in the Pauli basis, such that any Hermicity-preserving map is represented by
a real-valued matrix. This is especially convienent for use with Hinton diagrams, as the plot thus carries complete
information about the channel.
As an example, conjugation by 𝜎𝑧 leaves ⊮ and 𝜎𝑧 invariant, but flips the sign of 𝜎𝑥 and 𝜎𝑦 . This is indicated in
Hinton diagrams by a negative-valued square for the sign change and a positive-valued square for a +1 sign.
hinton(to_super(sigmaz()))
I X Y Z
I 1.0
0.5
X
0.0
Y 0.5
1.0
Z
As a couple more examples, we also consider the supermatrix for a Hadamard transform and for 𝜎𝑧 ⊗ 𝐻.
hinton(to_super(hadamard_transform()))
hinton(to_super(tensor(sigmaz(), hadamard_transform())))
I X Y Z
I 1.0
0.5
X
0.0
Y 0.5
1.0
Z
II IXIYIZXIXXXYXZYIYXYYYZZIZXZYZZ
II
IX
IY 1.0
IZ
XI
XX 0.5
XY
XZ 0.0
YI
YX
YY 0.5
YZ
ZI
ZX 1.0
ZY
ZZ
We can think of the CNOT here as a system-environment representation of an open quantum process, in which an
environment register is prepared in a state 𝜌anc , then a unitary acts jointly on the system of interest and environ-
ment. Finally, the environment is traced out, leaving a channel on the system alone. In terms of Wood diagrams
<http://arxiv.org/abs/1111.6950>, this can be represented as the composition of a preparation map, evolution un-
der the system-environment unitary, and then a measurement map.
The two tensor wires on the left indicate where we must take a tensor contraction to obtain the measurement map.
Numbering the tensor wires from 0 to 3, this corresponds to a tensor_contract argument of (1, 3).
Meanwhile, the super_tensor function implements the swap on the right, such that we can quickly find the
preparation map.
q = tensor(identity(2), basis(2))
s_prep = sprepost(q, q.dag())
For a CNOT system-environment model, the composition of these maps should give us a completely dephasing
channel. The channel on both qubits is just the superunitary CNOT channel:
hinton(to_super(cnot()))
II IXIYIZXIXXXYXZYIYXYYYZZIZXZYZZ
II
IX
IY 1.0
IZ
XI
XX 0.5
XY
XZ 0.0
YI
YX
YY 0.5
YZ
ZI
ZX 1.0
ZY
ZZ
We now complete by multiplying the superunitary CNOT by the preparation channel above, then applying the partial
trace channel by contracting the second and fourth index indices. As expected, this gives us a dephasing map.
I X Y Z
I 1.0
0.5
X
0.0
Y 0.5
1.0
Z
3.6.1 Introduction
Although in some cases, we want to find the stationary states of a quantum system, often we are interested in the
dynamics: how the state of a system or an ensemble of systems evolves with time. QuTiP provides many ways to
model dynamics.
There are two kinds of quantum systems: open systems that interact with a larger environment and closed systems
that do not. In a closed system, the state can be described by a state vector. When we are modeling an open system,
or an ensemble of systems, the use of the density matrix is mandatory.
The following table lists of the solvers QuTiP provides for dynamic quantum systems and indicates the type of
object returned by the solver:
Before embarking on simulating the dynamics of quantum systems, we will first look at the data structure used for
returning the simulation results. This object is a Result class that stores all the crucial data needed for analyzing
and plotting the results of a simulation. A generic Result object result contains the following properties for
storing simulation data:
Property Description
result.solver String indicating which solver was used to generate the data.
result.times List/array of times at which simulation data is calculated.
result.expect List/array of expectation values, if requested.
result.e_data Dictionary of expectation values, if requested.
result.states List/array of state vectors/density matrices calculated at times, if requested.
result.final_state State vector or density matrix at the last time of the evolution.
result.stats Various statistics about the evolution.
To understand how to access the data in a Result object we will use an example as a guide, although we do not
worry about the simulation details at this stage. Like all solvers, the Master Equation solver used in this example
returns an Result object, here called simply result. To see what is contained inside result we can use the print
function:
>>> print(result)
<Result
Solver: mesolve
Solver stats:
method: 'scipy zvode adams'
init time: 0.0001876354217529297
preparation time: 0.007544517517089844
run time: 0.001268625259399414
solver: 'Master Equation Evolution'
num_collapse: 1
Time interval: [0, 1.0] (2 steps)
(continues on next page)
The first line tells us that this data object was generated from the Master Equation solver mesolve. Next we have
the statistics including the ODE solver used, setup time, number of collpases. Then the integration interval is
described, followed with the number of expectation value computed. Finally, it says whether the states are stored.
Now we have all the information needed to analyze the simulation results. To access the data for the two expectation
values one can do:
expt0 = result.expect[0]
expt1 = result.expect[1]
Recall that Python uses C-style indexing that begins with zero (i.e., [0] => 1st collapse operator data). Alternatively,
expectation values can be obtained as a dictionary:
When e_ops is a list, e_data ca be used with the list index. Together with the array of times at which these
expectation values are calculated:
times = result.times
plot(times, expt0)
plot(times, expt1)
show()
State vectors, or density matrices, are accessed in a similar manner, although typically one does not need an in-
dex (i.e [0]) since there is only one list for each of these components. Some other solver can have other output,
heomsolve’s results can have ado_states output if the options store_ados is set, similarly, fmmesolve can
return floquet_states.
Solver which compute multiple trajectories such as the Monte Carlo Equations Solvers or the Stochastics Solvers
result will differ depending on whether the trajectories are flags to be saved. For example:
>>> np.shape(result.expect)
(1, 11)
>>> np.shape(result.expect)
(1, 25, 11)
When the runs are not saved, the expectation values and states are averaged over all trajectories, while a list over
the runs are given when they are stored. For a fix output format, average_expect return the average, while
runs_states return the list over trajectories. The runs_ output will return None when the trajectories are not
saved. Standard derivation of the expectation values is also available:
Multiple trajectories results also keep the trajectories seeds to allows recomputing the results.
seeds = result.seeds
One last feature specific to multi-trajectories results is the addition operation that can be used to merge sets of
trajectories.
Unitary evolution
The dynamics of a closed (pure) quantum system is governed by the Schrödinger equation
𝜕
𝑖ℏ ˆ
Ψ = 𝐻Ψ, (3.1)
𝜕𝑡
where Ψ is the wave function, 𝐻 ˆ the Hamiltonian, and ℏ is Planck’s constant. In general, the Schrödinger equation
is a partial differential equation (PDE) where both Ψ and 𝐻 ˆ are functions of space and time. For computational
purposes it is useful to expand the PDE in a set of basis functions that span the Hilbert space of the Hamiltonian,
and to write the equation in matrix and vector form
𝑑
𝑖ℏ |𝜓⟩ = 𝐻 |𝜓⟩
𝑑𝑡
where |𝜓⟩ is the state vector and 𝐻 is the matrix representation of the Hamiltonian. This matrix equation can,
in principle, be solved by diagonalizing the Hamiltonian matrix 𝐻. In practice, however, it is difficult to perform
this diagonalization unless the size of the Hilbert space (dimension of the matrix 𝐻) is small. Analytically, it is
a formidable task to calculate the dynamics for systems with more than two states. If, in addition, we consider
dissipation due to the inevitable interaction with a surrounding environment, the computational complexity grows
even larger, and we have to resort to numerical calculations in all realistic situations. This illustrates the importance
of numerical calculations in describing the dynamics of open quantum systems, and the need for efficient and
accessible tools for this task.
The Schrödinger equation, which governs the time-evolution of closed quantum systems, is defined by its Hamilto-
nian and state vector. In the previous section, Using Tensor Products and Partial Traces, we showed how Hamiltoni-
ans and state vectors are constructed in QuTiP. Given a Hamiltonian, we can calculate the unitary (non-dissipative)
time-evolution of an arbitrary state vector |𝜓0 ⟩ (psi0) using the QuTiP solver SESolver or the function sesolve.
It evolves the state vector and evaluates the expectation values for a set of operators e_ops at the points in time in
the list times, using an ordinary differential equation solver.
For example, the time evolution of a quantum spin-1/2 system with tunneling rate 0.1 that initially is in the up state
is calculated, and the expectation values of the 𝜎𝑧 operator evaluated, with the following code
See the next section for examples on evolution with dissipation using mesolve.
The function returns an instance of Result, as described in the previous section Dynamics Simulation Results.
The attribute expect in result is a list of expectation values for the operator(s) that are passed to the e_ops
parameter. Passing multiple operators to e_ops as a list or dict results in a vector of expectation value for each
operators. result.e_data present the expectation values as a dict of list of expect outputs, while result.expect
coerce the values to numpy arrays.
The resulting expectation values can easily be visualized using matplotlib’s plotting functions:
1.00
0.75
0.50
Expectation values
0.25
0.00
0.25
0.50
0.75
Sigma-Z
1.00 Sigma-Y
0 2 4 6 8 10
Time
If an empty list of operators is passed to the e_ops parameter, the sesolve and mesolve functions return a Result
instance that contains a list of state vectors for the times specified in times
Non-unitary evolution
While the evolution of the state vector in a closed quantum system is deterministic, open quantum systems are
stochastic in nature. The effect of an environment on the system of interest is to induce stochastic transitions
between energy levels, and to introduce uncertainty in the phase difference between states of the system. The
state of an open quantum system is therefore described in terms of ensemble averaged states using the density
matrix formalism. ∑︀A density matrix 𝜌 describes a probability distribution of quantum states |𝜓𝑛 ⟩, in a matrix
representation 𝜌 = 𝑛 𝑝𝑛 |𝜓𝑛 ⟩ ⟨𝜓𝑛 |, where 𝑝𝑛 is the classical probability that the system is in the quantum state
|𝜓𝑛 ⟩. The time evolution of a density matrix 𝜌 is the topic of the remaining portions of this section.
The standard approach for deriving the equations of motion for a system interacting with its environment is to
expand the scope of the system to include the environment. The combined quantum system is then closed, and its
evolution is governed by the von Neumann equation
𝑖
𝜌˙ tot (𝑡) = − [𝐻tot , 𝜌tot (𝑡)], (3.2)
ℏ
the equivalent of the Schrödinger equation (3.1) in the density matrix formalism. Here, the total Hamiltonian
includes the original system Hamiltonian 𝐻sys , the Hamiltonian for the environment 𝐻env , and a term representing
the interaction between the system and its environment 𝐻int . Since we are only interested in the dynamics of the
system, we can at this point perform a partial trace over the environmental degrees of freedom in Eq. (3.2), and
thereby obtain a master equation for the motion of the original system density matrix. The most general trace-
preserving and completely positive form of this evolution is the Lindblad master equation for the reduced density
matrix 𝜌 = Trenv [𝜌tot ]
𝑖 ∑︁ 1 [︀
2𝐶𝑛 𝜌(𝑡)𝐶𝑛† − 𝜌(𝑡)𝐶𝑛† 𝐶𝑛 − 𝐶𝑛† 𝐶𝑛 𝜌(𝑡)
]︀
˙ = − [𝐻(𝑡), 𝜌(𝑡)] +
𝜌(𝑡) (3.3)
ℏ 𝑛
2
√
where the 𝐶𝑛 = 𝛾𝑛 𝐴𝑛 are collapse operators, and 𝐴𝑛 are the operators through which the environment couples
to the system in 𝐻int , and 𝛾𝑛 are the corresponding rates. The derivation of Eq. (3.3) may be found in several
sources, and will not be reproduced here. Instead, we emphasize the approximations that are required to arrive at
the master equation in the form of Eq. (3.3) from physical arguments, and hence perform a calculation in QuTiP:
• Separability: At 𝑡 = 0 there are no correlations between the system and its environment such that the total
density matrix can be written as a tensor product 𝜌𝐼tot (0) = 𝜌𝐼 (0) ⊗ 𝜌𝐼env (0).
• Born approximation: Requires: (1) that the state of the environment does not significantly change as a
result of the interaction with the system; (2) The system and the environment remain separable throughout
the evolution. These assumptions are justified if the interaction is weak, and if the environment is much
larger than the system. In summary, 𝜌tot (𝑡) ≈ 𝜌(𝑡) ⊗ 𝜌env .
• Markov approximation The time-scale of decay for the environment 𝜏env is much shorter than the smallest
time-scale of the system dynamics 𝜏sys ≫ 𝜏env . This approximation is often deemed a “short-memory
environment” as it requires that environmental correlation functions decay on a time-scale fast compared to
those of the system.
• Secular approximation Stipulates that elements in the master equation corresponding to transition frequen-
cies satisfy |𝜔𝑎𝑏 − 𝜔𝑐𝑑 | ≪ 1/𝜏sys , i.e., all fast rotating terms in the interaction picture can be neglected. It
also ignores terms that lead to a small renormalization of the system energy levels. This approximation is
not strictly necessary for all master-equation formalisms (e.g., the Block-Redfield master equation), but it is
required for arriving at the Lindblad form (3.3) which is used in mesolve.
For systems with environments satisfying the conditions outlined above, the Lindblad master equation (3.3) governs
the time-evolution of the system density matrix, giving an ensemble average of the system dynamics. In order
to ensure that these approximations are not violated, it is important that the decay rates 𝛾𝑛 be smaller than the
minimum energy splitting in the system Hamiltonian. Situations that demand special attention therefore include,
for example, systems strongly coupled to their environment, and systems with degenerate or nearly degenerate
energy levels.
For non-unitary evolution of a quantum systems, i.e., evolution that includes incoherent processes such as relaxation
and dephasing, it is common to use master equations. In QuTiP, the function mesolve is used for both: the evolution
according to the Schrödinger equation and to the master equation, even though these two equations of motion are
very different. The mesolve function automatically determines if it is sufficient to use the Schrödinger equation (if
no collapse operators were given) or if it has to use the master equation (if collapse operators were given). Note that
to calculate the time evolution according to the Schrödinger equation is easier and much faster (for large systems)
than using the master equation, so if possible the solver will fall back on using the Schrödinger equation.
What is new in the master equation compared to the Schrödinger equation are processes that describe dissipation
in the quantum system due to its interaction with an environment. These environmental interactions are defined
by the operators through which the system couples to the environment, and rates that describe the strength of the
processes.
In QuTiP, the product of the square root of the rate and the operator that describe the dissipation process is called
a collapse operator. A list of collapse operators (c_ops) is passed as the fourth argument to the mesolve function
in order to define the dissipation processes in the master equation. When the c_ops isn’t empty, the mesolve
function will use the master equation instead of the unitary Schrödinger equation.
Using the example with the spin dynamics from the previous section, we can easily add a relaxation process (de-
scribing the dissipation of energy from the spin to its environment), by adding np.sqrt(0.05) * sigmax() in
the fourth parameter to the mesolve function.
1.00 Sigma-Z
Sigma-Y
0.75
0.50
Expectation values
0.25
0.00
0.25
0.50
0.75
0 2 4 6 8 10
Time
Here, 0.05 is the rate and the operator 𝜎𝑥 (sigmax) describes the dissipation process.
Now a slightly more complex example: Consider a two-level atom coupled to a leaky single-mode cavity through
a dipole-type interaction, which supports a coherent exchange of quanta between the two systems. If the atom
initially is in its groundstate and the cavity in a 5-photon Fock state, the dynamics is calculated with the lines
following code
4
Expectation values
0
0 2 4 6 8 10
Time
Introduction
Where as the density matrix formalism describes the ensemble average over many identical realizations of a quan-
tum system, the Monte Carlo (MC), or quantum-jump approach to wave function evolution, allows for simulating
an individual realization of the system dynamics. Here, the environment is continuously monitored, resulting in a
series of quantum jumps in the system wave function, conditioned on the increase in information gained about the
state of the system via the environmental measurements. In general, this evolution is governed by the Schrödinger
𝑖ℏ ∑︁ +
𝐻eff = 𝐻sys − 𝐶 𝐶𝑛 , (3.4)
2 𝑖 𝑛
where again, the 𝐶𝑛 are collapse operators, each corresponding to a separate irreversible process with rate 𝛾𝑛 .
Here, the strictly negative non-Hermitian portion of Eq. (3.4) gives rise to a reduction in the norm of the wave
function, that to first-order in a small time 𝛿𝑡, is given by ⟨𝜓(𝑡 + 𝛿𝑡)|𝜓(𝑡 + 𝛿𝑡)⟩ = 1 − 𝛿𝑝 where
∑︁ ⟨︀
𝜓(𝑡)|𝐶𝑛+ 𝐶𝑛 |𝜓(𝑡) ,
⟩︀
𝛿𝑝 = 𝛿𝑡 (3.5)
𝑛
and 𝛿𝑡 is such that 𝛿𝑝 ≪ 1. With a probability of remaining in the state |𝜓(𝑡 + 𝛿𝑡)⟩ given by 1 − 𝛿𝑝, the cor-
responding quantum jump probability is thus Eq. (3.5). If the environmental measurements register a quantum
jump, say via the emission of a photon into the environment, or a change in the spin of a quantum dot, the wave
function undergoes a jump into a state defined by projecting |𝜓(𝑡)⟩ using the collapse operator 𝐶𝑛 corresponding
to the measurement
⟩︀1/2
|𝜓(𝑡 + 𝛿𝑡)⟩ = 𝐶𝑛 |𝜓(𝑡)⟩ / 𝜓(𝑡)|𝐶𝑛+ 𝐶𝑛 |𝜓(𝑡) (3.6)
⟨︀
.
If more than a single collapse operator is present in Eq. (3.4), the probability of collapse due to the 𝑖th-operator
𝐶𝑖 is given by
Evaluating the MC evolution to first-order in time is quite tedious. Instead, QuTiP uses the following algorithm to
simulate a single realization of a quantum system. Starting from a pure state |𝜓(0)⟩:
• Ia: Choose a random number 𝑟1 between zero and one, representing the probability that a quantum jump
occurs.
• Ib: Choose a random number 𝑟2 between zero and one, used to select which collapse operator was respon-
sible for the jump.
• II: Integrate the Schrödinger equation, using the effective Hamiltonian (3.4) until a time 𝜏 such that the norm
of the wave function satisfies ⟨𝜓(𝜏 ) |𝜓(𝜏 )⟩ = 𝑟1 , at which point a jump occurs.
• III: The resultant jump projects the system at time 𝜏 into one of the renormalized states given by Eq. (3.6).
The corresponding collapse operator 𝐶𝑛 is chosen such that 𝑛 is the smallest integer satisfying:
𝑛
∑︁
𝑃𝑛 (𝜏 ) ≥ 𝑟2 (3.8)
𝑖=1
where the individual 𝑃𝑛 are given by Eq. (3.7). Note that the left hand side of Eq. (3.8) is, by definition, normalized
to unity.
• IV: Using the renormalized state from step III as the new initial condition at time 𝜏 , draw a new random
number, and repeat the above procedure until the final simulation time is reached.
In QuTiP, Monte Carlo evolution is implemented with the mcsolve function. It takes nearly the same arguments as
the mesolve function for master-equation evolution, except that the initial state must be a ket vector, as oppose to a
density matrix, and there is an optional keyword parameter ntraj that defines the number of stochastic trajectories
to be simulated. By default, ntraj=500 indicating that 500 Monte Carlo trajectories will be performed.
To illustrate the use of the Monte Carlo evolution of quantum systems in QuTiP, let’s again consider the case of a
two-level atom coupled to a leaky cavity. The only differences to the master-equation treatment is that in this case
we invoke the mcsolve function instead of mesolve
plt.figure()
plt.plot(times, data.expect[0], times, data.expect[1])
plt.title('Monte Carlo time evolution')
plt.xlabel('Time')
plt.ylabel('Expectation values')
plt.legend(("cavity photon number", "atom excitation probability"))
plt.show()
5
4
3
2
1
0
0 2 4 6 8 10
Time
The advantage of the Monte Carlo method over the master equation approach is that only the state vector is required
to be kept in the computers memory, as opposed to the entire density matrix. For large quantum system this
becomes a significant advantage, and the Monte Carlo solver is therefore generally recommended for such systems.
For example, simulating a Heisenberg spin-chain consisting of 10 spins with random parameters and initial states
takes almost 7 times longer using the master equation rather than Monte Carlo approach with the default number of
trajectories running on a quad-CPU machine. Furthermore, it takes about 7 times the memory as well. However,
for small systems, the added overhead of averaging a large number of stochastic trajectories to obtain the open
system dynamics, as well as starting the multiprocessing functionality, outweighs the benefit of the minor (in this
case) memory saving. Master equation methods are therefore generally more efficient when Hilbert space sizes are
on the order of a couple of hundred states or smaller.
The Monte Carlo solver returns a McResult object consisting of expectation values and/or states. The main differ-
ence with mesolve’s Result is that it optionally stores the result of each trajectory together with their averages.
When trajectories are stored, result.runs_expect is a list over the expectation operators, trajectories and times
in that order. The averages are stored in result.average_expect and the standard derivation of the expecta-
tion values in result.std_expect. When the states are returned, result.runs_states will be an array of
length ntraj. Each element contains an array of “Qobj” type ket with the same number of elements as times.
result.average_states is a list of density matrices computed as the average of the states at each time step. Fur-
thermore, the output will also contain a list of times at which the collapse occurred, and which collapse operators
did the collapse. These can be obtained in result.col_times and result.col_which respectively.
By default, the mcsolve function runs 500 trajectories. This value was chosen because it gives good accuracy,
Monte Carlo errors scale as 1/𝑛 where 𝑛 is the number of trajectories, and simultaneously does not take an excessive
amount of time to run. However, you can change the number of trajectories to fit your needs. In order to run 1000
trajectories in the above example, we can simply modify the call to mcsolve like:
where we have added the keyword argument ntraj=1000 at the end of the inputs. Now, the Monte Carlo solver will
calculate expectation values for both operators, a.dag() * a, sm.dag() * sm averaging over 1000 trajectories.
Other than a target number of trajectories, it is possible to use a computation time or errors bars as condition to
stop computing trajectories.
timeout is quite simple as mcsolve will stop starting the computation of new trajectories when it is reached.
Thus:
Will compute 60 seconds of trajectories or 1000, which ever is reached first. The solver will finish any trajectory
started when the timeout is reached. Therefore if the computation time of a single trajectory is quite long, the
overall computation time can be much longer that the provided timeout.
Lastly, mcsolve can be instructed to stop when the statistical error of the expectation values get under a certain
value. When computing the average over trajectories, the error on these are computed using jackknife resampling
for each expect and each time and the computation will be stopped when all these values are under the tolerance
passed to target_tol. Therefore:
will stop either after all errors bars on expectation values are under 0.01, 1000 trajectories are computed or 10
minutes have passed, whichever comes first. When a single values is passed, it is used as the absolute value of the
tolerance. When a pair of values is passed, it is understood as an absolute and relative tolerance pair. For even
finer control, one such pair can be passed for each e_ops. For example:
will stop when the error bars on the expectation values of the first e_ops are under 10% of their average values.
If after computation of some trajectories, it is determined that more are needed, it is possible to add trajectories to
existing result by adding result together:
Note that this merging operation only checks that the result are compatible – i.e. that the e_ops and tlist are the
same. It does not check that the same initial state or Hamiltonian where used.
This can be used to explore the convergence of the Monte Carlo solver. For example, the following code block
plots expectation values for 1, 10 and 100 trajectories:
expt1 = data1.expect
expt10 = data10.expect
expt100 = data100.expect
plt.figure()
plt.plot(times, expt1[0], label="ntraj=1")
plt.plot(times, expt10[0], label="ntraj=10")
plt.plot(times, expt100[0], label="ntraj=100")
plt.title('Monte Carlo time evolution')
plt.xlabel('Time')
plt.ylabel('Expectation values')
plt.legend()
plt.show()
0 2 4 6 8 10
Time
Oftentimes, quantum jumps are rare. This is especially true in the context of simulating gates for quantum informa-
tion purposes, where typical gate times are orders of magnitude smaller than typical timescales for decoherence. In
this case, using the standard monte-carlo sampling algorithm, we often repeatedly sample the no-jump trajectory.
We can thus reduce the number of required runs by only sampling the no-jump trajectory once. We then extract
the no-jump probability 𝑝, and for all future runs we only sample random numbers 𝑟1 where 𝑟1 > 𝑝, thus ensuring
that a jump will occur. When it comes time to compute expectation values, we weight the no-jump trajectory by 𝑝
and the jump trajectories by 1 − 𝑝. This algorithm is described in [Abd19] and can be utilized by setting the option
"improved_sampling" in the call to mcsolve:
where in this case the first run samples the no-jump trajectory, and the remaining 499 trajectories are all guaranteed
to include (at least) one jump.
The power of this algorithm is most obvious when considering systems that rarely undergo jumps. For instance,
consider the following T1 simulation of a qubit with a lifetime of 10 microseconds (assuming time is in units of
nanoseconds)
plt.figure()
plt.plot(times, data.expect[0], label="original")
plt.plot(times, data_imp.expect[0], label="improved sampling")
plt.plot(times, np.exp(-gamma * times), label=r"$\exp(-\gamma t)$")
plt.title('Monte Carlo: improved sampling algorithm')
plt.xlabel("time [ns]")
plt.ylabel(r"$p_{1}$")
plt.legend()
plt.show()
0.990
0.985
p1
0.980
0.975
0.970
The original sampling algorithm samples the no-jump trajectory on average 96.7% of the time, while the improved
sampling algorithm only does so once.
Reproducibility
For reproducibility of Monte-Carlo computations it is possible to set the seed of the random number generator:
The seeds parameter can either be an integer or a numpy SeedSequence, which will then be used to create seeds
for each trajectory. Alternatively it may be a list of intergers or SeedSequence s with one seed for each trajectories.
Seeds available in the result object can be used to redo the same evolution:
Monte-Carlo evolutions often need hundreds of trajectories to obtain sufficient statistics. Since all trajectories are
independent of each other, they can be computed in parallel. The option map can take "serial", "parallel" or
"loky". Both "parallel" and "loky" compute trajectories on multiple CPUs using respectively the multipro-
cessing and loky python modules.
Note that when running in parallel, the order in which the trajectories are added to the result can differ. Therefore
>>> print(res_par.seeds[:3])
[SeedSequence(entropy=1,spawn_key=(1,),),
SeedSequence(entropy=1,spawn_key=(0,),),
SeedSequence(entropy=1,spawn_key=(2,),)]
>>> print(res_ser.seeds[:3])
[SeedSequence(entropy=1,spawn_key=(0,),),
SeedSequence(entropy=1,spawn_key=(1,),),
SeedSequence(entropy=1,spawn_key=(2,),)]
Photocurrent
The photocurrent, previously computed using the photocurrent_sesolve and photocurrent_sesolve func-
tions, are now included in the output of mcsolve as result.photocurrent.
plt.figure()
plt.plot((times[:-1] + times[1:])/2, data.photocurrent[0])
plt.title('Monte Carlo Photocurrent')
plt.xlabel('Time')
plt.ylabel('Photon detections')
plt.show()
1.2
1.0
Photon detections
0.8
0.6
0.4
0.2
0 2 4 6 8 10
Time
Open Systems
mcsolve can be used to study systems which have measurement and dissipative interactions with their environment.
This is done by passing a Liouvillian including the dissipative interaction to the solver instead of a Hamiltonian.
In this case the effective Liouvillian becomes:
1 ∑︁ (︀ +
𝐶𝑛 𝐶𝑛 𝜌 + 𝜌𝐶𝑛+ 𝐶𝑛 ,
)︀
𝐿eff 𝜌 = 𝐿sys 𝜌 − (3.9)
2 𝑖
And a jump with the collapse operator n changing the state as:
We can redo the previous example for a situation where only half the emitted photons are detected.
plt.figure()
plt.plot((times[:-1] + times[1:])/2, data.photocurrent[0])
plt.title('Monte Carlo Photocurrent')
plt.xlabel('Time')
plt.ylabel('Photon detections')
plt.show()
0.6
0.5
Photon detections
0.4
0.3
0.2
0.1
0.0
0 2 4 6 8 10
Time
Introduction
The Krylov-subspace method is a standard method to approximate quantum dynamics. Let |𝜓⟩ be a state in
a 𝐷-dimensional complex Hilbert space that evolves under a time-independent Hamiltonian 𝐻. Then, the 𝑁 -
dimensional Krylov subspace associated with that state and Hamiltonian is given by
where the dimension 𝑁 < 𝐷 is a parameter of choice. To construct an orthonormal basis 𝐵𝑁 for 𝒦𝑁 , the simplest
algorithm is the well-known Lanczos algorithm, which provides a sort of Gram-Schmidt procedure that harnesses
the fact that orthonormalization needs to be imposed only for the last two vectors in the basis. Written in this basis
the time-evolved state can be approximated as
|𝜓(𝑡)⟩ = 𝑒−𝑖𝐻𝑡 |𝜓⟩ ≈ P𝑁 𝑒−𝑖𝐻𝑡 P𝑁 |𝜓⟩ = V†𝑁 𝑒−𝑖𝑇𝑁 𝑡 V𝑁 |𝜓⟩ ≡ |𝜓𝑁 (𝑡)⟩ , (3.13)
where 𝑇𝑁 = V𝑁 𝐻V†𝑁 is the Hamiltonian reduced to the Krylov subspace (which takes a tridiagonal matrix form),
and V†𝑁 is the matrix containing the vectors of the Krylov basis as columns.
With the above approximation, the time-evolution is calculated only with a smaller square matrix of the desired
size. Therefore, the Krylov method provides huge speed-ups in computation of short-time evolutions when the
dimension of the Hamiltonian is very large, a point at which exact calculations on the complete subspace are
practically impossible.
One of the biggest problems with this type of method is the control of the error. After a short time, the error starts
to grow exponentially. However, this can be easily corrected by restarting the subspace when the error reaches a
certain threshold. Therefore, a series of 𝑀 Krylov-subspace time evolutions provides accurate solutions for the
complete time evolution. Within this scheme, the magic of Krylov resides not only in its ability to capture complex
time evolutions from very large Hilbert spaces with very small dimenions 𝑀 , but also in the computing speed-up
it presents.
For exceptional cases, the Lanczos algorithm might arrive at the exact evolution of the initial state at a dimension
𝑀ℎ𝑏 < 𝑀 . This is called a happy breakdown. For example, if a Hamiltonian has a symmetry subspace 𝐷sim < 𝑀 ,
then the algorithm will optimize using the value math:M_{hb}<M:, at which the evolution is not only exact but
also cheap.
In QuTiP, Krylov-subspace evolution is implemented as the function krylovsolve. Arguments are nearly the
same as sesolve function for master-equation evolution, except that the Hamiltonian cannot depend on time, the
initial state must always be a ket vector, (it cannot be used to compute propagators) and an additional parameter
krylov_dim is needed. krylov_dim defines the maximum allowed Krylov-subspace dimension.
Let’s solve a simple example using the algorithm in QuTiP to get familiar with the method.
4 jmat x
jmat y
3 jmat z
2
Expectation values
1
0
1
2
3
4
0 2 4 6 8 10
Time
When a quantum system is subjected to continuous measurement, through homodyne detection for example, it is
possible to simulate the conditional quantum state using stochastic Schrodinger and master equations. The solution
of these stochastic equations are quantum trajectories, which represent the conditioned evolution of the system given
a specific measurement record.
In general, the stochastic evolution of a quantum state is calculated in QuTiP by solving the general equation
∑︁
𝑑𝜌(𝑡) = 𝑑1 𝜌 𝑑𝑡 + 𝑑2,𝑛 𝜌 𝑑𝑊𝑛 , (3.14)
𝑛
where 𝑑𝑊𝑛 is a Wiener increment, which has the expectation values 𝐸[𝑑𝑊 ] = 0 and 𝐸[𝑑𝑊 2 ] = 𝑑𝑡.
In QuTiP, this equation can be solved using the function ssesolve, which is implemented by defining 𝑑1 and 𝑑2,𝑛
from Equation (3.14) as
𝑒2
(︂ )︂
1 ∑︁
𝑑1 = −𝑖𝐻 − 𝑆𝑛† 𝑆𝑛 − 𝑒𝑛 𝑆𝑛 + 𝑖 , (3.17)
2 𝑛 4
and
𝑒𝑛
𝑑2,𝑛 = 𝑆𝑛 − . (3.18)
2
The solver ssesolve will construct the operators 𝑑1 and 𝑑2,𝑛 once the user passes the Hamiltonian (H) and the
stochastic operator list (sc_ops). As with the mcsolve, the number of trajectories and the seed for the noise reali-
sation can be fixed using the arguments: ntraj and seeds, respectively. If the user also requires the measurement
output, the options entry {"store_measurement": True} should be included.
Per default, homodyne is used. Heterodyne detections can be easily simulated by passing the arguments
'heterodyne=True' to ssesolve.
When the initial state of the system is a density matrix 𝜌, the stochastic master equation solver qutip.
stochastic.smesolve must be used. The stochastic master equation is given by (see section 4.4, [Wis09])
where
1 [︀
2𝐴𝜌𝐴† − 𝜌𝐴† 𝐴 − 𝐴† 𝐴𝜌 , (3.20)
]︀
𝐷[𝐴]𝜌 =
2
and
In QuTiP, solutions for the stochastic master equation are obtained using the solver smesolve. The implementation
takes into account 2 types of collapse operators. 𝐶𝑖 (c_ops) represent the dissipation in the environment, while 𝑆𝑛
(sc_ops) are monitored operators. The deterministic part of the evolution, described by the 𝑑1 in Equation (3.14),
takes into account all operators 𝐶𝑖 and 𝑆𝑛 :
∑︁ ∑︁
𝑑1 = −𝑖[𝐻(𝑡), 𝜌(𝑡)] + 𝐷[𝐶𝑖 ]𝜌 + 𝐷[𝑆𝑛 ]𝜌, (3.22)
𝑖 𝑛
As in the stochastic Schrodinger equation, heterodyne detection can be chosen by passing heterodyne=True.
Example
Below, we solve the dynamics for an optical cavity at 0K whose output is monitored using homodyne detection. The
cavity decay rate is given by 𝜅 and the ∆ is the cavity detuning with respect to the driving field. The measurement
operators can be passed using the option m_ops. The homodyne current 𝐽𝑥 is calculated using
where 𝑥 is the operator passed using m_ops. The results are available in result.measurements.
# parameters
DIM = 20 # Hilbert space dimension
DELTA = 5 * 2 * np.pi # cavity detuning
KAPPA = 2 # cavity decay rate
INTENSITY = 4 # intensity of initial state
NUMBER_OF_TRAJECTORIES = 500
stoc_solution = smesolve(
H, rho_0, times,
c_ops=[],
sc_ops=[np.sqrt(KAPPA) * a],
e_ops=[x],
ntraj=NUMBER_OF_TRAJECTORIES,
options={"dt": 0.00125, "store_measurement": True,}
)
fig, ax = plt.subplots()
ax.set_title('Stochastic Master Equation - Homodyne Detection')
ax.plot(times[1:], np.array(stoc_solution.measurement).mean(axis=0)[0, :].real,
'r', lw=2, label=r'$J_x$')
ax.plot(times, stoc_solution.expect[0], 'k', lw=2,
label=r'$\langle x \rangle$')
ax.set_xlabel('Time')
ax.legend()
6
0.0 0.2 0.4 0.6 0.8 1.0
Time
The stochastic solvers share many features with mcsolve, such as end conditions, seed control and running in
parallel. See the sections Changing the Number of Trajectories, Reproducibility and Running trajectories in parallel
for details.
Time-Dependent Operators
In the previous examples of quantum evolution, we assumed that the systems under consideration were described by
time-independent Hamiltonians. However, many systems have explicit time dependence in either the Hamiltonian,
or the collapse operators describing coupling to the environment, and sometimes both components might depend on
time. The time-evolutions solvers such as sesolve, brmesolve, etc. are all capable of handling time-dependent
Hamiltonians and collapse terms. QuTiP use QobjEvo to represent time-dependent quantum operators. There are
three different ways to build a QobjEvo:
1. Function based: Build the time dependent operator from a function returning a Qobj:
def oper(t):
return num(N) + (destroy(N) + create(N)) * np.sin(t)
H_t = QobjEvo(oper)
1. List based: The time dependent quantum operator is represented as a list of qobj and [qobj,
coefficient] pairs:
3. coefficent based: The product of a Qobj with a Coefficient, created by the coefficient function, result in
a QobjEvo:
These 3 examples will create the same time dependent operator, however the function based method will usually
be slower when used in solver.
Most solvers accept a QobjEvo when an operator is expected: this include the Hamiltonian H, collapse operators,
expectation values operators, the operator of brmesolve’s a_ops, etc. Exception are krylovsolve’s Hamiltonian
and HEOM’s Bath operators.
Most solvers will accept any format that could be made into a QobjEvo for the Hamiltonian. All of the following
are equivalent:
Collapse operator also accept a list of object that could be made into QobjEvo. However one needs to be careful
about not confusing the list nature of the c_ops parameter with list format quantum system. In the following call:
mesolve will see 2 collapses operators: num(N) and [destroy(N) + create(N), lambda t: np.sin(t)].
It is therefore preferred to pass each collapse operator as either a Qobj or a QobjEvo.
As an example, we will look at a case with a time-dependent Hamiltonian
[︁ of the
]︁ form 𝐻 = 𝐻0 + 𝑓 (𝑡)𝐻1 where
2
𝑓 (𝑡) is the time-dependent driving strength given as 𝑓 (𝑡) = 𝐴 exp − (𝑡/𝜎) . The following code sets up the
problem
ustate = basis(3, 0)
excited = basis(3, 1)
ground = basis(3, 2)
g = 5 # coupling strength
H0 = -g * (sigma_ge.dag() * a + a.dag() * sigma_ge) # time-independent term
H1 = (sigma_ue.dag() + sigma_ue) # time-dependent term
Given that we have a single time-dependent Hamiltonian term, and constant collapse terms, we need to specify a
single Python function for the coefficient 𝑓 (𝑡). In this case, one can simply do
def H1_coeff(t):
return 9 * np.exp(-(t / 5.) ** 2)
In this case, the return value depends only on time. However it is possible to add optional arguments to the call,
see Using arguments. Having specified our coefficient function, we can now specify the Hamiltonian in list format
and call the solver (in this case mesolve)
We can call the Monte Carlo solver in the exact same way (if using the default ntraj=500):
The output from the master equation solver is identical to that shown in the examples, the Monte Carlo however
will be noticeably off, suggesting we should increase the number of trajectories for this example. In addition, we
can also consider the decay of a simple Harmonic oscillator with time-varying decay rate
kappa = 0.5
Qobjevo
QobjEvo as a time dependent quantum system, as it’s main functionality create a Qobj at a time:
QobjEvo’s follow the same mathematical operations rules than Qobj. They can be added, subtracted and multiplied
with scalar, Qobj and QobjEvo. They also support the dag and trans and conj method and can be used for tensor
operations and super operator transformation:
H = tensor(H_t, qeye(2))
c_op = tensor(QobjEvo([destroy(N), lambda t: np.exp(-t)]), sigmax())
Or equivalently:
L = liouvillian(H, [c_op])
Using arguments
Until now, the coefficients were only functions of time. In the definition of H1_coeff, the driving amplitude A and
width sigma were hardcoded with their numerical values. This is fine for problems that are specialized, or that we
only want to run once. However, in many cases, we would like study the same problem with a range of parameters
and not have to worry about manually changing the values on each run. QuTiP allows you to accomplish this
using by adding extra arguments to coefficients function that make the QobjEvo. For instance, instead of explicitly
writing 9 for the amplitude and 5 for the width of the gaussian driving term, we can add an args positional variable:
When the second positional input of the coefficient function is named args, the arguments are passed as a Python
dictionary of key: value pairs. Otherwise the coefficient function is called as coeff(t, **args). In the
last example, args = {'A': a, 'sigma': b} where a and b are the two parameters for the amplitude and
width, respectively. This args dictionary need to be given at creation of the QobjEvo when function using then
are included:
>>> QobjEvo(system)
TypeError: H1_coeff() missing 2 required positional arguments: 'A' and 'sigma'
When evaluation the QobjEvo at a time, new arguments can be passed either with the args dictionary positional
arguments, or with specific keywords arguments:
>>> print(qevo(1))
Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', isherm=True
Qobj data =
[[ 1. 8.64710495]
[ 8.64710495 -1. ]]
>>> print(qevo(1, {"A": 5, "sigma": 0.2}))
Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', isherm=True
Qobj data =
[[ 1.00000000e+00 6.94397193e-11]
[ 6.94397193e-11 -1.00000000e+00]]
>>> print(qevo(1, A=5))
Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', isherm=True
Qobj data =
[[ 1. 4.8039472]
[ 4.8039472 -1. ]]
Whether the original coefficient used the args or specific input does not matter. It is fine to mix the different
signatures.
Solver calls take an args input that is used to build the time dependent system. If the Hamiltonian or collapse
operators are already QobjEvo, their arguments will be overwritten.
To update arguments of an existing time dependent quantum system, you can pass the previous object as the input
of a QobjEvo with new args:
When merging two or more QobjEvo, each will keep it arguments, but calling it with updated are will affect all
parts:
Coefficients
To build time dependent quantum system we often use a list of Qobj and Coefficient. These Coefficient
represent the strength of the corresponding quantum object a function that of time. Up to now, we used functions
for these, but QuTiP support multiple formats: callable, strings, array.
Function coefficients : Use a callable with the signature f(t: double, ...) -> double as coefficient. Any
function or method that can be called by f(t, args), f(t, **args) is accepted.
String coefficients : Use a string containing a simple Python expression. The variable t, common mathematical
functions such as sin or exp an variable in args will be available. If available, the string will be compiled using
cython, fixing variable type when possible, allowing slightly faster execution than function. While the speed up
is usually very small, in long evolution, numerous calls to the functions are made and it’s can accumulate. From
version 5, compilation of the coefficient is done only once and saved between sessions. When either the cython or
filelock modules are not available, the code will be executed in python using exec with the same environment .
This, however, as no advantage over using python function.
Per default, a cubic spline interpolation is used, but the order of the interpolation can be controlled with the order
input: Outside the interpolation range, the first or last value are used.
plt.legend()
0.30 CubicSpline
step
linear
0.25
0.20
0.15
0.10
0.05
0.00
0.0 0.2 0.4 0.6 0.8 1.0
When using array coefficients in solver, if the time dependent quantum system is in list format, the solver tlist is
used as times of the array. This is often not ideal as the interpolation is usually less precise close the extremities
of the range. It is therefore better to create the QobjEvo using an extended range prior to the solver:
N = 5
times = np.linspace(-0.1, 1.1, 13)
coeff = np.exp(-times)
4.0
3.8
3.6
3.4
3.2
3.0
2.8
2.6
0.0 0.2 0.4 0.6 0.8 1.0
Special care is needed when working with pulses. ODE solvers select the step length automatically and can miss
thin pulses when not properly warned. Integrations methods with variable step sizes have the max_step option
that control the maximum length of a single internal integration step. This value should be set to under half the
pulse width to be certain they are not missed.
For example, the following pulse is missed without fixing the maximum step length.
def pulse(t):
return 10 * np.pi * (0.7 < t < 0.75)
plt.ylim([-0.1, 1.1])
plt.legend(loc="center left")
1.0
0.8
0.6 no max_step
fixed max_step
pulse
0.4
0.2
0.0
In QuTiP version 5 and later, solvers such as mesolve, mcsolve also have a class interface. The class interface
allows reusing the Hamiltonian and fine tuning many details of how the solver is run.
Examples of some of the solver class features are given below.
There are many cases where one would like to study multiple evolutions of the same quantum system, whether
by changing the initial state or other parameters. In order to evolve a given system as fast as possible, the solvers
in QuTiP take the given input operators (Hamiltonian, collapse operators, etc) and prepare them for use with the
selected ODE solver.
These operations are usually reasonably fast, but for some solvers, such as brmesolve or fmmesolve, the overhead
can be significant. Even for simpler solvers, the time spent organizing data can become appreciable when repeatedly
solving a system.
The class interface allows us to setup the system once and reuse it with various parameters. Most ...solve
function have a paired ...Solver class, with a ..Solver.run method to run the evolution. At class instance
creation, the physics (H, c_ops, a_ops, etc.) and options are passed. The initial state, times and expectation
operators are only passed when calling run:
plt.figure()
plt.plot(times, data1.expect[0], "b", times, data1.expect[1], "r", lw=2)
plt.plot(times, data2.expect[0], 'b--', times, data2.expect[1], 'r--', lw=2)
plt.title('Master Equation time evolution')
plt.xlabel('Time', fontsize=14)
plt.ylabel('Expectation values', fontsize=14)
plt.legend(("cavity photon number", "atom excitation probability"))
plt.show()
4
Expectation values
0
0 1 2 3 4 5 6
Time
Note that as shown, options can be set at initialization or with the options property.
The simulation parameters, the args of the QobjEvo passed as system operators, can be updated at the start of a
run:
plt.figure()
plt.plot(times, data1.expect[0], label="A=pi/2")
plt.plot(times, data2.expect[0], label="A=pi/4")
plt.plot(times, data3.expect[0], label="A=pi/8")
plt.title('Master Equation time evolution')
plt.xlabel('Time', fontsize=14)
plt.ylabel('Expectation values', fontsize=14)
plt.legend()
plt.show()
4.0
3.5
3.0
2.5
0 1 2 3 4 5 6
Time
Stepping through the run
The solver class also allows to run through a simulation one step at a time, updating args at each step:
data = [5.]
solver.start(state0=psi0, t0=times[0])
for t in times[1:]:
psi_t = solver.step(t, args={"A": np.pi*np.exp(-(t-3)**2)})
data.append(expect(e_ops[0], psi_t))
plt.figure()
plt.plot(times, data)
plt.title('Master Equation time evolution')
plt.xlabel('Time', fontsize=14)
plt.ylabel('Expectation values', fontsize=14)
plt.legend(("cavity photon number"))
plt.show()
4.5
Expectation values
4.0
3.5
3.0
2.5
0 1 2 3 4 5 6
Time
Note: This is an example only, updating a constant args parameter between step should not replace using a
function as QobjEvo’s coefficient.
Note: It is possible to create multiple solvers and to advance them using step in parallel. However, many ODE
solver, including the default adams method, only allow one instance at a time per process. QuTiP supports using
multiple solver instances of these ODE solvers but with a performance cost. In these situations, using dop853 or
vern9 integration method is recommended instead.
The state of the system during the evolution is accessible via properties of the solver classes.
Each solver has a StateFeedback and ExpectFeedback class method that can be passed as arguments to time
dependent systems. For example, ExpectFeedback can be used to create a system which uncouples when there
are 5 or fewer photons in the cavity.
plt.figure()
plt.plot(times, data[0])
plt.plot(times, data[1])
plt.title('Master Equation time evolution')
plt.xlabel('Time', fontsize=14)
plt.ylabel('Expectation values', fontsize=14)
plt.legend(("cavity photon number", "atom excitation probability"))
plt.show()
5
4
3
2
1
0
0.0 0.2 0.4 0.6 0.8 1.0
Time
Introduction
The Lindblad master equation introduced earlier is constructed so that it describes a physical evolution of the density
matrix (i.e., trace and positivity preserving), but it does not provide a connection to any underlying microscopic
physical model. The Lindblad operators (collapse operators) describe phenomenological processes, such as for
example dephasing and spin flips, and the rates of these processes are arbitrary parameters in the model. In many
situations the collapse operators and their corresponding rates have clear physical interpretation, such as dephasing
and relaxation rates, and in those cases the Lindblad master equation is usually the method of choice.
However, in some cases, for example systems with varying energy biases and eigenstates and that couple to an
environment in some well-defined manner (through a physically motivated system-environment interaction opera-
tor), it is often desirable to derive the master equation from more fundamental physical principles, and relate it to
for example the noise-power spectrum of the environment.
The Bloch-Redfield formalism is one such approach to derive a master equation from a microscopic system. It
starts from a combined system-environment perspective, and derives a perturbative master equation for the system
alone, under the assumption of weak system-environment coupling. One advantage of this approach is that the
dissipation processes and rates are obtained directly from the properties of the environment. On the downside, it
does not intrinsically guarantee that the resulting master equation unconditionally preserves the physical properties
of the density matrix (because it is a perturbative method). The Bloch-Redfield master equation must therefore be
used with care, and the assumptions made in the derivation must be honored. (The Lindblad master equation is in
a sense more robust – it always results in a physical density matrix – although some collapse operators might not
be physically justified). For a full derivation of the Bloch Redfield master equation, see e.g. [Coh92] or [Bre02].
Here we present only a brief version of the derivation, with the intention of introducing the notation and how it
relates to the implementation in QuTiP.
The starting point of the Bloch-Redfield formalism is the total Hamiltonian for the system and the environment
(bath): 𝐻 = 𝐻S + 𝐻B + 𝐻I , where 𝐻 is the total system+bath Hamiltonian, 𝐻S and 𝐻B are the system and bath
Hamiltonians, respectively, and 𝐻I is the interaction Hamiltonian.
The most general form of a master equation for the system dynamics is obtained by tracing out the bath from the
von-Neumann equation of motion for the combined system (𝜌˙ = −𝑖ℏ−1 [𝐻, 𝜌]). In the interaction picture the result
is
∫︁ 𝑡
𝑑
𝜌𝑆 (𝑡) = −ℏ−2 𝑑𝜏 Tr𝐵 [𝐻𝐼 (𝑡), [𝐻𝐼 (𝜏 ), 𝜌𝑆 (𝜏 ) ⊗ 𝜌𝐵 ]], (3.25)
𝑑𝑡 0
where the additional assumption that the total system-bath density matrix can be factorized as 𝜌(𝑡) ≈ 𝜌𝑆 (𝑡) ⊗ 𝜌𝐵 .
This assumption is known as the Born approximation, and it implies that there never is any entanglement between
the system and the bath, neither in the initial state nor at any time during the evolution. It is justified for weak
system-bath interaction.
The master equation (3.25) is non-Markovian, i.e., the change in the density matrix at a time 𝑡 depends on states
at all times 𝜏 < 𝑡, making it intractable to solve both theoretically and numerically. To make progress towards a
manageable master equation, we now introduce the Markovian approximation, in which 𝜌𝑆 (𝜏 ) is replaced by 𝜌𝑆 (𝑡)
in Eq. (3.25). The result is the Redfield equation
∫︁ 𝑡
𝑑
𝜌𝑆 (𝑡) = −ℏ−2 𝑑𝜏 Tr𝐵 [𝐻𝐼 (𝑡), [𝐻𝐼 (𝜏 ), 𝜌𝑆 (𝑡) ⊗ 𝜌𝐵 ]], (3.26)
𝑑𝑡 0
which is local in time with respect the density matrix, but still not Markovian since it contains an implicit depen-
dence on the initial state. By extending the integration to infinity and substituting 𝜏 → 𝑡 − 𝜏 , a fully Markovian
master equation is obtained:
∫︁ ∞
𝑑
𝜌𝑆 (𝑡) = −ℏ−2 𝑑𝜏 Tr𝐵 [𝐻𝐼 (𝑡), [𝐻𝐼 (𝑡 − 𝜏 ), 𝜌𝑆 (𝑡) ⊗ 𝜌𝐵 ]]. (3.27)
𝑑𝑡 0
The two Markovian approximations introduced above are valid if the time-scale with which the system dynamics
changes is large compared to the time-scale with which correlations in the bath decays (corresponding to a “short-
memory” bath, which results in Markovian system dynamics).
The master equation (3.27) is still on a too general form to be∑︀
suitable for numerical implementation. We therefore
assume that the system-bath interaction takes the form 𝐻𝐼 = 𝛼 𝐴𝛼 ⊗𝐵𝛼 and where 𝐴𝛼 are system operators and
𝐵𝛼 are bath operators. This allows us to write master equation in terms of system operators and bath correlation
functions:
𝑑 ∑︁ ∫︁ ∞
𝜌𝑆 (𝑡) = −ℏ−2 𝑑𝜏 {𝑔𝛼𝛽 (𝜏 ) [𝐴𝛼 (𝑡)𝐴𝛽 (𝑡 − 𝜏 )𝜌𝑆 (𝑡) − 𝐴𝛼 (𝑡 − 𝜏 )𝜌𝑆 (𝑡)𝐴𝛽 (𝑡)]
𝑑𝑡 0
𝛼𝛽
where 𝑔𝛼𝛽 (𝜏 ) = Tr𝐵 [𝐵𝛼 (𝑡)𝐵𝛽 (𝑡 − 𝜏 )𝜌𝐵 ] = ⟨𝐵𝛼 (𝜏 )𝐵𝛽 (0)⟩, since the bath state 𝜌𝐵 is a steady state.
In the eigenbasis of the system Hamiltonian, where 𝐴𝑚𝑛 (𝑡) = 𝐴𝑚𝑛 𝑒𝑖𝜔𝑚𝑛 𝑡 , 𝜔𝑚𝑛 = 𝜔𝑚 − 𝜔𝑛 and 𝜔𝑚 are the
eigenfrequencies corresponding the eigenstate |𝑚⟩, we obtain in matrix form in the Schrödinger picture
𝑑
𝜌𝑎𝑏 (𝑡) = − 𝑖𝜔𝑎𝑏 𝜌𝑎𝑏 (𝑡)
𝑑𝑡 {︃ [︃ ]︃
∑︁ ∑︁sec ∫︁ ∞ ∑︁
−2 𝛽 𝑖𝜔𝑐𝑎 𝜏
−ℏ 𝑑𝜏 𝑔𝛼𝛽 (𝜏 ) 𝛿𝑏𝑑 𝐴𝛼 𝛽 𝑖𝜔𝑐𝑛 𝜏
𝑎𝑛 𝐴𝑛𝑐 𝑒 − 𝐴𝛼
𝑎𝑐 𝐴𝑑𝑏 𝑒
𝛼,𝛽 𝑐,𝑑 0 𝑛
[︃ ]︃}︃
∑︁ 𝛽 𝑖𝜔𝑛𝑑 𝜏 𝛽 𝑖𝜔𝑏𝑑 𝜏
+ 𝑔𝛼𝛽 (−𝜏 ) 𝛿𝑎𝑐 𝐴𝛼
𝑑𝑛 𝐴𝑛𝑏 𝑒 − 𝐴𝛼
𝑎𝑐 𝐴𝑑𝑏 𝑒 𝜌𝑐𝑑 (𝑡),
𝑛
where the “sec” above the summation symbol indicate summation of the secular terms which satisfy |𝜔𝑎𝑏 −𝜔𝑐𝑑 | ≪
𝜏decay . This is an almost-useful form of the master equation. The final step before arriving at the form of the Bloch-
Redfield master equation that is implemented in QuTiP, involves ∫︀ ∞rewriting the bath correlation function 𝑔(𝜏 ) in
terms of the noise-power spectrum of the environment 𝑆(𝜔) = −∞ 𝑑𝜏 𝑒𝑖𝜔𝜏 𝑔(𝜏 ):
∫︁ ∞
1
𝑑𝜏 𝑔𝛼𝛽 (𝜏 )𝑒𝑖𝜔𝜏 = 𝑆𝛼𝛽 (𝜔) + 𝑖𝜆𝛼𝛽 (𝜔), (3.28)
0 2
where 𝜆𝑎𝑏 (𝜔) is an energy shift that is neglected here. The final form of the Bloch-Redfield master equation is
sec
𝑑 ∑︁
𝜌𝑎𝑏 (𝑡) = −𝑖𝜔𝑎𝑏 𝜌𝑎𝑏 (𝑡) + 𝑅𝑎𝑏𝑐𝑑 𝜌𝑐𝑑 (𝑡), (3.29)
𝑑𝑡
𝑐,𝑑
where
{︃
ℏ−2 ∑︁ ∑︁ 𝛽
𝑅𝑎𝑏𝑐𝑑 =− 𝛿𝑏𝑑 𝐴𝛼 𝛽 𝛼
𝑎𝑛 𝐴𝑛𝑐 𝑆𝛼𝛽 (𝜔𝑐𝑛 ) − 𝐴𝑎𝑐 𝐴𝑑𝑏 𝑆𝛼𝛽 (𝜔𝑐𝑎 )
2 𝑛
𝛼,𝛽
}︃
∑︁ 𝛽 𝛽
+ 𝛿𝑎𝑐 𝐴𝛼 𝛼
𝑑𝑛 𝐴𝑛𝑏 𝑆𝛼𝛽 (𝜔𝑑𝑛 ) − 𝐴𝑎𝑐 𝐴𝑑𝑏 𝑆𝛼𝛽 (𝜔𝑑𝑏 ) ,
𝑛
In QuTiP, the Bloch-Redfield tensor Eq. (3.30) can be calculated using the function bloch_redfield_tensor. It
takes two mandatory arguments: The system Hamiltonian 𝐻, a nested list of operator 𝐴𝛼 , spectral density functions
𝑆𝛼 (𝜔) pairs that characterize the coupling between system and bath. The spectral density functions are Python
callback functions that takes the (angular) frequency as a single argument.
To illustrate how to calculate the Bloch-Redfield tensor, let’s consider a two-level atom
1 1
𝐻 = − ∆𝜎𝑥 − 𝜖0 𝜎𝑧 (3.30)
2 2
def ohmic_spectrum(w):
if w == 0.0: # dephasing inducing noise
return gamma1
else: # relaxation inducing noise
return gamma1 / 2 * (w / (2 * np.pi)) * (w > 0.0)
print(R)
Output:
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = (4, 4), type = super, isherm␣
˓→= False
Qobj data =
[[ 0. +0.j 0. +0.j 0. +0.j
0.24514517+0.j ]
[ 0. +0.j -0.16103412-6.4076169j 0. +0.j
0. +0.j ]
[ 0. +0.j 0. +0.j -0.16103412+6.4076169j
0. +0.j ]
[ 0. +0.j 0. +0.j 0. +0.j
-0.24514517+0.j ]]
Note that it is also possible to add Lindblad dissipation superoperators in the Bloch-Refield tensor by passing the
operators via the c_ops keyword argument like you would in the mesolve or mcsolve functions. For convenience,
the function bloch_redfield_tensor also returns the basis transformation operator, the eigen vector matrix,
since they are calculated in the process of calculating the Bloch-Redfield tensor R, and the ekets are usually needed
again later when transforming operators between the laboratory basis and the eigen basis. The tensor can be
obtained in the laboratory basis by setting fock_basis=True, in that case, the transformation operator is not
returned.
The evolution of a wavefunction or density matrix, according to the Bloch-Redfield master equation (3.29), can
be calculated using the QuTiP function mesolve using Bloch-Refield tensor in the laboratory basis instead of a
liouvillian. For example, to evaluate the expectation values of the 𝜎𝑥 , 𝜎𝑦 , and 𝜎𝑧 operators for the example above,
we can use the following code:
def ohmic_spectrum(w):
if w == 0.0: # dephasing inducing noise
return gamma1
else: # relaxation inducing noise
return gamma1 / 2 * (w / (2 * np.pi)) * (w > 0.0)
sphere = Bloch()
sphere.vector_color = ['r']
sphere.make_sphere()
|0
y
x
|1
The two steps of calculating the Bloch-Redfield tensor and evolving according to the corresponding master equa-
tion can be combined into one by using the function brmesolve, which takes same arguments as mesolve and
mcsolve, save for the additional nested list of operator-spectrum pairs that is called a_ops.
Note: While the code example simulates the Bloch-Redfield equation in the secular approximation, QuTiP’s
implementation allows the user to simulate the non-secular version of the Bloch-Redfield equation by setting
sec_cutoff=-1, as well as do a partial secular approximation by setting it to a float , this float will become
the cutoff for the sum in (3.29) meaning terms with |𝜔𝑎𝑏 − 𝜔𝑐𝑑 | greater than the cutoff will be neglected. Its default
value is 0.1 which corresponds to the secular approximation. For example the command
will simulate the same example as above without the secular approximation. Note that using the non-secular version
may lead to negativity issues.
If you have not done so already, please read the section: Solving Problems with Time-dependent Hamiltonians.
As we have already discussed, the Bloch-Redfield master equation requires transforming into the eigenbasis of the
system Hamiltonian. For time-independent systems, this transformation need only be done once. However, for
time-dependent systems, one must move to the instantaneous eigenbasis at each time-step in the evolution, thus
greatly increasing the computational complexity of the dynamics. In addition, the requirement for computing all
the eigenvalues severely limits the scalability of the method. Fortunately, this eigen decomposition occurs at the
Hamiltonian level, as opposed to the super-operator level, and thus, with efficient programming, one can tackle
many systems that are commonly encountered.
For time-dependent Hamiltonians, the Hamiltonian itself can be passed into the solver like any other time depen-
dent Hamiltonian, as thus we will not discuss this topic further. Instead, here the focus is on time-dependent bath
coupling terms. To this end, suppose that we have a dissipative harmonic oscillator, where the white-noise dissi-
pation rate decreases exponentially with time 𝜅(𝑡) = 𝜅(0) exp(−𝑡). In the Lindblad or Monte Carlo solvers, this
could be implemented as a time-dependent collapse operator list c_ops = [[a, 'sqrt(kappa*exp(-t))']].
In the Bloch-Redfield solver, the bath coupling terms must be Hermitian. As such, in this example, our coupling
operator is the position operator a+a.dag(). The complete example, and comparison to the analytic expression
is:
plt.figure()
plt.plot(tlist, out.expect[0])
plt.plot(tlist, actual_answer)
plt.show()
9.0
8.8
8.6
8.4
8.2
8.0
7.8
7.6
7.4
0 2 4 6 8 10
In many cases, the bath-coupling operators can take the form 𝐴 = 𝑓 (𝑡)𝑎 + 𝑓 (𝑡)* 𝑎+ . The operator parts of the
a_ops can be made of as many time-dependent terms as needed to construct such operator. For example consider
a white-noise bath that is coupled to an operator of the form exp(1j*t)*a + exp(-1j*t)* a.dag(). In this
example, the a_ops list would be:
a_ops = [
([[a, 'exp(1j*t)'], [a.dag(), 'exp(-1j*t)']], f'{kappa} * (w >= 0)')
]
where the first tuple element [[a, 'exp(1j*t)'], [a.dag(), 'exp(-1j*t)']] tells the solver what is the
time-dependent Hermitian coupling operator. The second tuple f'{kappa} * (w >= 0)', gives the noise power
spectrum. A full example is:
N = 10
w0 = 1.0 * 2 * np.pi
g = 0.05 * w0
kappa = 0.15
times = np.linspace(0, 25, 1000)
a = destroy(N)
H = w0 * a.dag() * a + g * (a + a.dag())
psi0 = ket2dm((basis(N, 4) + basis(N, 2) + basis(N, 0)).unit())
a_ops = [[
QobjEvo([[a, 'exp(1j*t)'], [a.dag(), 'exp(-1j*t)']]), (f'{kappa} * (w >= 0)')
]]
e_ops = [a.dag() * a, a + a.dag()]
plt.figure()
plt.plot(times, res_brme.expect[0], label=r'$a^{+}a$')
plt.plot(times, res_brme.expect[1], label=r'$a+a^{+}$')
plt.legend()
plt.show()
2.0 a +a
a + a+
1.5
1.0
0.5
0.0
0 5 10 15 20 25
Further examples on time-dependent Bloch-Redfield simulations can be found in the online tutorials.
Introduction
Many time-dependent problems of interest are periodic. The dynamics of such systems can be solved for directly
by numerical integration of the Schrödinger or Master equation, using the time-dependent Hamiltonian. But they
can also be transformed into time-independent problems using the Floquet formalism. Time-independent problems
can be solve much more efficiently, so such a transformation is often very desirable.
In the standard derivations of the Lindblad and Bloch-Redfield master equations the Hamiltonian describing the
system under consideration is assumed to be time independent. Thus, strictly speaking, the standard forms of these
master equation formalisms should not blindly be applied to system with time-dependent Hamiltonians. However,
in many relevant cases, in particular for weak driving, the standard master equations still turns out to be useful for
many time-dependent problems. But a more rigorous approach would be to rederive the master equation taking
the time-dependent nature of the Hamiltonian into account from the start. The Floquet-Markov Master equation is
one such a formalism, with important applications for strongly driven systems (see e.g., [Gri98]).
Here we give an overview of how the Floquet and Floquet-Markov formalisms can be used for solving time-
dependent problems in QuTiP. To introduce the terminology and naming conventions used in QuTiP we first give
a brief summary of quantum Floquet theory.
𝜕
𝐻(𝑡)Ψ(𝑡) = 𝑖ℏ Ψ(𝑡), (3.31)
𝜕𝑡
where Ψ(𝑡) is the wave function solution. Here we are interested in problems with periodic time-dependence, i.e.,
the Hamiltonian satisfies 𝐻(𝑡) = 𝐻(𝑡 + 𝑇 ) where 𝑇 is the period. According to the Floquet theorem, there exist
solutions to (3.31) of the form
where Ψ𝛼 (𝑡) are the Floquet states (i.e., the set of wave function solutions to the Schrödinger equation), Φ𝛼 (𝑡) =
Φ𝛼 (𝑡 + 𝑇 ) are the periodic Floquet modes, and 𝜖𝛼 are the quasienergy levels. The quasienergy levels are constants
in time, but only uniquely defined up to multiples of 2𝜋/𝑇 (i.e., unique value in the interval [0, 2𝜋/𝑇 ]).
If we know the Floquet modes (for 𝑡 ∈ [0, 𝑇 ]) and the quasienergies for a particular 𝐻(𝑡), we can easily decompose
any initial wavefunction Ψ(𝑡 = 0) in the Floquet states and immediately obtain the solution for arbitrary 𝑡
∑︁ ∑︁
Ψ(𝑡) = 𝑐𝛼 Ψ𝛼 (𝑡) = 𝑐𝛼 exp(−𝑖𝜖𝛼 𝑡/ℏ)Φ𝛼 (𝑡), (3.33)
𝛼 𝛼
This formalism is useful for finding Ψ(𝑡) for a given 𝐻(𝑡) only if we can obtain the Floquet modes Φ𝑎 (𝑡) and
quasienergies 𝜖𝛼 more easily than directly solving (3.31). By substituting (3.32) into the Schrödinger equation
(3.31) we obtain an eigenvalue equation for the Floquet modes and quasienergies
where ℋ(𝑡) = 𝐻(𝑡) − 𝑖ℏ𝜕𝑡 . This eigenvalue problem could be solved analytically or numerically, but in QuTiP we
use an alternative approach for numerically finding the Floquet states and quasienergies [see e.g. Creffield et al.,
Phys. Rev. B 67, 165301 (2003)]. Consider the propagator for the time-dependent Schrödinger equation (3.31),
which by definition satisfies
Inserting the Floquet states from (3.32) into this expression results in
which shows that the Floquet modes are eigenstates of the one-period propagator. We can therefore find the Floquet
modes and quasienergies 𝜖𝛼 = −ℏ arg(𝜂𝛼 )/𝑇 by numerically calculating 𝑈 (𝑇 + 𝑡, 𝑡) and diagonalizing it. In
particular this method is useful to find Φ𝛼 (0) by calculating and diagonalize 𝑈 (𝑇, 0).
The Floquet modes at arbitrary time 𝑡 can then be found by propagating Φ𝛼 (0) to Φ𝛼 (𝑡) using the wave function
propagator 𝑈 (𝑡, 0)Ψ𝛼 (0) = Ψ𝛼 (𝑡), which for the Floquet modes yields
so that Φ𝛼 (𝑡) = exp(𝑖𝜖𝛼 𝑡/ℏ)𝑈 (𝑡, 0)Φ𝛼 (0). Since Φ𝛼 (𝑡) is periodic we only need to evaluate it for 𝑡 ∈ [0, 𝑇 ], and
from Φ𝛼 (𝑡 ∈ [0, 𝑇 ]) we can directly evaluate Φ𝛼 (𝑡), Ψ𝛼 (𝑡) and Ψ(𝑡) for arbitrary large 𝑡.
QuTiP provides a family of functions to calculate the Floquet modes and quasi energies, Floquet state decomposi-
tion, etc., given a time-dependent Hamiltonian.
Consider for example the case of a strongly driven two-level atom, described by the Hamiltonian
1 1 1
𝐻(𝑡) = − ∆𝜎𝑥 − 𝜖0 𝜎𝑧 + 𝐴 sin(𝜔𝑡)𝜎𝑧 . (3.35)
2 2 2
In QuTiP we can define this Hamiltonian as follows:
The 𝑡 = 0 Floquet modes corresponding to the Hamiltonian (3.35) can then be calculated using the FloquetBasis
class, which encapsulates the Floquet modes and the quasienergies:
For some problems interesting observations can be draw from the quasienergy levels alone. Consider for example
the quasienergies for the driven two-level system introduced above as a function of the driving amplitude, calculated
and plotted in the following example. For certain driving amplitudes the quasienergy levels cross. Since the
quasienergies can be associated with the time-scale of the long-term dynamics due that the driving, degenerate
quasienergies indicates a “freezing” of the dynamics (sometimes known as coherent destruction of tunneling).
>>> plt.xlabel(r'$A/\omega$')
>>> plt.ylabel(r'Quasienergy / $\Delta$')
>>> plt.title(r'Floquet quasienergies')
>>> plt.show()
Floquet quasienergies
0.4
0.2
Quasienergy /
0.0
0.2
0.4
0 2 4 6 8 10
A/
Given the Floquet modes at 𝑡 = 0, we obtain the Floquet mode at some later time 𝑡 using FloquetBasis.mode:
The purpose of calculating the Floquet modes is to find the wavefunction solution to the original problem (3.35)
given some initial state |𝜓0 ⟩. To do that, we first need to decompose the initial state in the Floquet states, using the
function FloquetBasis.to_floquet_basis
and given this decomposition of the initial state in the Floquet states we can easily evaluate the wavefunction that
is the solution to (3.35) at an arbitrary time 𝑡 using the function FloquetBasis.from_floquet_basis:
>>> t = 10 * np.random.rand()
>>> psi_t = floquet_basis.from_floquet_basis(f_coeff, t)
The following example illustrates how to use the functions introduced above to calculate and plot the time-evolution
of (3.35).
import numpy as np
from matplotlib import pyplot
import qutip
# calculate the wavefunctions using the from the floquet modes coefficients
p_ex = np.zeros(len(tlist))
for n, t in enumerate(tlist):
psi_t = floquetbasis.from_floquet_basis(f_coeff, t)
p_ex[n] = qutip.expect(qutip.num(2), psi_t)
1.0
0.8
0.2
0.0
0 2 4 6 8 10
Time
When evaluating the Floquet states or the wavefunction at many points in time it is useful to pre-compute the Floquet
modes for the first period of the driving with the required times. The list of times to pre-compute modes for may
be passed to FloquetBasis using precompute=tlist, and then FloquetBasis.from_floquet_basis and
FloquetBasis.to_floquet_basis can be used to efficiently retrieve the wave function at the pre-computed
times. The following example illustrates how the example from the previous section can be solved more efficiently
using these functions for pre-computing the Floquet modes:
import numpy as np
from matplotlib import pyplot
import qutip
# calculate the wavefunctions using the from the floquet modes coefficients
p_ex = np.zeros(len(tlist))
for n, t in enumerate(tlist):
psi_t = floquetbasis.from_floquet_basis(f_coeff, t)
p_ex[n] = qutip.expect(qutip.num(2), psi_t)
(continues on next page)
1.0
0.8
Occupation probability
0.6 Floquet P1
Floquet P0
Lindblad P1
0.4 Lindblad P0
0.2
0.0
0 2 4 6 8 10
Time
Note that the parameters and the Hamiltonian used in this example is not the same as in the previous section, and
hence the different appearance of the resulting figure.
For convenience, all the steps described above for calculating the evolution of a quantum system using the Floquet
formalisms are encapsulated in the function fsesolve. Using this function, we could have achieved the same
results as in the examples above using
A driven system that is interacting with its environment is not necessarily well described by the standard Lindblad
master equation, since its dissipation process could be time-dependent due to the driving. In such cases a rigorious
approach would be to take the driving into account when deriving the master equation. This can be done in many
different ways, but one way common approach is to derive the master equation in the Floquet basis. That approach
results in the so-called Floquet-Markov master equation, see Grifoni et al., Physics Reports 304, 299 (1998) for
details.
For a brief summary of the derivation, the important contents for the implementation in QuTiP are listed below.
The floquet mode |𝜑𝛼 (𝑡)⟩ refers to a full class of quasienergies defined by 𝜖𝛼 + 𝑘Ω for arbitrary 𝑘. Hence, the
quasienenergy difference between two floquet modes is given by
𝜖𝛼 − 𝜖𝛽
∆𝛼𝛽𝑘 = + 𝑘Ω
ℏ
For any coupling operator 𝑞 (given by the user) the matrix elements in the floquet basis are calculated as:
∫︁ 𝑇
1
𝑋𝛼𝛽𝑘 = 𝑑𝑡 𝑒−𝑖𝑘Ω𝑡 ⟨𝜑𝛼 (𝑡)| 𝑞 |𝜑𝛽 (𝑡)⟩
𝑇 0
From the matrix elements and the spectral density 𝐽(𝜔), the decay rate 𝛾𝛼𝛽𝑘 is defined:
The master equation is further simplified by the RWA, which makes the following matrix useful:
∞
∑︁
𝐴𝛼𝛽 = [𝛾𝛼𝛽𝑘 + 𝑛𝑡ℎ (|∆𝛼𝛽𝑘 |)(𝛾𝛼𝛽𝑘 + 𝛾𝛼𝛽−𝑘 )
𝑘=−∞
1 ∑︁
𝜌˙ 𝛼𝛽 (𝑡) = − (𝐴𝜈𝛼 + 𝐴𝜈𝛽 )𝜌𝛼𝛽 (𝑡) 𝛼 ̸= 𝛽
2 𝜈
The QuTiP function fmmesolve implements the Floquet-Markov master equation. It calculates the dynamics
of a system given its initial state, a time-dependent Hamiltonian, a list of operators through which the system
couples to its environment and a list of corresponding spectral-density functions that describes the environment.
In contrast to the mesolve and mcsolve, and the fmmesolve does characterize the environment with dissipation
rates, but extract the strength of the coupling to the environment from the noise spectral-density functions and the
instantaneous Hamiltonian parameters (similar to the Bloch-Redfield master equation solver brmesolve).
Note: Currently the fmmesolve can only accept a single environment coupling operator and spectral-density
function.
The noise spectral-density function of the environment is implemented as a Python callback function that is passed
to the solver. For example:
gamma1 = 0.1
def noise_spectrum(omega):
return (omega>0) * 0.5 * gamma1 * omega/(2*pi)
The other parameters are similar to the mesolve and mcsolve, and the same format for the return value is used
Result. The following example extends the example studied above, and uses fmmesolve to introduce dissipation
into the calculation
import numpy as np
from matplotlib import pyplot
import qutip
1.0 Floquet P1
Floquet P0
Lindblad P1
0.8 Lindblad P0
0.4
0.2
0.0
0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0
Time
Finally, fmmesolve always expects the e_ops to be specified in the laboratory basis (as for other solvers) and we
can calculate expectation values using:
The Monte Carlo solver of QuTiP can also be used to solve the dynamics of time-local non-Markovian master
equations, i.e., master equations of the Lindblad form
𝑖 ∑︁ 𝛾𝑛 (𝑡) [︀
2𝐴𝑛 𝜌(𝑡)𝐴†𝑛 − 𝜌(𝑡)𝐴†𝑛 𝐴𝑛 − 𝐴†𝑛 𝐴𝑛 𝜌(𝑡)
]︀
˙ = − [𝐻, 𝜌(𝑡)] +
𝜌(𝑡) (3.36)
ℏ 𝑛
2
with “rates” 𝛾𝑛 (𝑡) that can take negative values. This can be done with the nm_mcsolve function. The function
is based on the influence martingale formalism [Donvil22] and formally requires that the collapse operators 𝐴𝑛
satisfy a completeness relation of the form
∑︁
𝐴†𝑛 𝐴𝑛 = 𝛼I, (3.37)
𝑛
where I is the identity operator on the system Hilbert space and 𝛼 > 0. Note that when the collapse operators of a
model don’t satisfy such a relation, nm_mcsolve automatically adds an extra collapse operator such that (3.37) is
satisfied. The rate corresponding to this extra collapse operator is set to zero.
Technically, the influence martingale formalism works as follows. We introduce an influence martingale 𝜇(𝑡),
which follows the evolution of the system state. When no jump happens, it evolves as
(︂ ∫︁ 𝑡 )︂
𝜇(𝑡) = exp 𝛼 𝐾(𝜏 )𝑑𝜏 (3.38)
0
where 𝐾(𝑡) is for now an arbitrary function. When a jump corresponding to the collapse operator 𝐴𝑛 happens, the
influence martingale becomes
(︂ )︂
𝐾(𝑡) − 𝛾𝑛 (𝑡)
𝜇(𝑡 + 𝛿𝑡) = 𝜇(𝑡) (3.39)
𝛾𝑛 (𝑡)
Assuming that the state 𝜌¯(𝑡) computed by the Monte Carlo average
𝑁
1 ∑︁
𝜌¯(𝑡) = |𝜓𝑙 (𝑡)⟩⟨𝜓𝑙 (𝑡)| (3.40)
𝑁
𝑙=1
solves a Lindblad master equation with collapse operators 𝐴𝑛 and rates Γ𝑛 (𝑡), the state 𝜌(𝑡) defined by
𝑁
1 ∑︁
𝜌(𝑡) = 𝜇𝑙 (𝑡)|𝜓𝑙 (𝑡)⟩⟨𝜓𝑙 (𝑡)| (3.41)
𝑁
𝑙=1
solves a Lindblad master equation with collapse operators 𝐴𝑛 and shifted rates 𝛾𝑛 (𝑡) − 𝐾(𝑡). Thus, while Γ𝑛 (𝑡) ≥
0, the new “rates” 𝛾𝑛 (𝑡) = Γ𝑛 (𝑡) − 𝐾(𝑡) satisfy no positivity requirement.
The input of nm_mcsolve is almost the same as for mcsolve. The only difference is how the collapse operators
and rate functions should be defined. nm_mcsolve requires collapse operators 𝐴𝑛 and target “rates” 𝛾𝑛 (which
are allowed to take negative values) to be given in list form [[C_1, gamma_1], [C_2, gamma_2], ...]. Note
that we give the actual rate and not its square root, and that nm_mcsolve automatically computes associated jump
rates Γ𝑛 (𝑡) ≥ 0 appropriate for simulation.
We conclude with a simple example demonstrating the usage of the nm_mcsolve function. For more elaborate,
physically motivated examples, we refer to the accompanying tutorial notebook.
# Rate functions
gamma1 = "kappa * nth"
gamma2 = "kappa * (nth+1) + 12 * np.exp(-2*t**3) * (-np.sin(15*t)**2)"
# gamma2 becomes negative during some time intervals
# nm_mcsolve integration
ops_and_rates = []
ops_and_rates.append([a0.dag(), gamma1])
ops_and_rates.append([a0, gamma2])
MCSol = nm_mcsolve(H, psi0, times, ops_and_rates,
args={'kappa': 1.0 / 0.129, 'nth': 0.063},
e_ops=[a0.dag() * a0, a0 * a0.dag()],
options={'map': 'parallel'}, ntraj=2500)
plt.figure()
plt.plot(times, MCSol.expect[0], 'g',
times, MCSol.expect[1], 'b',
times, MCSol.trace, 'r')
plt.plot(times, MESol.expect[0], 'g--',
times, MESol.expect[1], 'b--')
plt.title('Monte Carlo time evolution')
plt.xlabel('Time')
plt.ylabel('Expectation values')
plt.legend((r'$\langle 1 | \rho | 1 \rangle$',
r'$\langle 0 | \rho | 0 \rangle$',
r'$\operatorname{tr} \rho$'))
plt.show()
0.8
Expectation values
0.6 1| |1
0| |0
tr
0.4
0.2
0.0
0.0 0.2 0.4 0.6 0.8 1.0
Time
Occasionally it is necessary to change the built in parameters of the dynamics solvers used by for example the
mesolve and mcsolve functions. The options for all dynamics solvers may be changed by using the dictionaries.
Supported items come from 2 sources, the solver and the ODE integration method. Supported solver options and
their default can be seen using the class interface:
help(MESolver.options)
Options supported by the ODE integration depend on the “method” options of the solver, they can be listed through
the integrator method of the solvers:
help(MESolver.integrator("adams").options)
To use these new settings we can use the keyword argument options in either the mesolve and mcsolve function:
or:
Sometime the evolution of a single state is not sufficient and the full propagator is desired. QuTiP has the
propagator function to compute them:
The first argument is the Hamiltonian, any time dependent system format is accepted. The function also accepts
an optional c_ops argument for collapse operators. When used, a propagator for density matrices is computed:
𝜌(𝑡) = 𝑈 (𝑡)(𝜌(0)):
Many solvers accept an operator as the initial state. When an identity matrix is passed as the initial state, the
propagator is computed. This can be used to compute a propagator for Bloch-Redfield or Floquet equations:
3.7.1 Introduction
The Hierarchical Equations of Motion (HEOM) method was originally developed by Tanimura and Kubo [TK89]
in the context of physical chemistry to ‘’exactly” solve a quantum system in contact with a bosonic environment,
encapsulated in the Hamiltonian:
∑︁ (︁ )︁
𝜔𝑘 𝑎†𝑘 𝑎𝑘 + 𝑄 𝑔𝑘 𝑎𝑘 + 𝑎†𝑘 .
∑︁
𝐻 = 𝐻𝑠 + ˆ
𝑘 𝑘
As in other solutions to this problem, the properties of the bath are encapsulated by its temperature and its spectral
density,
∑︁
𝐽(𝜔) = 𝜋 𝑔𝑘2 𝛿(𝜔 − 𝜔𝑘 ).
𝑘
In the HEOM, for bosonic baths, one typically chooses a Drude-Lorentz spectral density:
2𝜆𝛾𝜔
𝐽𝐷 = ,
(𝛾 2 + 𝜔 2 )
𝛼2 Γ𝜔
𝐽𝑈 = .
[(𝜔𝑐2 − 𝜔 2 )2 + Γ2 𝜔 2 ]
Given the spectral density, the HEOM requires a decomposition of the bath correlation functions in terms of ex-
ponentials. In Bosonic Environments we describe how this is done with code examples, and how these expansions
are passed to the solver.
In addition to support for bosonic environments, QuTiP also provides support for feriomic environments which is
described in Fermionic Environments.
Both bosonic and fermionic environments are supported via a single solver, HEOMSolver, that supports solving
for both dynamics and steady-states.
In this section we consider a simple two-level system coupled to a Drude-Lorentz bosonic bath. The system Hamil-
tonian, 𝐻𝑠𝑦𝑠 , and the bath spectral density, 𝐽𝐷 , are
𝜖𝜎𝑧 ∆𝜎𝑥
𝐻𝑠𝑦𝑠 = +
2 2
2𝜆𝛾𝜔
𝐽𝐷 = 2 ,
(𝛾 + 𝜔 2 )
We will demonstrate how to describe the bath using two different expansions of the spectral density correlation
function (Matsubara’s expansion and a Padé expansion), how to evolve the system in time, and how to calculate
the steady state.
First we will do this in the simplest way, using the built-in implementations of the two bath expansions,
DrudeLorentzBath and DrudeLorentzPadeBath . We will do this both with a truncated expansion and show
how to include an approximation to all of the remaining terms in the bath expansion.
Afterwards, we will show how to calculate the bath expansion coefficients and to use those coefficients to construct
your own bath description so that you can implement your own bosonic baths.
Finally, we will demonstrate how to simulate a system coupled to multiple independent baths, as occurs, for exam-
ple, in certain photosynthesis processes.
A notebook containing a complete example similar to this one implemented in BoFiN can be found in example
notebook 1a.
First, let us construct the system Hamiltonian, 𝐻𝑠𝑦𝑠 , and the initial system state, rho0:
# Bath properties:
gamma = 0.5 # cut off frequency
lam = 0.1 # coupling strength
T = 0.5 # temperature
where 𝛾 (gamma), 𝜆 (lam) and 𝑇 are the parameters of a Drude-Lorentz bath, and Q is the coupling operator between
the system and the bath.
We may the pass these parameters to either DrudeLorentzBath or DrudeLorentzPadeBath to construct an
expansion of the bath correlations:
# Matsubara expansion:
bath = DrudeLorentzBath(Q, lam, gamma, T, Nk)
# Padé expansion:
bath = DrudeLorentzPadeBath(Q, lam, gamma, T, Nk)
Where Nk is the number of terms to retain within the expansion of the bath.
The max_depth parameter determines how many levels of the hierarchy to retain. As a first approximation hier-
archy depth may be thought of as similar to the order of Feynman Diagrams (both classify terms by increasing
number of interactions).
The result is a standard QuTiP results object with the attributes:
• times: the times at which the state was evaluated (i.e. tlist)
• states: the system states at each time
• expect: a list with the values of each e_ops at each time
• e_data: a dictionary with the values of each e_op at each time
• ado_states: see below (an instance of HierarchyADOsState)
If ado_return=True is passed to .run(...) the full set of auxilliary density operators (ADOs) that make up the
hierarchy at each time will be returned as .ado_states. We will describe how to use these to determine other
properties, such as system-bath currents, later in the fermionic guide (see Determining currents).
If one has a full set of ADOs from a previous call of .run(...) you may supply it as the initial state of the solver
by calling .run(result.ado_states[-1], tlist, ado_init=True).
As with other QuTiP solvers, if expectation operators or functions are supplied using .run(..., e_ops=[...])
the expectation values are available in result.expect and result.e_data.
Below we run the solver again, but use e_ops to store the expectation values of the population of the system states
and the coherence:
1.0 P11
P12
0.8
0.6
0.4
0.2
0.0
0.2
Using the same solver, we can also determine the steady state of the combined system and bath using:
where steady_state is the steady state of the system and steady_ados if the steady state of the full hierarchy.
The ADO states are described more fully in Determining currents and HierarchyADOsState.
Matsubara Terminator
When constructing the Drude-Lorentz bath we have truncated the expansion at Nk = 2 terms and ignore the re-
maining terms.
However, since the coupling to these higher order terms is comparatively weak, we may consider the interaction
with them to be Markovian, and construct an additional Lindbladian term that captures their interaction with the
system and the lower order terms in the expansion.
This additional term is called the terminator because it terminates the expansion.
The DrudeLorentzBath and DrudeLorentzPadeBath both provide a means of calculating the terminator for a
given expansion:
# Matsubara expansion:
bath = DrudeLorentzBath(Q, lam, gamma, T, Nk)
# Padé expansion:
bath = DrudeLorentzPadeBath(Q, lam, gamma, T, Nk)
# Construct solver:
solver = HEOMSolver(HL, bath, max_depth=max_depth, options=options)
This captures the Markovian effect of the remaining terms in the expansion without having to fully model many
more terms.
The value delta is an approximation to the strength of the effect of the remaining terms in the expansion (i.e. how
strongly the terminator is coupled to the rest of the system).
So far we have relied on the built-in DrudeLorentzBath to construct the Drude-Lorentz bath expansion for us.
Now we will calculate the coefficients ourselves and construct a BosonicBath directly. A similar procedure can
be used to apply HEOMSolver to any bosonic bath for which we can calculate the expansion coefficients.
The real and imaginary parts of the correlation function, 𝐶(𝑡), for the bosonic bath is expanded in an expontential
series:
𝐶(𝑡) = 𝐶𝑟𝑒𝑎𝑙 (𝑡) + 𝑖𝐶𝑖𝑚𝑎𝑔 (𝑡)
∞
∑︁
𝐶𝑟𝑒𝑎𝑙 (𝑡) = 𝑐𝑘,𝑟𝑒𝑎𝑙 𝑒−𝜈𝑘,𝑟𝑒𝑎𝑙 𝑡
𝑘=0
∞
∑︁
𝐶𝑖𝑚𝑎𝑔 (𝑡) = 𝑐𝑘,𝑖𝑚𝑎𝑔 𝑒−𝜈𝑘,𝑖𝑚𝑎𝑔 𝑡
𝑘=0
In the specific case of Matsubara expansion for the Drude-Lorentz bath, the coefficients of this expansion are, for
the real part, 𝐶𝑟𝑒𝑎𝑙 (𝑡):
{︃
𝛾 𝑘=0
𝜈𝑘,𝑟𝑒𝑎𝑙 =
2𝜋𝑘/𝛽 𝑘 ≥ 1
{︃
𝜆𝛾[cot(𝛽𝛾/2) − 𝑖] 𝑘 = 0
𝑐𝑘,𝑟𝑒𝑎𝑙 = 4𝜆𝛾𝜈𝑘
(𝜈 2 −𝛾 2 )𝛽
𝑘≥1
𝑘
def cot(x):
return 1. / np.tan(x)
beta = 1. / T
Multiple baths
The HEOMSolver supports having a system interact with multiple environments. All that is needed is to supply a
list of baths instead of a single bath.
In the example below we calculate the evolution of a small system where each basis state of the system interacts
with a separate bath. Such an arrangement can model, for example, the Fenna–Matthews–Olson (FMO) pigment-
protein complex which plays an important role in photosynthesis ( for a full FMO example see the notebook https:
//github.com/tehruhn/bofin/blob/main/examples/example-2-FMO-example.ipynb ).
For each bath expansion, we also include the terminator in the system Liouvillian.
At the end, we plot the populations of the system states as a function of time, and show the long-time beating of
quantum state coherence that occurs:
# Plot populations:
fig, axes = plt.subplots(1, 1, sharex=True, figsize=(8,8))
for label, values in result.e_data.items():
axes.plot(result.times, values, label=label)
axes.set_xlabel(r't', fontsize=28)
axes.set_ylabel(r"Population", fontsize=28)
axes.legend(loc=0, fontsize=12)
1.0 P0
P1
P2
0.8
Population
0.6
0.4
0.2
0.0
0 1 2 3 4 5
t
3.7.3 Fermionic Environments
Here we model a single fermion coupled to two electronic leads or reservoirs (e.g., this can describe a single
quantum dot, a molecular transistor, etc). The system hamiltonian, 𝐻𝑠𝑦𝑠 , and bath spectral density, 𝐽𝐷 , are
𝐻𝑠𝑦𝑠 = 𝑐† 𝑐
Γ𝑊 2
𝐽𝐷 = ,
(𝑤 − 𝜇)2 + 𝑊 2
We will demonstrate how to describe the bath using two different expansions of the spectral density correlation
function (Matsubara’s expansion and a Padé expansion), how to evolve the system in time, and how to calculate
the steady state.
Since our fermion is coupled to two reservoirs, we will construct two baths – one for each reservoir or lead – and
call them the left (𝐿) and right (𝑅) baths for convenience. Each bath will have a different chemical potential 𝜇
which we will label 𝜇𝐿 and 𝜇𝑅 .
First we will do this using the built-in implementations of the bath expansions, LorentzianBath and
LorentzianPadeBath .
Afterwards, we will show how to calculate the bath expansion coefficients and to use those coefficients to construct
your own bath description so that you can implement your own fermionic baths.
Our implementation of fermionic baths primarily follows the definitions used by Christian Schinabeck in his dis-
sertation ( https://opus4.kobv.de/opus4-fau/files/10984/DissertationChristianSchinabeck.pdf ) and related publi-
cations.
A notebook containing a complete example similar to this one implemented in BoFiN can be found in example
notebook 4b.
First, let us construct the system Hamiltonian, 𝐻𝑠𝑦𝑠 , and the initial system state, rho0:
where Γ (gamma), 𝑊 and 𝑇 are the parameters of an Lorentzian bath, 𝜇𝐿 (mu_L) and 𝜇𝑅 (mu_R) are the chemical
potentials of the left and right baths, and Q is the coupling operator between the system and the baths.
We may the pass these parameters to either LorentzianBath or LorentzianPadeBath to construct an expansion
of the bath correlations:
# Matsubara expansion:
bath_L = LorentzianBath(Q, gamma, W, mu_L, T, Nk, tag="L")
bath_R = LorentzianBath(Q, gamma, W, mu_R, T, Nk, tag="R")
# Padé expansion:
bath_L = LorentzianPadeBath(Q, gamma, W, mu_L, T, Nk, tag="L")
bath_R = LorentzianPadeBath(Q, gamma, W, mu_R, T, Nk, tag="R")
Where Nk is the number of terms to retain within the expansion of the bath.
Note that we haved labelled each bath with a tag (either “L” or “R”) so that we can identify the exponents from
individual baths later when calculating the currents between the system and the bath.
As in the bosonic case, the max_depth parameter determines how many levels of the hierarchy to retain.
As in the bosonic case, we can specify e_ops in order to retrieve the expectation values of operators at each given
time. See System and bath dynamics for a fuller description of the returned result object.
Below we run the solver again, but use e_ops to store the expectation values of the population of the system states:
1.0 P11
P22
0.8
0.6
0.4
0.2
0.0
0 100 200 300 400 500
t
The plot above is not very exciting. What we would really like to see in this case are the currents between the system
and the two baths. We will plot these in the next section using the auxiliary density operators (ADOs) returned by
the solver.
Determining currents
The currents between the system and a fermionic bath may be calculated from the first level auxiliary density
operators (ADOs) associated with the exponents of that bath.
The contribution to the current into a given bath from each exponent in that bath is:
ContributionfromExponent = ±𝑖Tr(𝑄± · 𝐴)
where the ± sign is the sign of the exponent (see the description later in Padé expansion coefficients) and 𝑄± is 𝑄
for + exponents and 𝑄† for - exponents.
The first-level exponents for the left bath are retrieved by calling .filter(tags=["L"]) on ado_state which is
an instance of HierarchyADOsState and also provides access to the methods of HierarchyADOs which describes
the structure of the hierarchy for a given problem.
Here the tag “L” matches the tag passed when constructing bath_L earlier in this example.
Similarly, we may calculate the current to the right bath from the exponents tagged with “R”.
Once we have defined functions for retrieving the currents for the baths, we can pass them to e_ops and plot the
results:
0.004
0.003
Current
0.002
0.001
0.000
0 20 40 60 80 100
t
And now we have a more interesting plot that shows the currents to the left and right baths decaying towards their
steady states!
In the next section, we will calculate the steady state currents directly.
Using the same solver, we can also determine the steady state of the combined system and bath using:
and calculate the steady state currents to the two baths from steady_ados using the same heom_current function
we defined previously:
Now we can add the steady state currents to the previous plot:
0.003
Current
0.002
0.001
0.000
0 20 40 60 80 100
t
As you can see, there is still some way to go beyond t = 100 before the steady state is reached!
We now look at how to calculate the correlation expansion coefficients for the Lorentzian spectral density ourselves.
Once we have calculated the coefficients we can construct a FermionicBath directly from them. A similar proce-
dure can be used to apply HEOMSolver to any fermionic bath for which we can calculate the expansion coefficients.
In the fermionic case we must descriminate between the order in which excitations are created within the bath, so
we define two different correlation functions, 𝐶+ (𝑡), and 𝐶− (𝑡):
∫︁ ∞
𝜎 1
𝐶 (𝑡) = 𝑑𝜔𝑒𝜎𝑖𝜔𝑡 𝐽(𝜔)𝑓𝐹 [𝜎𝛽(𝜔 − 𝜇)]
2𝜋 −∞
where 𝜎 is either + or - and, 𝑓𝐹 is the Fermi distribution function, and 𝐽(𝜔) is the Lorentzian spectral density we
defined at the start.
The Fermi distribution function is:
As in the bosonic case we can approximate this integral with a Matsubara or Padé expansion. For the Lorentzian
bath the Padé expansion converges much more quickly, so we will calculate the Padé expansion coefficients here.
The Padé decomposition approximates the Fermi distribution as:
𝑁𝑘
1 ∑︁ 2𝑘𝑙 𝑥
𝑓𝐹 (𝑥) ≈ 𝑓𝐹approx (𝑥) = −
2 𝑥2 + 𝜖2𝑙
𝑙=0
where 𝑘𝑙 and 𝜖𝑙 are coefficients defined in J. Chem Phys 133, “Efficient on the fly calculation of time correlation
functions in computer simulations”, and 𝑁 𝑘 specifies the cut-off in the expansion.
Evaluating the integral for the correlation functions gives:
𝑁𝑘
∑︁
𝐶 𝜎 (𝑡) ≈ 𝜂 𝜎,𝑙 𝑒−𝛾𝜎,𝑙 𝑡
𝑙=0
where:
⎧ 𝑎𝑝𝑝𝑟𝑜𝑥
⎨ Γ𝑊
2 𝑓𝐹 (𝑖𝛽𝑊 ) 𝑙 = 0
𝜂𝜎,𝑙 = −𝑖 · 𝑘𝑙 · Γ𝑊 2
𝑙 ̸= 0
𝛽 𝜖2
− 𝛽𝑙2 +𝑊 2
⎩
{︃
𝑊 − 𝜎𝑖𝜇 𝑙=0
𝛾𝜎,𝑙 = 𝜖𝑙
𝛽 − 𝜎𝑖𝜇 𝑙 ̸= 0
and 𝛽 = 1
𝑇 .
And now we calculate the same numbers in Python:
# Imports
from numpy.linalg import eigvalsh
def kappa_epsilon(Nk):
""" Calculate kappa and epsilon coefficients. """
eta_list = [
0.5 * Nk * (2 * (Nk + 1) - 1) * (
np.prod([chi[k]**2 - eps[j]**2 for k in range(Nk - 1)]) /
np.prod([
eps[k]**2 - eps[j]**2 + deltafun(j, k) for k in range(Nk)
])
)
for j in range(Nk)
]
# Padé expansion:
bath_L = FermionicBath(Q, ck_plus_L, vk_plus_L, ck_minus_L, vk_minus_L)
bath_R = FermionicBath(Q, ck_plus_R, vk_plus_R, ck_minus_R, vk_minus_R)
The FermionicBath can be used with the HEOMSolver in exactly the same way as the baths we constructed
previously using the built-in Lorentzian bath expansions.
The current HEOM implementation in QuTiP is the latest in a succession of HEOM implementations by various
contributors:
HSolverDL
The original HEOM solver was implemented by Neill Lambert, Anubhav Vardhan, and Alexander Pitchford. In
QuTiP 4.7 it was still available as qutip.solve.nonmarkov.dlheom_solver.HSolverDL but the legacy im-
plementation was removed in QuTiP 5.
It only directly provided support for the Drude-Lorentz bath although there was the possibility of sub-classing the
solver to implement other baths.
A compatible interface using the current implementation is still available under the same name in qutip.solver.
heom.HSolverDL.
BoFiN-HEOM
BoFiN-HEOM (the bosonic and fermionic HEOM solver) was a much more flexible re-write of the original QuTiP
HSolverDL that added support for both bosonic and fermionic baths and for baths to be specified directly via their
correlation function expansion coefficients. Its authors were Neill Lambert, Tarun Raheja, Shahnawaz Ahmed, and
Alexander Pitchford.
BoFiN was written outside of QuTiP and is can still be found in its original repository at https://github.com/tehruhn/
bofin.
The construction of the right-hand side matrix for BoFiN was slow, so BoFiN-fast, a hybrid C++ and Python
implementation, was written that performed the right-hand side construction in C++. It was otherwise identical to
the pure Python version. BoFiN-fast can be found at https://github.com/tehruhn/bofin_fast.
BoFiN also came with an extensive set of example notebooks that are available at https://github.com/tehruhn/bofin/
tree/main/examples.
Current implementation
The current implementation is a rewrite of BoFiN in pure Python. It’s right-hand side construction has similar
speed to BoFiN-fast, but is written in pure Python. Built-in implementations of a variety of different baths are
provided, and a single solver is used for both fermionic and bosonic baths. Multiple baths of either the same kind,
or a mixture of fermionic and bosonic baths, may be specified in a single problem, and there is good support for
working with the auxiliary density operator (ADO) state and extracting information from it.
The code was written by Neill Lambert and Simon Cross.
3.7.5 References
3.8.1 Introduction
For time-independent open quantum systems with decay rates larger than the corresponding excitation rates, the
system will tend toward a steady state as 𝑡 → ∞ that satisfies the equation
𝑑ˆ
𝜌𝑠𝑠
= ℒˆ
𝜌𝑠𝑠 = 0.
𝑑𝑡
Although the requirement for time-independence seems quite resitrictive, one can often employ a transformation
to the interaction picture that yields a time-independent Hamiltonian. For many these systems, solving for the
asymptotic density matrix 𝜌ˆ𝑠𝑠 can be achieved using direct or iterative solution methods faster than using master
equation or Monte Carlo simulations. Although the steady state equation has a simple mathematical form, the
properties of the Liouvillian operator are such that the solutions to this equation are anything but straightforward
to find.
In QuTiP, the steady-state solution for a system Hamiltonian or Liouvillian is given by steadystate. This function
implements a number of different methods for finding the steady state, each with their own pros and cons, where
the method used can be chosen using the method keyword argument.
The function steadystate can take either a Hamiltonian and a list of collapse operators as input, generating
internally the corresponding Liouvillian super operator in Lindblad form, or alternatively, a Liouvillian passed by
the user.
Both the "direct" and "power" method need to solve a linear equation system. To do so, there are multiple
solvers available: ``
QuTiP can take advantage of the Intel Pardiso LU solver in the Intel Math Kernel library that comes with the
Anacoda (2.5+) and Intel Python distributions. This gives a substantial increase in performance compared with the
standard SuperLU method used by SciPy. To verify that QuTiP can find the necessary libraries, one can check for
INTEL MKL Ext: True in the QuTiP about box (about).
Solving for the steady state solution to the Lindblad master equation for a general system with steadystate can
be accomplished using:
where H is a quantum object representing the system Hamiltonian, and c_ops is a list of quantum objects for the
system collapse operators. The output, labelled as rho_ss, is the steady-state solution for the systems. If no other
keywords are passed to the solver, the default ‘direct’ method is used with numpy.linalg.solve, generating a
solution that is exact to machine precision at the expense of a large memory requirement. However Liouvillians
are often quite sparse and using a sparse solver may be preferred:
where method='power' indicates that we are using the inverse-power solution method, and solver="spsolve"
indicate to use the sparse solver.
Sparse solvers may still use quite a large amount of memory when they factorize the matrix since the Liouvillian
usually has a large bandwidth. To address this, steadystate allows one to use the bandwidth minimization
algorithms listed in Additional Solver Arguments. For example:
where L is the Louvillian. All of the additional arguments can also be used in this case.
The following additional solver arguments are available for the steady-state solver:
A simple example of a system that reaches a steady state is a harmonic oscillator coupled to a thermal environment.
Below we consider a harmonic oscillator, initially in the |10⟩ number state, and weakly coupled to a thermal
environment characterized by an average particle expectation value of ⟨𝑛⟩ = 2. We calculate the evolution via
master equation and Monte Carlo methods, and see that they converge to the steady-state solution. Here we choose
to perform only a few Monte Carlo trajectories so we can distinguish this evolution from the master-equation
solution.
import numpy as np
import matplotlib.pyplot as plt
import qutip
# Define paramters
N = 20 # number of basis states to consider
a = qutip.destroy(N)
H = a.dag() * a
psi0 = qutip.basis(N, 10) # initial state
kappa = 0.1 # coupling to oscillator
# collapse operators
c_op_list = []
n_th_a = 2 # temperature with average of 2 excitations
rate = kappa * (1 + n_th_a)
if rate > 0.0:
c_op_list.append(np.sqrt(rate) * a) # decay operators
rate = kappa * n_th_a
if rate > 0.0:
c_op_list.append(np.sqrt(rate) * a.dag()) # excitation operators
0
0 10 20 30 40 50
Time
The Permutational Invariant Quantum Solver (PIQS) is a QuTiP module that allows to study the dynamics of an
open quantum system consisting of an ensemble of identical qubits that can dissipate through local and collective
baths according to a Lindblad master equation.
The Liouvillian of an ensemble of 𝑁 qubits, or two-level systems (TLSs), 𝒟𝑇 𝐿𝑆 (𝜌), can be built using only poly-
nomial – instead of exponential – resources. This has many applications for the study of realistic quantum optics
models of many TLSs and in general as a tool in cavity QED.
Consider a system evolving according to the equation
𝑖 𝛾CE 𝛾CD 𝛾CP
𝜌˙ = 𝒟TLS (𝜌) = − [𝐻, 𝜌] + ℒ𝐽− [𝜌] + ℒ𝐽𝑧 [𝜌] + ℒ𝐽+ [𝜌]
ℏ 2 2 2
𝑁 (︁
∑︁ 𝛾E 𝛾D 𝛾P )︁
+ ℒ𝐽−,𝑛 [𝜌] + ℒ𝐽𝑧,𝑛 [𝜌] + ℒ𝐽+,𝑛 [𝜌]
𝑛=1
2 2 2
∑︀ are SU(2) Pauli spin operators, with 𝛼 = 𝑥, 𝑦, 𝑧 and 𝐽±,𝑛 = 𝜎±,𝑛 . The collective spin
where 𝐽𝛼,𝑛 = 12 𝜎𝛼,𝑛
operators are 𝐽𝛼 = 𝑛 𝐽𝛼,𝑛 . The Lindblad super-operators are ℒ𝐴 = 2𝐴𝜌𝐴† − 𝐴† 𝐴𝜌 − 𝜌𝐴† 𝐴.
The inclusion of local processes in the dynamics lead to using a Liouvillian space of dimension 4𝑁 . By exploiting
the permutational invariance of identical particles [2-8], the Liouvillian 𝒟TLS (𝜌) can be built as a block-diagonal
matrix in the basis of Dicke states |𝑗, 𝑚⟩.
The system under study is defined by creating an object of the Dicke class, e.g. simply named system, whose
first attribute is
• system.N, the number of TLSs of the system 𝑁 .
The rates for collective and local processes are simply defined as
• collective_emission defines 𝛾CE , collective (superradiant) emission
• collective_dephasing defines 𝛾CD , collective dephasing
• collective_pumping defines 𝛾CP , collective pumping.
• emission defines 𝛾E , incoherent emission (losses)
• dephasing defines 𝛾D , local dephasing
• pumping defines 𝛾P , incoherent pumping.
Then the system.lindbladian() creates the total TLS Lindbladian superoperator matrix. Similarly, system.
hamiltonian defines the TLS hamiltonian of the system 𝐻TLS .
The system’s Liouvillian can be built using system.liouvillian(). The properties of a Piqs object can be
visualized by simply calling system. We give two basic examples on the use of PIQS. In the first example the
incoherent emission of N driven TLSs is considered.
For more example of use, see the “Permutational Invariant Lindblad Dynamics” section in the tutorials section of
the website, https://qutip.org/tutorials.html.
Note that the mathematical object representing the density matrix of the full system that is manipulated (or obtained
from steadystate) in the Dicke-basis formalism used here is a representative of the density matrix. This represen-
tative object is of linear size N^2, whereas the full density matrix is defined over a 2^N Hilbert space. In order to
calculate nonlinear functions of such density matrix, such as the Von Neumann entropy or the purity, it is necessary
to take into account the degeneracy of each block of such block-diagonal density matrix. Note that as long as one
calculates expected values of operators, being Tr[A*rho] a linear function of rho, the representative density matrix
give straightforwardly the correct result. When a nonlinear function of the density matrix needs to be calculated,
one needs to weigh each degenerate block correctly; this is taken care by the dicke_function_trace in piqs, and
the user can use it to define general nonlinear functions that can be described as the trace of a Taylor expandable
function. Two nonlinear functions that use dicke_function_trace and are already implemented are purity_dicke, to
calculate the purity of a density matrix in the Dicke basis, and entropy_vn_dicke, which can be used to calculate
the Von Neumann entropy.
More functions relative to the qutip.piqs module can be found at API documentation. Attributes to the piqs.
Dicke and piqs.Pim class can also be found there.
With the QuTiP time-evolution functions (for example mesolve and mcsolve), a state vector or density matrix can
be evolved from an initial state at 𝑡0 to an arbitrary time 𝑡, 𝜌(𝑡) = 𝑉 (𝑡, 𝑡0 ) {𝜌(𝑡0 )}, where 𝑉 (𝑡, 𝑡0 ) is the propagator
defined by the equation of motion. The resulting density matrix can then be used to evaluate the expectation values
of arbitrary combinations of same-time operators.
To calculate two-time correlation functions on the form ⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩, we can use the quantum regression theo-
rem (see, e.g., [Gar03]) to write
We therefore first calculate 𝜌(𝑡) = 𝑉 (𝑡, 0) {𝜌(0)} using one of the QuTiP evolution solvers with 𝜌(0) as initial
state, and then again use the same solver to calculate 𝑉 (𝑡 + 𝜏, 𝑡) {𝐵𝜌(𝑡)} using 𝐵𝜌(𝑡) as initial state.
Note that if the initial state is the steady state, then 𝜌(𝑡) = 𝑉 (𝑡, 0) {𝜌ss } = 𝜌ss and
The most common use-case is to calculate the two time correlation function ⟨𝐴(𝜏 )𝐵(0)⟩. correlation_2op_1t
performs this task with sensible default values, but only allows using the mesolve solver. From QuTiP 5.0 we
added correlation_3op. This function can also calculate correlation functions with two or three operators and
with one or two times. Most importantly, this function accepts alternative solvers such as brmesolve.
The following code demonstrates how to calculate the ⟨𝑥(𝑡)𝑥(0)⟩ correlation for a leaky cavity with three different
relaxation rates.
times = np.linspace(0,10.0,200)
a = destroy(10)
x = a.dag() + a
H = a.dag() * a
plt.figure()
plt.plot(times, np.real(corr1))
plt.plot(times, np.real(corr2))
plt.plot(times, np.real(corr3))
plt.legend(['0.5','1.0','2.0'])
plt.xlabel(r'Time $t$')
plt.ylabel(r'Correlation $\left<x(t)x(0)\right>$')
plt.show()
1.0 0.5
1.0
0.8 2.0
0.6
Correlation x(t)x(0)
0.4
0.2
0.0
0.2
0.4
0 2 4 6 8 10
Time t
Given a correlation function ⟨𝐴(𝜏 )𝐵(0)⟩ we can define the corresponding power spectrum as
∫︁ ∞
𝑆(𝜔) = ⟨𝐴(𝜏 )𝐵(0)⟩ 𝑒−𝑖𝜔𝜏 𝑑𝜏.
−∞
In QuTiP, we can calculate 𝑆(𝜔) using either spectrum, which first calculates the correlation function using one of
the time-dependent solvers and then performs the Fourier transform semi-analytically, or we can use the function
spectrum_correlation_fft to numerically calculate the Fourier transform of a given correlation data using
FFT.
The following example demonstrates how these two functions can be used to obtain the emission power spectrum.
import numpy as np
from matplotlib import pyplot
import qutip
# Jaynes-Cummings Hamiltonian
a = qutip.tensor(qutip.destroy(N), qutip.qeye(2))
sm = qutip.tensor(qutip.qeye(N), qutip.destroy(2))
H = wc*a.dag()*a + wa*sm.dag()*sm + g*(a.dag()*sm + a*sm.dag())
(continues on next page)
# collapse operators
n_th = 0.25
c_ops = [
np.sqrt(kappa * (1 + n_th)) * a,
np.sqrt(kappa * n_th) * a.dag(),
np.sqrt(gamma) * sm,
]
# calculate the correlation function using the mesolve solver, and then fft to
# obtain the spectrum. Here we need to make sure to evaluate the correlation
# function for a sufficient long time and sufficiently high sampling rate so
# that the discrete Fourier transform (FFT) captures all the features in the
# resulting spectrum.
tlist = np.linspace(0, 100, 5000)
corr = qutip.correlation_2op_1t(H, None, tlist, c_ops, a.dag(), a)
wlist1, spec1 = qutip.spectrum_correlation_fft(tlist, corr)
# calculate the power spectrum using spectrum, which internally uses essolve
# to solve for the dynamics (by default)
wlist2 = np.linspace(0.25, 1.75, 200) * 2 * np.pi
spec2 = qutip.spectrum(H, wlist2, c_ops, a.dag(), a)
0.4
Power spectrum
0.3
0.2
0.1
0.0
0.4 0.6 0.8 1.0 1.2 1.4 1.6
Frequency
More generally, we can also calculate correlation functions of the kind ⟨𝐴(𝑡1 + 𝑡2 )𝐵(𝑡1 )⟩, i.e., the correlation
function of a system that is not in its steady state. In QuTiP, we can evaluate such correlation functions using the
function correlation_2op_2t. The default behavior of this function is to return a matrix with the correlations
as a function of the two time coordinates (𝑡1 and 𝑡2 ).
import numpy as np
import matplotlib.pyplot as plt
import qutip
plt.pcolor(np.real(corr))
plt.xlabel(r'Time $t_2$')
plt.ylabel(r'Time $t_1$')
plt.title(r'Correlation $\left<x(t)x(0)\right>$')
plt.show()
Correlation x(t)x(0)
200
175
150
125
Time t1
100
75
50
25
0
0 25 50 75 100 125 150 175 200
Time t2
However, in some cases we might be interested in the correlation functions on the form ⟨𝐴(𝑡1 + 𝑡2 )𝐵(𝑡1 )⟩, but only
as a function of time coordinate 𝑡2 . In this case we can also use the correlation_2op_2t function, if we pass the
density matrix at time 𝑡1 as second argument, and None as third argument. The correlation_2op_2t function
then returns a vector with the correlation values corresponding to the times in taulist (the fourth argument).
This example demonstrates how to calculate a correlation function on the form ⟨𝐴(𝜏 )𝐵(0)⟩ for a non-steady initial
state. Consider an oscillator that is interacting with a thermal environment. If the oscillator initially is in a coherent
state, it will gradually decay to a thermal (incoherent) state. The amount of coherence can be quantified using the
⟨𝑎† (𝜏 )𝑎(0)⟩
first-order optical coherence function 𝑔 (1) (𝜏 ) = √ † †
. For a coherent state |𝑔 (1) (𝜏 )| = 1, and for
⟨𝑎 (𝜏 )𝑎(𝜏 )⟩⟨𝑎 (0)𝑎(0)⟩
a completely incoherent (thermal) state 𝑔 (1)
(𝜏 ) = 0. The following code calculates and plots 𝑔 (1) (𝜏 ) as a function
of 𝜏 .
import numpy as np
import matplotlib.pyplot as plt
import qutip
N = 15
taus = np.linspace(0,10.0,200)
a = qutip.destroy(N)
H = 2 * np.pi * a.dag() * a
# collapse operator
G1 = 0.75
n_th = 2.00 # bath temperature in terms of excitation number
c_ops = [np.sqrt(G1 * (1 + n_th)) * a, np.sqrt(G1 * n_th) * a.dag()]
1
0 2 4 6 8 10
For convenience, the steps for calculating the first-order coherence function have been collected in the function
coherence_function_g1.
For a coherent state 𝑔 (2) (𝜏 ) = 1, for a thermal state 𝑔 (2) (𝜏 = 0) = 2 and it decreases as a function of time (bunched
photons, they tend to appear together), and for a Fock state with 𝑛 photons 𝑔 (2) (𝜏 = 0) = 𝑛(𝑛 − 1)/𝑛2 < 1 and
it increases with time (anti-bunched photons, more likely to arrive separated in time).
To calculate this type of correlation function with QuTiP, we can use correlation_3op_1t, which computes
a correlation function on the form ⟨𝐴(0)𝐵(𝜏 )𝐶(0)⟩ (three operators, one delay-time vector). We first have to
combine the central two operators into one single one as they are evaluated at the same time, e.g. here we do
𝑎† (𝜏 )𝑎(𝜏 ) = (𝑎† 𝑎)(𝜏 ).
The following code calculates and plots 𝑔 (2) (𝜏 ) as a function of 𝜏 for a coherent, thermal and Fock state.
import numpy as np
import matplotlib.pyplot as plt
import qutip
N = 25
taus = np.linspace(0, 25.0, 200)
a = qutip.destroy(N)
H = 2 * np.pi * a.dag() * a
kappa = 0.25
n_th = 2.0 # bath temperature in terms of excitation number
c_ops = [np.sqrt(kappa * (1 + n_th)) * a, np.sqrt(kappa * n_th) * a.dag()]
states = [
{'state': qutip.coherent_dm(N, np.sqrt(2)), 'label': "coherent state"},
{'state': qutip.thermal_dm(N, 2), 'label': "thermal state"},
{'state': qutip.fock_dm(N, 2), 'label': "Fock state"},
]
fig, ax = plt.subplots(1, 1)
ax.legend(loc=0)
ax.set_xlabel(r'$\tau$')
ax.set_ylabel(r'$g^{(2)}(\tau)$')
plt.show()
1.6
1.4
g(2)( )
1.2
1.0
0.8
0.6
0 5 10 15 20 25
For convenience, the steps for calculating the second-order coherence function have been collected in the function
coherence_function_g2.
3.11.1 Introduction
When studying the dynamics of a two-level system, it is often convenient to visualize the state of the system by
plotting the state-vector or density matrix on the Bloch sphere. In QuTiP, there is a class to allow for easy creation
and manipulation of data sets, both vectors and data points, on the Bloch sphere.
b = qutip.Bloch()
which will load an instance of the Bloch class. Before getting into the details of these objects, we can simply plot
the blank Bloch sphere associated with these instances via:
b.make_sphere()
|0
y
x
|1
In addition to the show command, see the API documentation for Bloch for a full list of other available functions.
As an example, we can add a single data point:
|0
y
x
|1
b.fig.clf()
vec = [0, 1, 0]
b.add_vectors(vec)
b.render()
|0
y
x
|1
up = qutip.basis(2, 0)
b.add_states(up)
b.render()
|0
y
x
|1
Notice that when we add more than a single vector (or data point), a different color will automatically be applied
to the later data set (mod 4). In total, the code for constructing our Bloch sphere with one vector, one state, and a
single data point is:
b = qutip.Bloch()
|0
y
x
|1
b.clear()
b.render()
|0
y
x
|1
Now on the same Bloch sphere, we can plot the three states associated with the x, y, and z directions:
b.add_states([x, y, z])
b.render()
|0
y
x
|1
b.clear()
vec = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
b.add_vectors(vec)
b.render()
|0
y
x
|1
Adding multiple points to the Bloch sphere works slightly differently than adding multiple states or vectors. For
example, lets add a set of 20 points around the equator (after calling clear()):
b.clear()
|0
y
x
|1
Notice that, in contrast to states or vectors, each point remains the same color as the initial point. This is because
adding multiple data points using the add_points function is interpreted, by default, to correspond to a single
data point (single qubit state) plotted at different times. This is very useful when visualizing the dynamics of a
qubit. An example of this is given in the example . If we want to plot additional qubit states we can call additional
add_points functions:
xz = np.zeros(20)
yz = np.sin(th)
zz = np.cos(th)
b.add_points([xz, yz, zz])
b.render()
|0
y
x
|1
The color and shape of the data points is varied automatically by the Bloch class. Notice how the color and point
markers change for each set of data. Again, we have had to call add_points twice because adding more than one
set of multiple data points is not supported by the add_points function.
What if we want to vary the color of our points. We can tell the qutip.bloch.Bloch class to vary the color
of each point according to the colors listed in the b.point_color list (see Configuring the Bloch sphere below).
Again after clear():
b.clear()
xp = np.cos(th)
yp = np.sin(th)
zp = np.zeros(20)
pnts = [xp, yp, zp]
b.add_points(pnts, 'm') # <-- add a 'm' string to signify 'multi' colored points
b.render()
|0
y
x
|1
Now, the data points cycle through a variety of predefined colors. Now lets add another set of points, but this time
we want the set to be a single color, representing say a qubit going from the |up⟩ state to the |down⟩ state in the
y-z plane:
xz = np.zeros(20)
yz = np.sin(th)
zz = np.cos(th)
|0
y
x
|1
A more slick way of using this ‘multi’ color feature is also given in the example, where we set the color of the
markers as a function of time.
At the end of the last section we saw that the colors and marker shapes of the data plotted on the Bloch sphere are
automatically varied according to the number of points and vectors added. But what if you want a different choice
of color, or you want your sphere to be purple with different axes labels? Well then you are in luck as the Bloch
class has 22 attributes which one can control. Assuming b=Bloch():
>>> b = qutip.Bloch()
>>> print(b)
Bloch data:
-----------
Number of points: 0
Number of vectors: 0
The Bloch class was designed from the outset to generate animations. To animate a set of vectors or data points
the basic idea is: plot the data at time t1, save the sphere, clear the sphere, plot data at t2,. . . The Bloch sphere
will automatically number the output file based on how many times the object has been saved (this is stored in
b.savenum). The easiest way to animate data on the Bloch sphere is to use the save() method and generate a
series of images to convert into an animation. However, as of Matplotlib version 1.1, creating animations is built-
in. We will demonstrate both methods by looking at the decay of a qubit on the bloch sphere.
The code for calculating the expectation values for the Pauli spin operators of a qubit decay is given below. This
code is common to both animation examples.
import numpy as np
import qutip
An example of generating images for generating an animation outside of Python is given below:
import numpy as np
b = qutip.Bloch()
b.vector_color = ['r']
b.view = [-40, 30]
for i in range(len(sx)):
b.clear()
b.add_vectors([np.sin(theta), 0, np.cos(theta)])
b.add_points([sx[:i+1], sy[:i+1], sz[:i+1]])
b.save(dirc='temp') # saving images to temp directory in current working␣
˓→directory
Important: Generating animations directly from Matplotlib requires installing either MEncoder or FFmpeg.
While either choice works on linux, it is best to choose FFmpeg when running on the Mac. If using macports just
do: sudo port install ffmpeg.
The code to directly generate an mp4 movie of the Qubit decay is as follows
fig = pyplot.figure()
ax = fig.add_subplot(azim=-40, elev=30, projection="3d")
sphere = qutip.Bloch(axes=ax)
def animate(i):
sphere.clear()
sphere.add_vectors([np.sin(theta), 0, np.cos(theta)], ["r"])
sphere.add_points([sx[:i+1], sy[:i+1], sz[:i+1]])
sphere.make_sphere()
return ax
ani.save('bloch_sphere.mp4', fps=20)
Visualization is often an important complement to a simulation of a quantum mechanical system. The first method
of visualization that come to mind might be to plot the expectation values of a few selected operators. But on top
of that, it can often be instructive to visualize for example the state vectors or density matices that describe the
state of the system, or how the state is transformed as a function of time (see process tomography below). In this
section we demonstrate how QuTiP and matplotlib can be used to perform a few types of visualizations that often
can provide additional understanding of quantum system.
In quantum mechanics probability distributions plays an important role, and as in statistics, the expectation values
computed from a probability distribution does not reveal the full story. For example, consider an quantum harmonic
oscillator mode with Hamiltonian 𝐻 = ℏ𝜔𝑎† 𝑎, which is in a state described by its density matrix 𝜌, and which on
average is occupied by two photons, Tr[𝜌𝑎† 𝑎] = 2. Given this information we cannot say whether the oscillator is
in a Fock state, a thermal state, a coherent state, etc. By visualizing the photon distribution in the Fock state basis
important clues about the underlying state can be obtained.
One convenient way to visualize a probability distribution is to use histograms. Consider the following histogram
visualization of the number-basis probability distribution, which can be obtained from the diagonal of the density
matrix, for a few possible oscillator states with on average occupation of two photons.
First we generate the density matrices for the coherent, thermal and fock states.
N = 20
rho_thermal = thermal_dm(N, 2)
rho_fock = fock_dm(N, 2)
plt.show()
All these states correspond to an average of two photons, but by visualizing the photon distribution in Fock basis
the differences between these states are easily appreciated.
One frequently need to visualize the Fock-distribution in the way described above, so QuTiP provides a convenience
function for doing this, see qutip.visualization.plot_fock_distribution, and the following example:
fig.tight_layout()
plt.show()
Occupation probability
Occupation probability
The probability distribution in the number (Fock) basis only describes the occupation probabilities for a discrete set
of states. A more complete phase-space probability-distribution-like function for harmonic modes are the Wigner
and Husumi Q-functions, which are full descriptions of the quantum state (equivalent to the density matrix). These
are called quasi-distribution functions because unlike real probability distribution functions they can for example be
negative. In addition to being more complete descriptions of a state (compared to only the occupation probabilities
plotted above), these distributions are also great for demonstrating if a quantum state is quantum mechanical, since
for example a negative Wigner function is a definite indicator that a state is distinctly nonclassical.
Wigner function
In QuTiP, the Wigner function for a harmonic mode can be calculated with the function qutip.wigner.wigner.
It takes a ket or a density matrix as input, together with arrays that define the ranges of the phase-space coordinates
(in the x-y plane). In the following example the Wigner functions are calculated and plotted for the same three
states as in the previous section.
xvec = np.linspace(-5,5,200)
plt.show()
2 2 2
0 0 0
2 2 2
4 4 4
4 2 0 2 4 4 2 0 2 4 4 2 0 2 4
The main objective when plotting a Wigner function is to demonstrate that the underlying state is nonclassical, as
indicated by negative values in the Wigner function. Therefore, making these negative values stand out in a figure
is helpful for both analysis and publication purposes. Unfortunately, all of the color schemes used in Matplotlib
(or any other plotting software) are linear colormaps where small negative values tend to be near the same color as
the zero values, and are thus hidden. To fix this dilemma, QuTiP includes a nonlinear colormap function qutip.
matplotlib_utilities.wigner_cmap that colors all negative values differently than positive or zero values.
Below is a demonstration of how to use this function in your Wigner figures:
axes[0].set_title("Standard Colormap");
axes[1].set_title("Wigner Colormap");
fig.tight_layout()
plt.show()
Husimi Q-function
The Husimi Q function is, like the Wigner function, a quasiprobability distribution for harmonic modes. It is
defined as
1
𝑄(𝛼) = ⟨𝛼|𝜌|𝛼⟩
𝜋
where |𝛼⟩ is a coherent state and 𝛼 = 𝑥 + 𝑖𝑦. In QuTiP, the Husimi Q function can be computed given a state ket
or density matrix using the function qfunc, as demonstrated below.
2 2 2
0 0 0
2 2 2
4 4 4
4 2 0 2 4 4 2 0 2 4 4 2 0 2 4
If you need to calculate the Q function for many states with the same phase-space coordinates, it is more efficient
to use the QFunc class. This stores various intermediary results to achieve an order-of-magnitude improvement
compared to calling qfunc in a loop.
xs = np.linspace(-1, 1, 101)
qfunc_calculator = qutip.QFunc(xs, xs)
q_state1 = qfunc_calculator(qutip.rand_dm(5))
q_state2 = qfunc_calculator(qutip.rand_ket(100))
Sometimes, it may also be useful to directly visualizing the underlying matrix representation of an operator. The
density matrix, for example, is an operator whose elements can give insights about the state it represents, but one
might also be interesting in plotting the matrix of an Hamiltonian to inspect the structure and relative importance
of various elements.
QuTiP offers a few functions for quickly visualizing matrix data in the form of histograms, qutip.
visualization.matrix_histogram and as Hinton diagram of weighted squares, qutip.visualization.
hinton. These functions takes a Qobj as first argument, and optional arguments to, for example, set the axis
labels and figure title (see the function’s documentation for details).
For example, to illustrate the use of qutip.visualization.matrix_histogram, let’s visualize of the Jaynes-
Cummings Hamiltonian:
N = 5
a = tensor(destroy(N), qeye(2))
b = tensor(qeye(N), destroy(2))
sx = tensor(qeye(N), sigmax())
# visualize H
xlabels = []
ax.view_init(azim=-55, elev=45)
plt.show()
3.5 3
2.5
1.5
0.5 2
0.5
real
4d
4u 0
3d
0u0d 3u
1u1d 2d
2u
2u2d 1d 1
3u3d 1u
4u4d 0d
0u
Similarly, we can use the function qutip.visualization.hinton, which is used below to visualize the corre-
sponding steadystate density matrix:
hinton(rho_ss)
plt.show()
Quantum process tomography (QPT) is a useful technique for characterizing experimental implementations of
quantum gates involving a small number of qubits. It can also be a useful theoretical tool that can give insight in
how a process transforms states, and it can be used for example to study how noise or other imperfections deteriorate
a gate. Whereas a fidelity or distance measure can give a single number that indicates how far from ideal a gate
is, a quantum process tomography analysis can give detailed information about exactly what kind of errors various
imperfections introduce.
The idea is to construct a transformation matrix for a quantum process (for example a quantum gate) that describes
how the density matrix of a system is transformed by the process. We can then decompose the transformation in
some operator basis that represent well-defined and easily interpreted transformations of the input states.
To see how this works (see e.g. [Moh08] for more details), consider a process that is described by quantum map
𝜖(𝜌in ) = 𝜌out , which can be written
2
𝑁
𝐴𝑖 𝜌in 𝐴†𝑖 , (3.42)
∑︁
𝜖(𝜌in ) = 𝜌out =
𝑖
where 𝑁 is the number of states of the system (that is, 𝜌 is represented by an [𝑁 × 𝑁 ] matrix). Given an orthogonal
2 †
operator basis of our choice {𝐵𝑖 }𝑁
𝑖 , which satisfies Tr[𝐵𝑖 𝐵𝑗 ] = 𝑁 𝛿𝑖𝑗 , we can write the map as
∑︁
𝜖(𝜌in ) = 𝜌out = 𝜒𝑚𝑛 𝐵𝑚 𝜌in 𝐵𝑛† . (3.43)
𝑚𝑛
where 𝜒𝑚𝑛 = 𝑖𝑗 𝑏𝑖𝑚 𝑏*𝑗𝑛 and 𝐴𝑖 = 𝑚 𝑏𝑖𝑚 𝐵𝑚 . Here, matrix 𝜒 is the transformation matrix we are after, since
∑︀ ∑︀
𝜖(˜
𝜌in ) = 𝑈 𝜌˜in = 𝜌˜out
where 𝜌˜ is the vector representation of the density matrix 𝜌. If we write Eq. (3.43) in superoperator form as well
we obtain
∑︁
𝜌˜out = 𝜒𝑚𝑛 𝐵˜𝑚 𝐵˜𝑛† 𝜌˜in = 𝑈 𝜌˜in .
𝑚𝑛
so we can identify
∑︁
𝑈= ˜𝑚 𝐵
𝜒𝑚𝑛 𝐵 ˜† .
𝑛
𝑚𝑛
Now this is a linear equation systems for the 𝑁 2 × 𝑁 2 elements in 𝜒. We can solve it by writing 𝜒 and the
superoperator propagator as [𝑁 4 ] vectors, and likewise write the superoperator product 𝐵 ˜𝑛† as a [𝑁 4 × 𝑁 4 ]
˜𝑚 𝐵
matrix 𝑀 :
4
𝑁
∑︁
𝑈𝐼 = 𝑀𝐼𝐽 𝜒𝐽
𝐽
𝜒 = 𝑀 −1 𝑈.
Note that to obtain 𝜒 with this method we have to construct a matrix 𝑀 with a size that is the square of the size
of the superoperator for the system. Obviously, this scales very badly with increasing system size, but this method
can still be a very useful for small systems (such as system comprised of a small number of coupled qubits).
Implementation in QuTiP
In QuTiP, the procedure described above is implemented in the function qutip.tomography.qpt, which returns
the 𝜒 matrix given a density matrix propagator. To illustrate how to use this function, let’s consider the SWAP gate
for two qubits. In QuTiP the function swap generates the unitary transformation for the state kets:
U_psi = swap()
To be able to use this unitary transformation matrix as input to the function qutip.tomography.qpt, we first
need to convert it to a transformation matrix for the corresponding density matrix:
Next, we construct a list of operators that define the basis {𝐵𝑖 } in the form of a list of operators for each composite
system. At the same time, we also construct a list of corresponding labels that will be used when plotting the 𝜒
matrix.
We are now ready to compute 𝜒 using qutip.tomography.qpt, and to plot it using qutip.tomography.
qpt_plot_combined.
plt.show()
SWAP
/2
arg
zxzyzz /2
yzzi
yy
ii ix iy yiyx
xz
iz xixx xxxy
xyxzyi xi
yxyyyz
zi ixiyiz
zxzyzz ii
For a slightly more advanced example, where the density matrix propagator is calculated from the dynamics of a
system defined by its Hamiltonian and collapse operators using the function propagator, see notebook “Time-
dependent master equation: Landau-Zener transitions” on the tutorials section on the QuTiP web site.
With time-consuming calculations it is often necessary to store the results to files on disk, so it can be post-processed
and archived. In QuTiP there are two facilities for storing data: Quantum objects can be stored to files and later
read back as python pickles, and numerical data (vectors and matrices) can be exported as plain text files in for
example CSV (comma-separated values), TSV (tab-separated values), etc. The former method is preferred when
further calculations will be performed with the data, and the latter when the calculations are completed and data is
to be imported into a post-processing tool (e.g. for generating figures).
To store and load arbitrary QuTiP related objects (Qobj, Result, etc.) there are two functions: qutip.fileio.
qsave and qutip.fileio.qload. The function qutip.fileio.qsave takes an arbitrary object as first param-
eter and an optional filename as second parameter (default filename is qutip_data.qu). The filename extension
is always .qu. The function qutip.fileio.qload takes a mandatory filename as first argument and loads and
returns the objects in the file.
To illustrate how these functions can be used, consider a simple calculation of the steadystate of the harmonic
oscillator
The steadystate density matrix rho_ss is an instance of Qobj. It can be stored to a file steadystate.qu using
The nice thing about the qutip.fileio.qsave and qutip.fileio.qload functions is that almost any object
can be stored and load again later on. We can for example store a list of density matrices as returned by mesolve
And it can then be loaded and used again, for example in an other program
The qutip.fileio.qsave and qutip.fileio.qload are great, but the file format used is only understood by
QuTiP (python) programs. When data must be exported to other programs the preferred method is to store the
data in the commonly used plain-text file formats. With the QuTiP functions qutip.fileio.file_data_store
and qutip.fileio.file_data_read we can store and load numpy arrays and matrices to files on disk using a
deliminator-separated value format (for example comma-separated values CSV). Almost any program can handle
this file format.
The qutip.fileio.file_data_store takes two mandatory and three optional arguments:
where filename is the name of the file, data is the data to be written to the file (must be a numpy array), numtype
(optional) is a flag indicating numerical type that can take values complex or real, numformat (optional) specifies
the numerical format that can take the values exp for the format 1.0e1 and decimal for the format 10.0, and sep
(optional) is an arbitrary single-character field separator (usually a tab, space, comma, semicolon, etc.).
A common use for the qutip.fileio.file_data_store function is to store the expectation values of a set of
operators for a sequence of times, e.g., as returned by the mesolve function, which is what the following example
does
>>> np.shape(medata.expect)
(3, 100)
>>> times.shape
(100,)
>>> output_data = np.vstack((times, medata.expect)) # join time and expt data
>>> file_data_store('expect.dat', output_data.T) # Note the .T for transpose!
>>> with open("expect.dat", "r") as f:
... print('\n'.join(f.readlines()[:10]))
# Generated by QuTiP: 100x4 complex matrix in decimal format [',' separated values].
0.0000000000+0.0000000000j,3.2109553666+0.0000000000j,0.3689771549+0.0000000000j,0.
˓→0185002867+0.0000000000j
1.0101010101+0.0000000000j,2.6754598872+0.0000000000j,0.1298251132+0.0000000000j,-0.
˓→3303672956+0.0000000000j
2.0202020202+0.0000000000j,2.2743186810+0.0000000000j,-0.2106241300+0.0000000000j,-0.
˓→2623894277+0.0000000000j
3.0303030303+0.0000000000j,1.9726633457+0.0000000000j,-0.3037311621+0.0000000000j,0.
˓→0397330921+0.0000000000j
4.0404040404+0.0000000000j,1.7435892209+0.0000000000j,-0.1126550232+0.0000000000j,0.
˓→2497182058+0.0000000000j
5.0505050505+0.0000000000j,1.5687324121+0.0000000000j,0.1351622725+0.0000000000j,0.
˓→2018398581+0.0000000000j
6.0606060606+0.0000000000j,1.4348632045+0.0000000000j,0.2143080535+0.0000000000j,-0.
˓→0067820038+0.0000000000j
8.0808080808+0.0000000000j,1.2533244850+0.0000000000j,-0.0771210981+0.0000000000j,-0.
˓→1468923919+0.0000000000j
In this case we didn’t really need to store both the real and imaginary parts, so instead we could use the
numtype="real" option
and if we prefer scientific notation we can request that using the numformat="exp" option
Loading data previously stored using qutip.fileio.file_data_store (or some other software) is a even easier.
Regardless of which deliminator was used, if data was stored as complex or real numbers, if it is in decimal
or exponential form, the data can be loaded using the qutip.fileio.file_data_read, which only takes the
filename as mandatory argument.
input_data = file_data_read('expect.dat')
plt.plot(input_data[:,0], input_data[:,1]); # plot the data
1
0 20 40 60 80 100
(If a particularly obscure choice of deliminator was used it might be necessary to use the optional second argument,
for example sep="_" if _ is the deliminator).
QuTiP includes a collection of random state, unitary and channel generators for simulations, Monte Carlo evalu-
ation, theorem evaluation, and code testing. Each of these objects can be sampled from one of several different
distributions.
For example, a random Hermitian operator can be sampled by calling rand_herm function:
>>> rand_herm(5)
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[-0.25091976+0.j 0. +0.j 0. +0.j
-0.21793701+0.47037633j -0.23212846-0.61607187j]
[ 0. +0.j -0.88383278+0.j 0.836086 -0.23956218j
-0.09464275+0.45370863j -0.15243356+0.65392096j]
[ 0. +0.j 0.836086 +0.23956218j 0.66488528+0.j
-0.26290446+0.64984451j -0.52603038-0.07991553j]
[-0.21793701-0.47037633j -0.09464275-0.45370863j -0.26290446-0.64984451j
-0.13610996+0.j -0.34240902-0.2879303j ]
[-0.23212846+0.61607187j -0.15243356-0.65392096j -0.52603038+0.07991553j
-0.34240902+0.2879303j 0. +0.j ]]
In all cases, these functions can be called with a single parameter 𝑑𝑖𝑚𝑒𝑛𝑠𝑖𝑜𝑛𝑠 that can be the size of the relevant
Hilbert space or the dimensions of a random state, unitary or channel.
>>> rand_super_bcsz(7).dims
[[[7], [7]], [[7], [7]]]
>>> rand_super_bcsz([[2, 3], [2, 3]]).dims
[[[2, 3], [2, 3]], [[2, 3], [2, 3]]]
Several of the random Qobj function in QuTiP support additional parameters as well, namely density and distri-
bution. rand_dm, rand_herm, rand_unitary and rand_ket can be created using multiple method controlled
by distribution. The rand_ket, rand_herm and rand_unitary functions can return quantum objects such that
a fraction of the elements are identically equal to zero. The ratio of nonzero elements is passed as the density
keyword argument. By contrast, rand_super_bcsz take as an argument the rank of the generated object, such that
passing rank=1 returns a random pure state or unitary channel, respectively. Passing rank=None specifies that the
generated object should be full-rank for the given dimension. rand_dm can support density or rank depending on
the chosen distribution.
For example,
Warning: When using the density keyword argument, setting the density too low may result in not enough
diagonal elements to satisfy trace constraints.
It is also possible to generate random Hamiltonian (rand_herm) and densitiy matrices (rand_dm) with a given
eigen spectrum. This is done by passing an array to eigenvalues argument to either function and choosing the
“eigen” distribution. For example,
>>> H
Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[ 0.5 +0.j , 0.228+0.27j, 0. +0.j , 0. +0.j ,-0.228-0.27j],
[ 0.228-0.27j, 1.75 +0.j , 0.456+0.54j, 0. +0.j , 1.25 +0.j ],
[ 0. +0.j , 0.456-0.54j, 3. +0.j , 0. +0.j , 0.456-0.54j],
[ 0. +0.j , 0. +0.j , 0. +0.j , 3. +0.j , 0. +0.j ],
[-0.228+0.27j, 1.25 +0.j , 0.456+0.54j, 0. +0.j , 1.75 +0.j ]]
>>> H.eigenenergies()
array([7.70647994e-17, 1.00000000e+00, 2.00000000e+00, 3.00000000e+00,
4.00000000e+00])
In order to generate a random object with a given spectrum QuTiP applies a series of random complex Jacobi
rotations. This technique requires many steps to build the desired quantum object, and is thus suitable only for
objects with Hilbert dimensionality ≲ 1000.
In many cases, one is interested in generating random quantum objects that correspond to composite systems
generated using the tensor function. Specifying the tensor structure of a quantum object is done passing a list
for the first argument. The resulting quantum objects size will be the product of the elements in the list and the
resulting Qobj dimensions will be [dims, dims]:
Qutip uses numpy random number generator to create random quantum objects. To control the random number, a
seed as an int or numpy.random.SeedSequence or a numpy.random.Generator can be passed to the seed keyword
argument:
The internal storage type of the generated random quantum objects can be set with the dtype keyword.
In this section we show how to modify a few of the internal parameters used by QuTiP. The settings that can be
modified are given in the following table:
The two most important settings are auto_tidyup and auto_tidyup_atol as they control whether the small
elements of a quantum object should be removed, and what number should be considered as the cut-off tolerance.
Modifying these, or any other parameters, is quite simple:
3.16.1 Introduction
Measurement is a fundamental part of the standard formulation of quantum mechanics and is the process by which
classical readings are obtained from a quantum object. Although the interpretation of the procedure is at times
contentious, the procedure itself is mathematically straightforward and is described in many good introductory
texts.
Here we will show you how to perform simple measurement operations on QuTiP objects. The same functions
measure and measurement_statistics can be used to handle both observable-style measurements and projec-
tive style measurements.
First we need to select some states to measure. For now, let us create an up state and a down state:
up = basis(2, 0)
down = basis(2, 1)
which represent spin-1/2 particles with their spin pointing either up or down along the z-axis.
We choose what to measure (in this case) by selecting a measurement operator. For example, we could select
sigmaz which measures the z-component of the spin of a spin-1/2 particle, or sigmax which measures the x-
component:
spin_z = sigmaz()
spin_x = sigmax()
How do we know what these operators measure? The answer lies in the measurement procedure itself:
• A quantum measurement transforms the state being measured by projecting it into one of the eigenvectors
of the measurement operator.
• Which eigenvector to project onto is chosen probabilistically according to the square of the amplitude of the
state in the direction of the eigenvector.
• The value returned by the measurement is the eigenvalue corresponding to the chosen eigenvector.
Note: How to interpret this “random choosing” is the famous “quantum measurement problem”.
The eigenvectors of spin_z are the states with their spin pointing either up or down, so it measures the component
of the spin along the z-axis.
The eigenvectors of spin_x are the states with their spin pointing either left or right, so it measures the component
of the spin along the x-axis.
When we measure our up and down states using the operator spin_z, we always obtain:
because up is the eigenvector of spin_z with eigenvalue 1.0 and down is the eigenvector with eigenvalue -1.0. The
minus signs are just an arbitrary global phase – up and -up represent the same quantum state.
Neither eigenvector has any component in the direction of the other (they are orthogonal), so measure(spin_z, up)
returns the state up 100% percent of the time and measure(spin_z, down) returns the state down 100% of the time.
Note how measure returns a pair of values. The first is the measured value, i.e. an eigenvalue of the operator (e.g.
1.0), and the second is the state of the quantum system after the measurement, i.e. an eigenvector of the operator
(e.g. up).
Now let us consider what happens if we measure the x-component of the spin of up:
measure(up, spin_x)
The up state is not an eigenvector of spin_x. spin_x has two eigenvectors which we will call left and right. The up
state has equal components in the direction of these two vectors, so measurement will select each of them 50% of
the time.
These left and right states are:
When left is chosen, the result of the measurement will be (-1.0, -left).
When right is chosen, the result of measurement with be (1.0, right).
Note: When measure is invoked with the second argument being an observable, it acts as an alias to
measure_observable.
We can also choose what to measure by specifying a list of projection operators. For example, we could select
the projection operators |0⟩ ⟨0| and |1⟩ ⟨1| which measure the state in the |0⟩ , |1⟩ basis. Note that these projection
operators are simply the projectors determined by the eigenstates of the sigmaz operator.
The probabilities and respective output state are calculated for each projection operator.
In this case, the projection operators are conveniently eigenstates corresponding to subspaces of dimension 1.
However, this might not be the case, in which case it is not possible to have unique eigenvalues for each eigenstate.
Suppose we want to measure only the first qubit in a two-qubit system. Consider the two qubit state |0+⟩
state_0 = basis(2, 0)
Now, suppose we want to measure only the first qubit in the computational basis. We can do that by measuring
with the projection operators |0⟩ ⟨0| ⊗ 𝐼 and |1⟩ ⟨1| ⊗ 𝐼.
Now, as in the previous example, we can measure by supplying a list of projection operators and the state.
The output of the measurement is the index of the measurement outcome as well as the output state on the full
Hilbert space of the input state. It is crucial to note that we do not discard the measured qubit after measurement
(as opposed to when measuring on quantum hardware).
Note: When measure is invoked with the second argument being a list of projectors, it acts as an alias to
measure_povm.
The measure function can perform measurements on density matrices too. You can read about these and other
details at measure_povm and measure_observable.
Now you know how to measure quantum states in QuTiP!
You’ve just learned how to perform measurements in QuTiP, but you’ve also learned that measurements are prob-
abilistic. What if instead of just making a single measurement, we want to determine the probability distribution
of a large number of measurements?
One way would be to repeat the measurement many times – and this is what happens in many quantum experiments.
In QuTiP one could simulate this using:
Output:
which measures the x-component of the spin of the up state 1000 times and stores the results in a dictionary.
Afterwards we expect to have seen the result 1.0 (i.e. left) roughly 500 times and the result -1.0 (i.e. right) roughly
500 times, but, of course, the number of each will vary slightly each time we run it.
But what if we want to know the distribution of results precisely? In a physical system, we would have to perform
the measurement many many times, but in QuTiP we can peak at the state itself and determine the probability
distribution of the outcomes exactly in a single line:
>>> eigenvalues
array([-1., 1.])
>>> eigenstates
array([Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[ 0.70710678]
[-0.70710678]],
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.70710678]
[0.70710678]]], dtype=object)
>>> probabilities
[0.5000000000000001, 0.4999999999999999]
The measurement_statistics function then returns three values when called with a single observable:
• eigenvalues is an array of eigenvalues of the measurement operator, i.e. a list of the possible measurement
results. In our example the value is array([-1., -1.]).
• eigenstates is an array of the eigenstates of the measurement operator, i.e. a list of the possible final states
after the measurement is complete. Each element of the array is a Qobj.
• probabilities is a list of the probabilities of each measurement result. In our example the value is [0.5, 0.5]
since the up state has equal probability of being measured to be in the left (-1.0) or right (1.0) eigenstates.
All three lists are in the same order – i.e. the first eigenvalue is eigenvalues[0], its corresponding eigenstate is
eigenstates[0], and its probability is probabilities[0], and so on.
Note: When measurement_statistics is invoked with the second argument being an observable, it acts as an
alias to measurement_statistics_observable.
Similarly, when we want to obtain measurement statistics for projection operators, we can use the measure-
ment_statistics function with the second argument being a list of projectors. Consider again, the state |0+⟩. Sup-
pose, now we want to obtain the measurement outcomes for the second qubit. We must use the projectors specified
earlier by PZ2 which allow us to measure only on the second qubit. Since the second qubit has the state |+⟩, we
get the following result.
print(collapsed_states)
Output:
[Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket
Qobj data =
[[1.]
[0.]
[0.]
[0.]], Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]]]
print(probabilities)
Output:
[0.4999999999999999, 0.4999999999999999]
Note: When measurement_statistics is invoked with the second argument being a list of projectors, it acts
as an alias to measurement_statistics_povm.
The measurement_statistics function can provide statistics for measurements of density matrices
too. You can read about these and other details at measurement_statistics_observable and
measurement_statistics_povm.
Furthermore, the measure_povm and measurement_statistics_povm functions can handle POVM measure-
ments which are more general than projective measurements.
3.17.1 Introduction
In quantum control we look to prepare some specific state, effect some state-to-state transfer, or effect some trans-
formation (or gate) on a quantum system. For a given quantum system there will always be factors that effect the
dynamics that are outside of our control. As examples, the interactions between elements of the system or a mag-
netic field required to trap the system. However, there may be methods of affecting the dynamics in a controlled
way, such as the time varying amplitude of the electric component of an interacting laser field. And so this leads to
some questions; given a specific quantum system with known time-independent dynamics generator (referred to as
the drift dynamics generators) and set of externally controllable fields for which the interaction can be described
by control dynamics generators:
1. What states or transformations can we achieve (if any)?
2. What is the shape of the control pulse required to achieve this?
These questions are addressed as controllability and quantum optimal control [dAless08]. The answer to question
of controllability is determined by the commutability of the dynamics generators and is formalised as the Lie
Algebra Rank Criterion and is discussed in detail in [dAless08]. The solutions to the second question can be
determined through optimal control algorithms, or control pulse optimisation.
Quantum Control has many applications including NMR, quantum metrology, control of chemical reactions, and
quantum information processing.
To explain the physics behind these algorithms we will first consider only finite-dimensional, closed quantum
systems.
In closed quantum systems the states can be represented by kets, and the transformations on these states are unitary
operators. The dynamics generators are Hamiltonians. The combined Hamiltonian for the system is given by
∑︁
𝐻(𝑡) = 𝐻0 + 𝑢𝑗 (𝑡)𝐻𝑗
𝑗=1
where 𝐻0 is the drift Hamiltonian and the 𝐻𝑗 are the control Hamiltonians. The 𝑢𝑗 are time varying amplitude
functions for the specific control.
The dynamics of the system are governed by Schrödingers equation.
𝑑
𝑑𝑡 |𝜓⟩ = −𝑖𝐻(𝑡) |𝜓⟩
Note we use units where ℏ = 1 throughout. The solutions to Schrödinger’s equation are of the form:
where 𝜓0 is the state of the system at 𝑡 = 0 and 𝑈 (𝑡) is a unitary operator on the Hilbert space containing the
states. 𝑈 (𝑡) is a solution to the Schrödinger operator equation
𝑑
𝑑𝑡 𝑈 = −𝑖𝐻(𝑡)𝑈, 𝑈 (0) = ⊮
We can use optimal control algorithms to determine a set of 𝑢𝑗 that will drive our system from |𝜓0 ⟩ to |𝜓1 ⟩, this is
state-to-state transfer, or drive the system from some arbitary state to a given state |𝜓1 ⟩, which is state preparation, or
effect some unitary transformation 𝑈𝑡𝑎𝑟𝑔𝑒𝑡 , called gate synthesis. The latter of these is most important in quantum
computation.
The GRadient Ascent Pulse Engineering was first proposed in [NKanej]. Solutions to Schrödinger’s equation for
a time-dependent Hamiltonian are not generally possible to obtain analytically. Therefore, a piecewise constant
approximation to the pulse amplitudes is made. Time allowed for the system to evolve 𝑇 is split into 𝑀 timeslots
(typically these are of equal duration), during which the control amplitude is assumed to remain constant. The
combined Hamiltonian can then be approximated as:
𝑁
∑︁
𝐻(𝑡) ≈ 𝐻(𝑡𝑘 ) = 𝐻0 + 𝑢𝑗𝑘 𝐻𝑗
𝑗=1
where 𝑘 is a timeslot index, 𝑗 is the control index, and 𝑁 is the number of controls. Hence 𝑡𝑘 is the evolution
time at the start of the timeslot, and 𝑢𝑗𝑘 is the amplitude of control 𝑗 throughout timeslot 𝑘. The time evolution
operator, or propagator, within the timeslot can then be calculated as:
𝑋𝑘 := 𝑒−𝑖𝐻(𝑡𝑘 )Δ𝑡𝑘
where ∆𝑡𝑘 is the duration of the timeslot. The evolution up to (and including) any timeslot 𝑘 (including the full
evolution 𝑘 = 𝑀 ) can the be calculated as
𝑋(𝑡𝑘 ) := 𝑋𝑘 𝑋𝑘−1 · · · 𝑋1 𝑋0
If the objective is state-to-state transfer then 𝑋0 = |𝜓0 ⟩ and the target 𝑋𝑡𝑎𝑟𝑔 = |𝜓1 ⟩, for gate synthesis 𝑋0 =
𝑈 (0) = ⊮ and the target 𝑋𝑡𝑎𝑟𝑔 = 𝑈𝑡𝑎𝑟𝑔 .
A figure of merit or fidelity is some measure of how close the evolution is to the target, based on the control
amplitudes in the timeslots. The typical figure of merit for unitary systems is the normalised overlap of the evolution
and the target.
†
⃒ ⃒
𝑓𝑃 𝑆𝑈 = 𝑑1 ⃒ tr{𝑋𝑡𝑎𝑟𝑔 𝑋(𝑇 )}⃒
where 𝑑 is the system dimension. In this figure of merit the absolute value is taken to ignore any differences in
global phase, and 0 ≤ 𝑓 ≤ 1. Typically the fidelity error (or infidelity) is more useful, in this case defined as
𝜀 = 1 − 𝑓𝑃 𝑆𝑈 . There are many other possible objectives, and hence figures of merit.
As there are now 𝑁 × 𝑀 variables (the 𝑢𝑗𝑘 ) and one parameter to minimise 𝜀, then the problem becomes a finite
multi-variable optimisation problem, for which there are many established methods, often referred to as ‘hill-
climbing’ methods. The simplest of these to understand is that of steepest ascent (or descent). The gradient of the
fidelity with respect to all the variables is calculated (or approximated) and a step is made in the variable space
in the direction of steepest ascent (or descent). This method is a first order gradient method. In two dimensions
this describes a method of climbing a hill by heading in the direction where the ground rises fastest. This analogy
also clearly illustrates one of the main challenges in multi-variable optimisation, which is that all methods have a
tendency to get stuck in local maxima. It is hard to determine whether one has found a global maximum or not - a
local peak is likely not to be the highest mountain in the region. In quantum optimal control we can typically define
an infidelity that has a lower bound of zero. We can then look to minimise the infidelity (from here on we will
only consider optimising for infidelity minima). This means that we can terminate any pulse optimisation when
the infidelity reaches zero (to a sufficient precision). This is however only possible for fully controllable systems;
otherwise it is hard (if not impossible) to know that the minimum possible infidelity has been achieved. In the hill
walking analogy the step size is roughly fixed to a stride, however, in computations the step size must be chosen.
Clearly there is a trade-off here between the number of steps (or iterations) required to reach the minima and the
possibility that we might step over a minima. In practice it is difficult to determine an efficient and effective step
size.
The second order differentials of the infidelity with respect to the variables can be used to approximate the local
landscape to a parabola. This way a step (or jump) can be made to where the minima would be if it were parabolic.
This typically vastly reduces the number of iterations, and removes the need to guess a step size. The method where
all the second differentials are calculated explicitly is called the Newton-Raphson method. However, calculating
the second-order differentials (the Hessian matrix) can be computationally expensive, and so there are a class of
methods known as quasi-Newton that approximate the Hessian based on successive iterations. The most popular
of these (in quantum optimal control) is the Broyden–Fletcher–Goldfarb–Shanno algorithm (BFGS). The default
method in the QuTiP Qtrl GRAPE implementation is the L-BFGS-B method in Scipy, which is a wrapper to the
implementation described in [Byrd95]. This limited memory and bounded method does not need to store the
entire Hessian, which reduces the computer memory required, and allows bounds to be set for variable values,
which considering these are field amplitudes is often physical.
The pulse optimisation is typically far more efficient if the gradients can be calculated exactly, rather than approxi-
mated. For simple fidelity measures such as 𝑓𝑃 𝑆𝑈 this is possible. Firstly the propagator gradient for each timeslot
with respect to the control amplitudes is calculated. For closed systems, with unitary dynamics, a method using
the eigendecomposition is used, which is efficient as it is also used in the propagator calculation (to exponentiate
the combined Hamiltonian). More generally (for example open systems and symplectic dynamics) the Frechet
derivative (or augmented matrix) method is used, which is described in [Flo12]. For other optimisation goals it
may not be possible to calculate analytic gradients. In these cases it is necessary to approximate the gradients, but
this can be very expensive, and can lead to other algorithms out-performing GRAPE.
It has been shown [Lloyd14], the dimension of a quantum optimal control problem is a polynomial function of the
dimension of the manifold of the time-polynomial reachable states, when allowing for a finite control precision
and evolution time. You can think of this as the information content of the pulse (as being the only effective input)
being very limited e.g. the pulse is compressible to a few bytes without loosing the target.
This is where the Chopped RAndom Basis (CRAB) algorithm [Doria11], [Caneva11] comes into play: Since the
pulse complexity is usually very low, it is sufficient to transform the optimal control problem to a few parameter
search by introducing a physically motivated function basis that builds up the pulse. Compared to the number
of time slices needed to accurately simulate quantum dynamics (often equals basis dimension for Gradient based
algorithms), this number is lower by orders of magnitude, allowing CRAB to efficiently optimize smooth pulses
with realistic experimental constraints. It is important to point out, that CRAB does not make any suggestion on the
basis function to be used. The basis must be chosen carefully considered, taking into account a priori knowledge of
the system (such as symmetries, magnitudes of scales,. . . ) and solution (e.g. sign, smoothness, bang-bang behavior,
singularities, maximum excursion or rate of change,. . . .). By doing so, this algorithm allows for native integration
of experimental constraints such as maximum frequencies allowed, maximum amplitude, smooth ramping up and
down of the pulse and many more. Moreover initial guesses, if they are available, can (however not have to) be
included to speed up convergence.
As mentioned in the GRAPE paragraph, for CRAB local minima arising from algorithmic design can occur, too.
However, for CRAB a ‘dressed’ version has recently been introduced [Rach15] that allows to escape local minima.
For some control objectives and/or dynamical quantum descriptions, it is either not possible to derive the gradient
for the cost functional with respect to each time slice or it is computationally expensive to do so. The same can
apply for the necessary (reverse) propagation of the co-state. All this trouble does not occur within CRAB as those
elements are not in use here. CRAB, instead, takes the time evolution as a black-box where the pulse goes as
an input and the cost (e.g. infidelity) value will be returned as an output. This concept, on top, allows for direct
integration in a closed loop experimental environment where both the preliminarily open loop optimization, as well
as the final adoption, and integration to the lab (to account for modeling errors, experimental systematic noise, . . . )
can be done all in one, using this algorithm.
The Quantum Control part of qutip has been moved to its own project.
The previously available implementation is now located in the qutip-qtrl module. If the qutip-qtrl package is
installed, it can also be imported under the name qutip.control to ease porting code developed for QuTiP 4 to
QuTiP 5.
A newer interface with upgraded capacities is being developped in qutip-qoc.
Please give these modules a try.
Gallery
This is the gallery for QuTiP examples, you can click on the image to see the source code.
185
QuTiP: Quantum Toolbox in Python, Release 5.0.4
API documentation
This chapter contains automatically generated API documentation, including a complete list of QuTiP’s public
classes and functions.
5.1 Classes
5.1.1 Qobj
187
QuTiP: Quantum Toolbox in Python, Release 5.0.4
superrep
[str] Representation used if type is ‘super’. One of ‘super’ (Liouville form), ‘choi’ (Choi
matrix with tr = dimension), or ‘chi’ (chi-matrix representation).
isherm
[bool] Indicates if quantum object represents Hermitian operator.
isunitary
[bool] Indictaes if quantum object represents unitary operator.
iscp
[bool] Indicates if the quantum object represents a map, and if that map is completely
positive (CP).
ishp
[bool] Indicates if the quantum object represents a map, and if that map is hermicity
preserving (HP).
istp
[bool] Indicates if the quantum object represents a map, and if that map is trace preserv-
ing (TP).
iscptp
[bool] Indicates if the quantum object represents a map that is completely positive and
trace preserving (CPTP).
isket
[bool] Indicates if the Qobj represents a ket state.
isbra
[bool] Indicates if the Qobj represents a bra state.
isoper
[bool] Indicates if the Qobj represents an operator.
issuper
[bool] Indicates if the Qobj represents a superoperator.
isoperket
[bool] Indicates if the Qobj represents a operator-ket state.
isoperbra
[bool] Indicates if the Qobj represents a operator-bra state.
Methods
__call__(other)
Acts this Qobj on another Qobj either by left-multiplication, or by vectorization and devectorization,
as appropriate.
check_herm()
Check if the quantum object is hermitian.
Returns
isherm
[bool] Returns the new value of isherm property.
conj()
Get the element-wise conjugation of the quantum object.
contract(inplace=False)
Contract subspaces of the tensor structure which are 1D. Not defined on superoperators. If all di-
mensions are scalar, a Qobj of dimension [[1], [1]] is returned, i.e. _multiple_ scalar dimensions are
contracted, but one is left.
Parameters
inplace: bool, optional
If True, modify the dimensions in place. If False, return a copied object.
Returns
out: Qobj
Quantum object with dimensions contracted. Will be self if inplace is True.
copy()
Create identical copy
cosm()
Cosine of a quantum operator.
Operator must be square.
Returns
oper
[Qobj] Matrix cosine of operator.
Raises
TypeError
Quantum object is not square.
Notes
eigvals
[int] Number of requested eigenvalues. Default is all eigenvalues.
tol
[float] Tolerance used by sparse Eigensolver (0=machine precision). The sparse solver
may not converge if the tolerance is set too low.
maxiter
[int] Maximum number of iterations performed by sparse solver (if used).
Returns
eigvals
[array] Array of eigenvalues for operator.
Notes
The sparse eigensolver is much slower than the dense version. Use sparse only if memory requirements
demand it.
eigenstates(sparse=False, sort='low', eigvals=0, tol=0, maxiter=100000, phase_fix=None)
Eigenstates and eigenenergies.
Eigenstates and eigenenergies are defined for operators and superoperators only.
Parameters
sparse
[bool] Use sparse Eigensolver
sort
[str] Sort eigenvalues (and vectors) ‘low’ to high, or ‘high’ to low.
eigvals
[int] Number of requested eigenvalues. Default is all eigenvalues.
tol
[float] Tolerance used by sparse Eigensolver (0 = machine precision). The sparse solver
may not converge if the tolerance is set too low.
maxiter
[int] Maximum number of iterations performed by sparse solver (if used).
phase_fix
[int, None] If not None, set the phase of each kets so that ket[phase_fix,0] is real posi-
tive.
Returns
eigvals
[array] Array of eigenvalues for operator.
eigvecs
[array] Array of quantum operators representing the oprator eigenkets. Order of eigen-
kets is determined by order of eigenvalues.
Notes
The sparse eigensolver is much slower than the dense version. Use sparse only if memory requirements
demand it.
expm(dtype=<class 'qutip.core.data.dense.Dense'>)
Matrix exponential of quantum operator.
Input operator must be square.
Parameters
dtype
[type] The data-layer type that should be output. As the matrix exponential is almost
dense, this defaults to outputting dense matrices.
Returns
oper
[Qobj] Exponentiated quantum operator.
Raises
TypeError
Quantum operator is not square.
full(order='C', squeeze=False)
Dense array from quantum object.
Parameters
order
[str {‘C’, ‘F’}] Return array in C (default) or Fortran ordering.
squeeze
[bool {False, True}] Squeeze output array.
Returns
data
[array] Array of complex data from quantum objects data attribute.
groundstate(sparse=False, tol=0, maxiter=100000, safe=True)
Ground state Eigenvalue and Eigenvector.
Defined for quantum operators or superoperators only.
Parameters
sparse
[bool] Use sparse Eigensolver
tol
[float] Tolerance used by sparse Eigensolver (0 = machine precision). The sparse solver
may not converge if the tolerance is set too low.
maxiter
[int] Maximum number of iterations performed by sparse solver (if used).
safe
[bool (default=True)] Check for degenerate ground state
Returns
eigval
[float] Eigenvalue for the ground state of quantum operator.
eigvec
[Qobj] Eigenket for the ground state of quantum operator.
Notes
The sparse eigensolver is much slower than the dense version. Use sparse only if memory requirements
demand it.
inv(sparse=False)
Matrix inverse of a quantum operator
Operator must be square.
Returns
oper
[Qobj] Matrix inverse of operator.
Raises
TypeError
Quantum object is not square.
property isbra
Indicates if the Qobj represents a bra state.
property isket
Indicates if the Qobj represents a ket state.
property isoper
Indicates if the Qobj represents an operator.
property isoperbra
Indicates if the Qobj represents a operator-bra state.
property isoperket
Indicates if the Qobj represents a operator-ket state.
property issuper
Indicates if the Qobj represents a superoperator.
logm()
Matrix logarithm of quantum operator.
Input operator must be square.
Returns
oper
[Qobj] Logarithm of the quantum operator.
Raises
TypeError
Quantum operator is not square.
matrix_element(bra, ket)
Calculates a matrix element.
Gives the matrix element for the quantum object sandwiched between a bra and ket vector.
Parameters
bra
[Qobj] Quantum object of type ‘bra’ or ‘ket’
ket
[Qobj] Quantum object of type ‘ket’.
Returns
elem
[complex] Complex valued matrix element.
Notes
It is slightly more computationally efficient to use a ket vector for the ‘bra’ input.
norm(norm=None, kwargs=None)
Norm of a quantum object.
Default norm is L2-norm for kets and trace-norm for operators. Other ket and operator norms may be
specified using the norm parameter.
Parameters
norm
[str] Which type of norm to use. Allowed values for vectors are ‘l2’ and ‘max’. Allowed
values for matrices are ‘tr’ for the trace norm, ‘fro’ for the Frobenius norm, ‘one’ and
‘max’.
kwargs
[dict] Additional keyword arguments to pass on to the relevant norm solver. See details
for each norm function in data.norm.
Returns
norm
[float] The requested norm of the operator or state quantum object.
overlap(other)
Overlap between two state vectors or two operators.
Gives the overlap (inner product) between the current bra or ket Qobj and and another bra or ket Qobj.
It gives the Hilbert-Schmidt overlap when one of the Qobj is an operator/density matrix.
Parameters
other
[Qobj] Quantum object for a state vector of type ‘ket’, ‘bra’ or density matrix.
Returns
overlap
[complex] Complex valued overlap.
Raises
TypeError
Can only calculate overlap between a bra, ket and density matrix quantum objects.
permute(order)
Permute the tensor structure of a quantum object. For example,
qutip.tensor(x, y).permute([1, 0])
will give the same result as
qutip.tensor(y, x)
and
qutip.tensor(a, b, c).permute([1, 2, 0])
will be the same as
qutip.tensor(b, c, a)
For regular objects (bras, kets and operators) we expect order to be a flat list of integers, which specifies
the new order of the tensor product.
For superoperators, we expect order to be something like
[[0, 2], [1, 3]]
which tells us to permute according to [0, 2, 1, 3], and then group indices according to the length of
each sublist. As another example, permuting a superoperator with dimensions of
[[[1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3]]]
by an order
[[0, 3], [1, 4], [2, 5]]
should give a new object with dimensions
[[[1, 1], [2, 2], [3, 3]], [[1, 1], [2, 2], [3, 3]]].
Parameters
order
[list] List of indices specifying the new tensor order.
Returns
P
[Qobj] Permuted quantum object.
proj()
Form the projector from a given ket or bra vector.
Parameters
Q
[Qobj] Input bra or ket vector
Returns
P
[Qobj] Projection operator.
ptrace(sel, dtype=None)
Take the partial trace of the quantum object leaving the selected subspaces. In other words, trace out
all subspaces which are _not_ passed.
This is typically a function which acts on operators; bras and kets will be promoted to density matrices
before the operation takes place since the partial trace is inherently undefined on pure states.
For operators which are currently being represented as states in the superoperator formalism (i.e. the
object has type operator-ket or operator-bra), the partial trace is applied as if the operator were in the
conventional form. This means that for any operator x, operator_to_vector(x).ptrace(0) ==
operator_to_vector(x.ptrace(0)) and similar for operator-bra.
The story is different for full superoperators. In the formalism that QuTiP uses, if an operator has di-
mensions (dims) of [[2, 3], [2, 3]] then it can be represented as a state on a Hilbert space of dimensions
[2, 3, 2, 3], and a superoperator would be an operator which acts on this joint space. This function per-
forms the partial trace on superoperators by letting the selected components refer to elements of the
_joint_ _space_, and then returns a regular operator (of type oper).
Parameters
sel
[int or iterable of int] An int or list of components to keep after partial trace. The
selected subspaces will _not_ be reordered, no matter order they are supplied to ptrace.
Returns
oper
[Qobj] Quantum object representing partial trace with selected components remaining.
purity()
Calculate purity of a quantum object.
Returns
state_purity
[float] Returns the purity of a quantum object. For a pure state, the purity is 1. For a
mixed state of dimension d, 1/d<=purity<1.
property shape
Return the shape of the Qobj data.
sinm()
Sine of a quantum operator.
Operator must be square.
Returns
oper
[Qobj] Matrix sine of operator.
Raises
TypeError
Quantum object is not square.
Notes
Notes
The sparse eigensolver is much slower than the dense version. Use sparse only if memory requirements
demand it.
tidyup(atol=None)
Removes small elements from the quantum object.
Parameters
atol
[float] Absolute tolerance used by tidyup. Default is set via qutip global settings pa-
rameters.
Returns
oper
[Qobj] Quantum object with small elements removed.
to(data_type, copy=False)
Convert the underlying data store of this Qobj into a different storage representation.
The different storage representations available are the “data-layer types” which are known to qutip.
core.data.to. By default, these are CSR, Dense and Dia, which respectively construct a compressed
sparse row matrix, diagonal matrix and a dense one. Certain algorithms and operations may be faster
or more accurate when using a more appropriate data store.
Parameters
data_type
[type, str] The data-layer type or its string alias that the data of this Qobj should be
converted to.
copy
[Bool] If the data store is already in the format requested, whether the function should
return returns self or a copy.
Returns
Qobj
A Qobj with the data stored in the requested format.
tr()
Trace of a quantum object.
Returns
trace
[float] Returns the trace of the quantum object.
trans()
Get the matrix transpose of the quantum operator.
Returns
oper
[Qobj] Transpose of input operator.
transform(inpt, inverse=False)
Basis transform defined by input array.
Input array can be a matrix defining the transformation, or a list of kets that defines the new basis.
Parameters
inpt
[array_like] A matrix or list of kets defining the transformation.
inverse
[bool] Whether to return inverse transformation.
Returns
oper
[Qobj] Operator in new basis.
Notes
5.1.2 QobjEvo
class QobjEvo
A class for representing time-dependent quantum objects, such as quantum operators and states.
Importantly, QobjEvo instances are used to represent such time-dependent quantum objects when working
with QuTiP solvers.
A QobjEvo instance may be constructed from one of the following:
• a callable f(t: double, args: dict) -> Qobj that returns the value of the quantum object at
time t.
• a [Qobj, Coefficient] pair, where the Coefficient may be any item that coefficient can
accept (e.g. a function, a numpy array of coefficient values, a string expression).
Parameters
Q_object
[callable, list or Qobj] A specification of the time-depedent quantum object. See the
paragraph above for a full description and the examples section below for examples.
args
[dict, optional] A dictionary that contains the arguments for the coefficients. Arguments
may be omitted if no function or string coefficients that require arguments are present.
tlist
[array-like, optional] A list of times corresponding to the values of the coefficients sup-
plied as numpy arrays. If no coefficients are supplied as numpy arrays, tlist may be
omitted, otherwise it is required.
The times in tlist do not need to be equidistant, but must be sorted.
By default, a cubic spline interpolation will be used to interpolate the value of the (numpy
array) coefficients at time t. If the coefficients are to be treated as step functions, pass
the argument order=0 (see below).
order
[int, default=3] Order of the spline interpolation that is to be used to interpolate the value
of the (numpy array) coefficients at time t. 0 use previous or left value.
copy
[bool, default=True] Whether to make a copy of the Qobj instances supplied in the
Q_object parameter.
compress
[bool, default=True] Whether to compress the QobjEvo instance terms after the instance
has been created.
This sums the constant terms in a single term and combines [Qobj, coefficient]
pairs with the same Qobj into a single pair containing the sum of the coefficients.
See compress.
function_style
[{None, “pythonic”, “dict”, “auto”}] The style of function signature used by
callables in Q_object. If style is None, the value of qutip.settings.
core["function_coefficient_style"] is used. Otherwise the supplied value over-
rides the global setting.
boundary_conditions
[2-Tuple, str or None, optional] Boundary conditions for spline evaluation. Default
value is None. Correspond to bc_type of scipy.interpolate.make_interp_spline. Refer
to Scipy’s documentation for further details: https://docs.scipy.org/doc/scipy/reference/
generated/scipy.interpolate.make_interp_spline.html
Examples
For list based QobjEvo, the list must consist of Qobj or [Qobj, Coefficient] pairs:
The coefficients may be specified either using a Coefficient object or by a function, string, numpy array
or any object that can be passed to the coefficient function. See the documentation of coefficient for
a full description.
An example of a coefficient specified by a function:
H = QobjEvo(
[H0, [H1, 'exp(-1j*w1*t)'], [H2, 'cos(w2*t)']],
args={"w1": 1., "w2": 2.}
)
Coefficients maybe also be expressed as numpy arrays giving a list of the coefficient values:
The coeffients array must have the same len as the tlist.
A QobjEvo may also be built using simple arithmetic operations combining Qobj with Coefficient, for
example:
Attributes
dims
[list] List of dimensions keeping track of the tensor structure.
shape
[(int, int)] List of dimensions keeping track of the tensor structure.
type
[str] Type of quantum object: ‘bra’, ‘ket’, ‘oper’, ‘operator-ket’, ‘operator-bra’, or ‘super’.
superrep
[str] Representation used if type is ‘super’. One of ‘super’ (Liouville form) or ‘choi’
(Choi matrix with tr = dimension).
__call__()
Get the Qobj at t.
Parameters
t
[float] Time at which the QobjEvo is to be evalued.
_args
[dict [optional]] New arguments as a dict. Update args with arguments(new_args).
**kwargs
New arguments as a keywors. Update args with arguments(**new_args).
Notes
If both the positional _args and keywords are passed new values from both will be used. If a key is
present with both, the _args dict value will take priority.
arguments(_args=None, **kwargs)
Update the arguments.
Parameters
_args
[dict [optional]] New arguments as a dict. Update args with arguments(new_args).
**kwargs
New arguments as a keywors. Update args with arguments(**new_args).
Notes
If both the positional _args and keywords are passed new values from both will be used. If a key is
present with both, the _args dict value will take priority.
compress()
Look for redundance in the QobjEvo components:
Constant parts, (Qobj without Coefficient) will be summed. Pairs [Qobj, Coefficient] with
the same Qobj are merged.
Example: [[sigmax(), f1], [sigmax(), f2]] -> [[sigmax(), f1+f2]]
The QobjEvo is transformed inplace.
Returns
None
conj()
Get the element-wise conjugation of the quantum object.
copy()
Return a copy of this QobjEvo
dag()
Get the Hermitian adjoint of the quantum object.
dtype
Type of the data layers of the QobjEvo. When different data layers are used, we return the type of the
sum of the parts.
Example
QobjEvo([sigmax(), coeff]).linear_map(spre)
gives the same result has
QobjEvo([spre(sigmax()), coeff])
Parameters
op_mapping: callable
Funtion to apply to each elements.
Returns
QobjEvo
Modified object
Notes
Does not modify the coefficients, thus linear_map(conj) would not give the the conjugate of the
QobjEvo. It’s only valid for linear transformations.
matmul(t, state)
Product of this operator at time t to the state. self(t) @ state
Parameters
t
[float] Time of the operator to apply.
state
[Qobj] right matrix of the product
Returns
product
[Qobj] The result product as a Qobj
matmul_data(t, state, out=None)
Compute out += self(t) @ state
num_elements
Number of parts composing the system
tidyup(atol=1e-12)
Removes small elements from quantum object.
to(data_type)
Convert the underlying data store of all component into the desired storage representation.
The different storage representations available are the “data-layer types”. By default, these are Dense,
Dia and CSR, which respectively construct a dense matrix, diagonal sparse matrixand a compressed
sparse row one.
The QobjEvo is transformed inplace.
Parameters
data_type
[type] The data-layer type that the data of this Qobj should be converted to.
Returns
None
to_list()
Restore the QobjEvo to a list form.
Returns
list_qevo: list
The QobjEvo as a list, element are either Qobj for constant parts, [Qobj,
Coefficient] for coefficient based term. The original format of the Coefficient
is not restored. Lastly if the original QobjEvo is constructed with a function returning
a Qobj, the term is returned as a pair of the original function and args (dict).
trans()
Transpose of the quantum object
xlpos
[list, default [1.1, -1.1]] Positions of +x and -x labels respectively.
ylabel
[list, default [“$y$”, “”]] List of strings corresponding to +y and -y axes labels, respec-
tively.
ylpos
[list, default [1.2, -1.2]] Positions of +y and -y labels respectively.
zlabel
[list, default [‘$\left|0\right>$’, ‘$\left|1\right>$’]] List of strings corresponding to +z
and -z axes labels, respectively.
zlpos
[list, default [1.2, -1.2]] Positions of +z and -z labels respectively.
add_annotation(state_or_vector, text, **kwargs)
Add a text or LaTeX annotation to Bloch sphere, parametrized by a qubit state or a vector.
Parameters
state_or_vector
[Qobj/array/list/tuple] Position for the annotaion. Qobj of a qubit or a vector of 3
elements.
text
[str] Annotation text. You can use LaTeX, but remember to use raw string e.g.
r”$langle x rangle$” or escape backslashes e.g. “$\langle x \rangle$”.
kwargs
Options as for mplot3d.axes3d.text, including: fontsize, color, horizontalalignment,
verticalalignment.
add_arc(start, end, fmt='b', steps=None, **kwargs)
Adds an arc between two points on a sphere. The arc is set to be blue solid curve by default.
The start and end points must be on the same sphere (i.e. have the same radius) but need not be on the
unit sphere.
Parameters
start
[Qobj or array-like] Array with cartesian coordinates of the first point, or a state vector
or density matrix that can be mapped to a point on or within the Bloch sphere.
end
[Qobj or array-like] Array with cartesian coordinates of the second point, or a state
vector or density matrix that can be mapped to a point on or within the Bloch sphere.
fmt
[str, default: “b”] A matplotlib format string for rendering the arc.
steps
[int, default: None] The number of segments to use when rendering the arc. The default
uses 100 steps times the distance between the start and end points, with a minimum of
2 steps.
**kwargs
[dict] Additional parameters to pass to the matplotlib .plot function when rendering
this arc.
add_line(start, end, fmt='k', **kwargs)
Adds a line segment connecting two points on the bloch sphere.
The line segment is set to be a black solid line by default.
Parameters
start
[Qobj or array-like] Array with cartesian coordinates of the first point, or a state vector
or density matrix that can be mapped to a point on or within the Bloch sphere.
end
[Qobj or array-like] Array with cartesian coordinates of the second point, or a state
vector or density matrix that can be mapped to a point on or within the Bloch sphere.
fmt
[str, default: “k”] A matplotlib format string for rendering the line.
**kwargs
[dict] Additional parameters to pass to the matplotlib .plot function when rendering
this line.
add_points(points, meth='s', colors=None, alpha=1.0)
Add a list of data points to bloch sphere.
Parameters
points
[array_like] Collection of data points.
meth
[{‘s’, ‘m’, ‘l’}] Type of points to plot, use ‘m’ for multicolored, ‘l’ for points connected
with a line.
colors
[array_like] Optional array with colors for the points. A single color for meth ‘s’, and
list of colors for meth ‘m’
alpha
[float, default=1.] Transparency value for the vectors. Values between 0 and 1.
Notes
When using meth=l in QuTiP 4.6, the line transparency defaulted to 0.75 and there was no way to
alter it. When the alpha parameter was added in QuTiP 4.7, the default became alpha=1.0 for values
of meth.
add_states(state, kind='vector', colors=None, alpha=1.0)
Add a state vector Qobj to Bloch sphere.
Parameters
state
[Qobj] Input state vector.
kind
[{‘vector’, ‘point’}] Type of object to plot.
colors
[array_like] Optional array with colors for the states.
alpha
[float, default=1.] Transparency value for the vectors. Values between 0 and 1.
add_vectors(vectors, colors=None, alpha=1.0)
Add a list of vectors to Bloch sphere.
Parameters
vectors
[array_like] Array with vectors of unit length or smaller.
colors
[array_like] Optional array with colors for the vectors.
alpha
[float, default=1.] Transparency value for the vectors. Values between 0 and 1.
clear()
Resets Bloch sphere data sets to empty.
make_sphere()
Plots Bloch sphere and data sets.
render()
Render the Bloch sphere and its data sets in on given figure and axes.
save(name=None, format='png', dirc=None, dpin=None)
Saves Bloch sphere to file of type format in directory dirc.
Parameters
name
[str] Name of saved image. Must include path and format as well. i.e.
‘/Users/Me/Desktop/bloch.png’ This overrides the ‘format’ and ‘dirc’ arguments.
format
[str] Format of output image.
dirc
[str] Directory for output images. Defaults to current working directory.
dpin
[int] Resolution in dots per inch.
Returns
File containing plot of Bloch sphere.
set_label_convention(convention)
Set x, y and z labels according to one of conventions.
Parameters
convention
[string] One of the following:
• “original”
• “xyz”
• “sx sy sz”
• “01”
• “polarization jones”
• “polarization jones letters” see also: https://en.wikipedia.org/wiki/Jones_calculus
• “polarization stokes” see also: https://en.wikipedia.org/wiki/Stokes_parameters
show()
Display Bloch sphere and corresponding data sets.
Notes
When using inline plotting in Jupyter notebooks, any figure created in a notebook cell is displayed
after the cell executes. Thus if you create a figure yourself and use it create a Bloch sphere with b =
Bloch(..., fig=fig) and then call b.show() in the same cell, then the figure will be displayed
twice. If you do create your own figure, the simplest solution to this is to not call .show() in the cell
you create the figure in.
5.1.4 Distributions
qfunc
A single function version, which will involve computing several quantities multiple times in order to
use less memory.
Examples
Initialise the class for a square set of coordinates, with some states we want to investigate.
Now we can calculate the Husimi-Q function over each of the states more efficiently with:
5.1.5 Solvers
args
[dict, optional {None}] Update the args of the system. The change is effective from
the beginning of the interval. Changing args can slow the evolution.
copy
[bool, optional {True}] Whether to return a copy of the data or the data in the ODE
solver.
Notes
The state must be initialized first by calling start or run. If run is called, step will continue from
the last time and state obtained.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class MESolver(H, c_ops=None, *, options=None)
Bases: SESolver
Master equation evolution of a density matrix for a given Hamiltonian and set of collapse operators, or a
Liouvillian.
Evolve the density matrix (rho0) using a given Hamiltonian or Liouvillian (H) and an optional set of collapse
operators (c_ops), by integrating the set of ordinary differential equations that define the system.
If either H or the Qobj elements in c_ops are superoperators, they will be treated as direct contributions to
the total system Liouvillian. This allows the solution of master equations that are not in standard Lindblad
form.
Parameters
H
[Qobj, QobjEvo] Possibly time-dependent system Liouvillian or Hamiltonian as a Qobj
or QobjEvo. List of [Qobj, Coefficient] or callable that can be made into QobjEvo
are also accepted.
c_ops
[list of Qobj, QobjEvo] Single collapse operator, or list of collapse operators, or a list
of Liouvillian superoperators. None is equivalent to an empty list.
options
[dict, optional] Options for the solver, see MESolver.options and Integrator for a list
of all options.
Attributes
stats: dict
Diverse diagnostic statistics of the evolution.
classmethod ExpectFeedback(operator, default=0.0)
Expectation value of the instantaneous state of the evolution to be used by a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"E0": Solver.ExpectFeedback(oper)})
The func will receive expect(oper, state) as E0 during the evolution.
Parameters
operator
[Qobj, QobjEvo] Operator to compute the expectation values of.
default
[float, default][0.] Initial value to be used at setup.
e_ops
[list {None}] List of Qobj, QobjEvo or callable to compute the expectation values.
Function[s] must have the signature f(t : float, state : Qobj) -> expect.
Returns
results
[Result] Results of the evolution. States and/or expect will be saved. You can control
the saved data in the options.
start(state0, t0)
Set the initial state and time for a step evolution.
Parameters
state0
[Qobj] Initial state of the evolution.
t0
[double] Initial time of the evolution.
step(t, *, args=None, copy=True)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
args
[dict, optional {None}] Update the args of the system. The change is effective from
the beginning of the interval. Changing args can slow the evolution.
copy
[bool, optional {True}] Whether to return a copy of the data or the data in the ODE
solver.
Notes
The state must be initialized first by calling start or run. If run is called, step will continue from
the last time and state obtained.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class BRSolver(H, a_ops, c_ops=None, sec_cutoff=0.1, *, options=None)
Bases: Solver
Bloch Redfield equation evolution of a density matrix for a given Hamiltonian and set of bath coupling
operators.
Parameters
H
[Qobj, QobjEvo] Possibly time-dependent system Liouvillian or Hamiltonian as a Qobj
or QobjEvo. list of [Qobj, Coefficient] or callable that can be made into QobjEvo
are also accepted.
a_ops
[list of (a_op, spectra)] Nested list of system operators that couple to the environment,
and the corresponding bath spectra.
a_op
[Qobj, QobjEvo] The operator coupling to the environment. Must be hermitian.
spectra
[Coefficient] The corresponding bath spectra. As a Coefficient using an ‘w’ args.
Can depend on t only if a_op is a QobjEvo. SpectraCoefficient can be used to
conver a coefficient depending on t to one depending on w.
Example:
a_ops = [
(a+a.dag(), coefficient('w>0', args={'w':0})),
(QobjEvo([b+b.dag(), lambda t: ...]),
coefficient(lambda t, w: ...), args={"w": 0}),
(c+c.dag(), SpectraCoefficient(coefficient(array, tlist=ws))),
]
c_ops
[list of Qobj, QobjEvo] Single collapse operator, or list of collapse operators, or a list
of Lindblad dissipator. None is equivalent to an empty list.
options
[dict, optional] Options for the solver, see BRSolver.options and Integrator for a list
of all options.
sec_cutoff
[float {0.1}] Cutoff for secular approximation. Use -1 if secular approximation is not
used when evaluating bath-coupling terms.
Attributes
stats: dict
Diverse diagnostic statistics of the evolution.
classmethod ExpectFeedback(operator, default=0.0)
Expectation value of the instantaneous state of the evolution to be used by a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"E0": Solver.ExpectFeedback(oper)})
The func will receive expect(oper, state) as E0 during the evolution.
Parameters
operator
[Qobj, QobjEvo] Operator to compute the expectation values of.
default
[float, default][0.] Initial value to be used at setup.
classmethod StateFeedback(default=None, raw_data=False)
State of the evolution to be used in a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"state": BRMESolver.StateFeedback()})
The func will receive the density matrix as state during the evolution.
Note: The state will not be in the lab basis, but in the evolution basis.
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
raw_data
[bool, default][False] If True, the raw matrix will be passed instead of a Qobj. For
density matrices, the matrices can be column stacked or square depending on the inte-
gration method.
property options
Options for bloch redfield solver:
store_final_state: bool, default: False
Whether or not to store the final state of the evolution in the result class.
store_states: bool, default: None
Whether or not to store the state vectors or density matrices. On None the states will be saved if
no expectation operators are given.
normalize_output: bool, default: False
Normalize output state to hide ODE numerical errors.
progress_bar: str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}, default: “”
How to present the solver progress. ‘tqdm’ uses the python module of the same name and raise an
error if not installed. Empty string or False will disable the bar.
progress_kwargs: dict, default: {“chunk_size”:10}
Arguments to pass to the progress_bar. Qutip’s bars use chunk_size.
tensor_type: str [‘sparse’, ‘dense’, ‘data’], default: “sparse”
Which data type to use when computing the brtensor. With a cutoff ‘sparse’ is usually the most
efficient.
sparse_eigensolver: bool, default: False
Whether to use the sparse eigensolver
method: str, default: “adams”
Which ODE integrator methods are supported.
run(state0, tlist, *, args=None, e_ops=None)
Do the evolution of the Quantum system.
For a state0 at time tlist[0] do the evolution as directed by rhs and for each time in tlist store the
state and/or expectation values in a Result. The evolution method and stored results are determined
by options.
Parameters
state0
[Qobj] Initial state of the evolution.
tlist
[list of double] Time for which to save the results (state and/or expect) of the evolution.
The first element of the list is the initial time of the evolution. Each times of the list
must be increasing, but does not need to be uniformy distributed.
args
[dict, optional {None}] Change the args of the rhs for the evolution.
e_ops
[list {None}] List of Qobj, QobjEvo or callable to compute the expectation values.
Function[s] must have the signature f(t : float, state : Qobj) -> expect.
Returns
results
[Result] Results of the evolution. States and/or expect will be saved. You can control
the saved data in the options.
start(state0, t0)
Set the initial state and time for a step evolution.
Parameters
state0
[Qobj] Initial state of the evolution.
t0
[double] Initial time of the evolution.
step(t, *, args=None, copy=True)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
args
[dict, optional {None}] Update the args of the system. The change is effective from
the beginning of the interval. Changing args can slow the evolution.
copy
[bool, optional {True}] Whether to return a copy of the data or the data in the ODE
solver.
Notes
The state must be initialized first by calling start or run. If run is called, step will continue from
the last time and state obtained.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class FMESolver(floquet_basis, a_ops, w_th=0.0, *, kmax=5, nT=None, options=None)
Bases: MESolver
Solver for the Floquet-Markov master equation.
Parameters
floquet_basis
[FloquetBasis] The system Hamiltonian wrapped in a FloquetBasis object. Choosing
a different integrator for the floquet_basis than for the evolution of the floquet state
can improve the performance.
a_ops
[list of tuple(Qobj, callable)] List of collapse operators and the corresponding function
for the noise power spectrum. The collapse operator must be a Qobj and cannot be time
dependent. The spectrum function must take and return an numpy array.
w_th
[float] The temperature of the environment in units of Hamiltonian frequency.
kmax
[int [5]] The truncation of the number of sidebands..
nT
[int [20*kmax]] The number of integration steps (for calculating X) within one period.
options
[dict, optional] Options for the solver, see FMESolver.options and Integrator for a list
of all options.
classmethod ExpectFeedback()
Expect of the state of the evolution to be used in a time-dependent operator.
Not not implemented for FMESolver
classmethod StateFeedback()
State of the evolution to be used in a time-dependent operator.
Not not implemented for FMESolver
property options
Solver’s options:
store_final_state: bool, default: False
Whether or not to store the final state of the evolution in the result class.
store_states: bool, default: None
Whether or not to store the state vectors or density matrices. On None the states will be saved if
no expectation operators are given.
normalize_output: bool, default: True
Normalize output state to hide ODE numerical errors.
progress_bar: str {“text”, “enhanced”, “tqdm”, “”}, default: “”
How to present the solver progress. ‘tqdm’ uses the python module of the same name and raise an
error if not installed. Empty string or False will disable the bar.
progress_kwargs: dict, default: {“chunk_size”: 10}
Arguments to pass to the progress_bar. Qutip’s bars use chunk_size.
method: str, default: “adams”
Which ordinary differential equation integration method to use.
run(state0, tlist, *, floquet=False, args=None, e_ops=None)
Calculate the evolution of the quantum system.
For a state0 at time tlist[0] do the evolution as directed by rhs and for each time in tlist store the
state and/or expectation values in a Result. The evolution method and stored results are determined
by options.
Parameters
state0
[Qobj] Initial state of the evolution.
tlist
[list of double] Time for which to save the results (state and/or expect) of the evolution.
The first element of the list is the initial time of the evolution. Each times of the list
must be increasing, but does not need to be uniformy distributed.
floquet
[bool, optional {False}] Whether the initial state in the floquet basis or laboratory basis.
args
[dict, optional {None}] Not supported
e_ops
[list {None}] List of Qobj, QobjEvo or callable to compute the expectation values.
Function[s] must have the signature f(t : float, state : Qobj) -> expect.
Returns
results
[FloquetResult] Results of the evolution. States and/or expect will be saved. You
can control the saved data in the options.
start(state0, t0, *, floquet=False)
Set the initial state and time for a step evolution. options for the evolutions are read at this step.
Parameters
state0
[Qobj] Initial state of the evolution.
t0
[double] Initial time of the evolution.
floquet
[bool, optional {False}] Whether the initial state is in the floquet basis or laboratory
basis.
step(t, *, args=None, copy=True, floquet=False)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
copy
[bool, optional {True}] Whether to return a copy of the data or the data in the ODE
solver.
floquet
[bool, optional {False}] Whether to return the state in the floquet basis or laboratory
basis.
args
[dict, optional {None}] Not supported
Notes
The state must be initialized first by calling start or run. If run is called, step will continue from
the last time and state obtained.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class FloquetBasis(H, T, args=None, options=None, sparse=False, sort=True, precompute=None)
Utility to compute floquet modes and states.
Attributes
U
[Propagator] The propagator of the Hamiltonian over one period.
evecs
[Data] Matrix where each column is an initial Floquet mode.
e_quasi
[np.ndarray[float]] The quasi energies of the Hamiltonian.
from_floquet_basis(floquet_basis, t=0)
Transform a ket or density matrix from the Floquet basis at time t to the lab basis.
Parameters
floquet_basis
[Qobj, Data] Initial state in the Floquet basis at time t. May be either a ket or density
matrix.
t
[float [0]] The time at which to evaluate the Floquet states.
Returns
output
[Qobj, Data] The state in the lab basis. The return type is the same as the type of the
input state.
mode(t, data=False)
Calculate the Floquet modes at time t.
Parameters
t
[float] The time for which to evaluate the Floquet mode.
data
[bool [False]] Whether to return the states as a single data matrix or a list of ket states.
Returns
output
[list[Qobj], Data] A list of Floquet states for the time t or the states as column in a
single matrix.
state(t, data=False)
Evaluate the floquet states at time t.
Parameters
t
[float] The time for which to evaluate the Floquet states.
data
[bool [False]] Whether to return the states as a single data matrix or a list of ket states.
Returns
output
[list[Qobj], Data] A list of Floquet states for the time t or the states as column in a
single matrix.
to_floquet_basis(lab_basis, t=0)
Transform a ket or density matrix in the lab basis to the Floquet basis at time t.
Parameters
lab_basis
[Qobj, Data] Initial state in the lab basis.
t
[float [0]] The time at which to evaluate the Floquet states.
Returns
output
[Qobj, Data] The state in the Floquet basis. The return type is the same as the type of
the input state.
class Propagator(system, *, c_ops=(), args=None, options=None, memoize=10, tol=1e-14)
A generator of propagator for a system.
Usage:
U = Propagator(H, c_ops)
psi_t = U(t) @ psi_0
Save some previously computed propagator are stored to speed up subsequent computation. Changing args
will erase these stored probagator.
Parameters
system
[Qobj, QobjEvo, Solver] Possibly time-dependent system driving the evolution, either
already packaged in a solver, such as SESolver or BRSolver, or the Liouvillian or
Hamiltonian as a Qobj, QobjEvo. list of [Qobj, Coefficient] or callable that can
be made into QobjEvo are also accepted.
Solvers that run non-deterministacilly, such as MCSolver, are not supported.
c_ops
[list, optional] List of Qobj or QobjEvo collapse operators.
args
[dictionary, optional] Parameters to callback functions for time-dependent Hamiltonians
and collapse operators.
options
[dict, optional] Options for the solver.
memoize
[int, default: 10] Max number of propagator to save.
tol
[float, default: 1e-14] Absolute tolerance for the time. If a previous propagator was
computed at a time within tolerance, that propagator will be returned.
Notes
The Propagator is not a QobjEvo so it cannot be used for operations with Qobj or QobjEvo. It can be
made into a QobjEvo with
U = QobjEvo(Propagator(H))
Parameters
t
[float] Time at which to compute the propagator.
args
[dict] Argument to pass to a time dependent Hamiltonian. Updating args take effect
since t=0 and the new args will be used in future call.
Note: CollapseFeedback can’t be added to a running solver when updating arguments between steps:
solver.step(..., args={}).
Parameters
default
[callable, default][[]] Default function used outside the solver.
t0
[double] Initial time of the evolution.
seed
[int, SeedSequence, list, optional] Seed for the random number generator. It can be
a single seed used to spawn seeds for each trajectory or a list of seed, one for each
trajectory.
Notes
When using step evolution, only one trajectory can be computed at once.
step(t, *, args=None, copy=True)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
args
[dict, optional] Update the args of the system. The change is effective from the be-
ginning of the interval. Changing args can slow the evolution.
copy
[bool, default: True] Whether to return a copy of the data or the data in the ODE solver.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class NonMarkovianMCSolver(H, ops_and_rates, args=None, options=None)
Bases: MCSolver
Monte Carlo Solver for Lindblad equations with “rates” that may be negative. The c_ops parameter of
MCSolver is replaced by an ops_and_rates parameter to allow for negative rates. Options for the under-
lying ODE solver are given by the Options class.
Parameters
H
[Qobj, QobjEvo, list, callable.] System Hamiltonian as a Qobj, QobjEvo. It can also
be any input type that QobjEvo accepts (see QobjEvo documentation). H can also be a
superoperator (liouvillian) if some collapse operators are to be treated deterministically.
ops_and_rates
[list] A list of tuples (L, Gamma), where the Lindblad operator L is a Qobj and Gamma
represents the corresponding rate, which is allowed to be negative. The Lindblad op-
erators must be operators even if H is a superoperator. Each rate Gamma may be just a
number (in the case of a constant rate) or, otherwise, specified using any format accepted
by qutip.coefficient.
args
[None / dict] Arguments for time-dependent Hamiltonian and collapse operator terms.
options
[SolverOptions, [optional]] Options for the evolution.
classmethod CollapseFeedback(default=None)
Collapse of the trajectory argument for time dependent systems.
When used as an args:
QobjEvo([op, func], args={"cols": MCSolver.CollapseFeedback()})
The func will receive a list of (time, operator number) for each collapses of the trajectory as
cols.
Note: CollapseFeedback can’t be added to a running solver when updating arguments between steps:
solver.step(..., args={}).
Parameters
default
[callable, default][[]] Default function used outside the solver.
rate_shift(t)
Return the rate shift at time t.
The rate shift is 2 * abs(min([0, rate_1(t), rate_2(t), ...])).
Parameters
t
[float] The time at which to calculate the rate shift.
Returns
rate_shift
[float] The rate shift amount.
run(state, tlist, ntraj=1, *, args=None, **kwargs)
Do the evolution of the Quantum system.
For a state at time tlist[0] do the evolution as directed by rhs and for each time in tlist store the
state and/or expectation values in a Result. The evolution method and stored results are determined
by options.
Parameters
state
[Qobj] Initial state of the evolution.
tlist
[list of double] Time for which to save the results (state and/or expect) of the evolution.
The first element of the list is the initial time of the evolution. Time in the list must be
in increasing order, but does not need to be uniformly distributed.
ntraj
[int] Number of trajectories to add.
args
[dict, optional] Change the args of the rhs for the evolution.
e_ops
[list] list of Qobj or QobjEvo to compute the expectation values. Alternatively, func-
tion[s] with the signature f(t, state) -> expect can be used.
timeout
[float, optional] Maximum time in seconds for the trajectories to run. Once this time is
reached, the simulation will end even if the number of trajectories is less than ntraj.
The map function, set in options, can interupt the running trajectory or wait for it to
finish. Set to an arbitrary high number to disable.
target_tol
[{float, tuple, list}, optional] Target tolerance of the evolution. The evolution will com-
pute trajectories until the error on the expectation values is lower than this tolerance.
The maximum number of trajectories employed is given by ntraj. The error is com-
puted using jackknife resampling. target_tol can be an absolute tolerance or a pair
of absolute and relative tolerance, in that order. Lastly, it can be a list of pairs of (atol,
rtol) for each e_ops.
seeds
[{int, SeedSequence, list}, optional] Seed or list of seeds for each trajectories.
Returns
results
[MultiTrajResult] Results of the evolution. States and/or expect will be saved. You
can control the saved data in the options.
sqrt_shifted_rate(t, i)
Return the square root of the i’th shifted rate at time t.
Parameters
t
[float] The time at wich to calculate the shifted rate.
i
[int] Which shifted rate to calculate.
Returns
rate
[float] The square root of the shifted value of rate i at time t.
start(state, t0, seed=None)
Set the initial state and time for a step evolution.
Parameters
state
[Qobj] Initial state of the evolution.
t0
[double] Initial time of the evolution.
seed
[int, SeedSequence, list, optional] Seed for the random number generator. It can be
a single seed used to spawn seeds for each trajectory or a list of seed, one for each
trajectory.
Notes
When using step evolution, only one trajectory can be computed at once.
step(t, *, args=None, copy=True)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
args
[dict, optional] Update the args of the system. The change is effective from the be-
ginning of the interval. Changing args can slow the evolution.
copy
[bool, default: True] Whether to return a copy of the data or the data in the ODE solver.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
store_ados
[bool, default: False] Whether or not to store the HEOM ADOs. Only relevant when using the
HEOM solver.
run(state0, tlist, *, args=None, e_ops=None)
Solve for the time evolution of the system.
Parameters
state0
[Qobj or HierarchyADOsState or array-like] If rho0 is a Qobj the it is the initial
state of the system (i.e. a Qobj density matrix).
If it is a HierarchyADOsState or array-like, then rho0 gives the initial state of all
ADOs.
Usually the state of the ADOs would be determine from a previous call to .run(..
.) with the solver results option store_ados set to True. For example, result =
solver.run(...) could be followed by solver.run(result.ado_states[-1],
tlist).
If a numpy array-like is passed its shape must be (number_of_ados, n, n) where
(n, n) is the system shape (i.e. shape of the system density matrix) and the ADOs
must be in the same order as in .ados.labels.
tlist
[list] An ordered list of times at which to return the value of the state.
args
[dict, optional {None}] Change the args of the RHS for the evolution.
e_ops
[Qobj / QobjEvo / callable / list / dict / None, optional] A list or dictionary of operators
as Qobj, QobjEvo and/or callable functions (they can be mixed) or a single operator
or callable function. For an operator op, the result will be computed using (state *
op).tr() and the state at each time t. For callable functions, f, the result is computed
using f(t, ado_state). The values are stored in the expect and e_data attributes
of the result (see the return section below).
Returns
HEOMResult
The results of the simulation run, with the following important attributes:
• times: the times t (i.e. the tlist).
• states: the system state at each time t (only available if e_ops was None or if the
solver option store_states was set to True).
• ado_states: the full ADO state at each time (only available if the re-
sults option ado_return was set to True). Each element is an instance of
HierarchyADOsState. The state of a particular ADO may be extracted from
result.ado_states[i] by calling extract.
• expect: a list containing the values of each e_ops at time t.
• e_data: a dictionary containing the values of each e_ops at tme t. The keys are
those given by e_ops if it was a dict, otherwise they are the indexes of the supplied
e_ops.
See HEOMResult and Result for the complete list of attributes.
start(state0, t0)
Set the initial state and time for a step evolution.
Parameters
state0
[Qobj] Initial state of the evolution. This may provide either just the initial density
matrix of the system, or the full set of ADOs for the hierarchy. See the documentation
for rho0 in the .run(...) method for details.
t0
[double] Initial time of the evolution.
steady_state(use_mkl=True, mkl_max_iter_refine=100, mkl_weighted_matching=False)
Compute the steady state of the system.
Parameters
use_mkl
[bool, default=False] Whether to use mkl or not. If mkl is not installed or if this is
false, use the scipy splu solver instead.
mkl_max_iter_refine
[int] Specifies the the maximum number of iterative refinement steps that the MKL
PARDISO solver performs.
For a complete description, see iparm(7) in https://www.intel.com/content/www/us/
en/docs/onemkl/developer-reference-c/2023-0/pardiso-iparm-parameter.html
mkl_weighted_matching
[bool] MKL PARDISO can use a maximum weighted matching algorithm to permute
large elements close the diagonal. This strategy adds an additional level of reliability
to the factorization methods.
For a complete description, see iparm(12) in https://www.intel.com/content/www/us/
en/docs/onemkl/developer-reference-c/2023-0/pardiso-iparm-parameter.html
Returns
steady_state
[Qobj] The steady state density matrix of the system.
steady_ados
[HierarchyADOsState] The steady state of the full ADO hierarchy. A particular
ADO may be extracted from the full state by calling extract.
property sys_dims
Dimensions of the space that the system use, excluding any environment:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class HSolverDL(H_sys, coup_op, coup_strength, temperature, N_cut, N_exp, cut_freq, *,
bnd_cut_approx=False, options=None, combine=True)
A helper class for creating an HEOMSolver that is backwards compatible with the HSolverDL provided in
qutip.nonmarkov.heom in QuTiP 4.6 and below.
See HEOMSolver and DrudeLorentzBath for more descriptions of the underlying solver and bath construc-
tion.
An exact copy of the QuTiP 4.6 HSolverDL is provided in qutip.nonmarkov.dlheom_solver for cases
where the functionality of the older solver is required. The older solver will be completely removed in QuTiP
5.
Note: Unlike the version of HSolverDL in QuTiP 4.6, this solver supports supplying a time-dependent or
Liouvillian H_sys.
Note: For compatibility with HSolverDL in QuTiP 4.6 and below, the parameter N_exp specifying the
number of exponents to keep in the expansion of the bath correlation function is one more than the equivalent
Note: The stats and renorm arguments accepted in QuTiP 4.6 and below are no longer supported.
Parameters
H_sys
[Qobj or QobjEvo or list] The system Hamiltonian or Liouvillian. See HEOMSolver for
a complete description.
coup_op
[Qobj] Operator describing the coupling between system and bath. See parameter Q in
BosonicBath for a complete description.
coup_strength
[float] Coupling strength. Referred to as lam in DrudeLorentzBath .
temperature
[float] Bath temperature. Referred to as T in DrudeLorentzBath .
N_cut
[int] The maximum depth of the hierarchy. See max_depth in HEOMSolver for a full
description.
N_exp
[int] Number of exponential terms used to approximate the bath correlation functions.
The equivalent Nk in DrudeLorentzBath is one less than N_exp (see note above).
cut_freq
[float] Bath spectral density cutoff frequency. Referred to as gamma in
DrudeLorentzBath .
bnd_cut_approx
[bool] Use boundary cut off approximation. If true, the Matsubara terminator is added to
the system Liouvillian (and H_sys is promoted to a Liouvillian if it was a Hamiltonian).
Keyword only. Default: False.
options
[dict, optional] Generic solver options. If set to None the default options will be used.
Keyword only. Default: None.
combine
[bool, default: True] Whether to combine exponents with the same frequency (and cou-
pling operator). See BosonicBath.combine for details. Keyword only. Default: True.
“+” and “-” are fermionic bath exponents. These fermionic bath exponents must spec-
ify sigma_bar_k_offset which specifies the amount to add to k (the exponent index
within the bath of this exponent) to determine the k of the corresponding exponent with
the opposite sign (i.e. “-” or “+”).
dim
[int or None] The dimension (i.e. maximum number of excitations for this exponent).
Usually 2 for fermionic exponents or None (i.e. unlimited) for bosonic exponents.
Q
[Qobj] The coupling operator for this excitation mode.
vk
[complex] The frequency of the exponent of the excitation term.
ck
[complex] The coefficient of the excitation term.
ck2
[optional, complex] For exponents of type “RI” this is the coefficient of the term in the
imaginary expansion (and ck is the coefficient in the real expansion).
sigma_bar_k_offset
[optional, int] For exponents of type “+” this gives the offset (within the list of exponents
within the bath) of the corresponding “-” bath exponent. For exponents of type “-” it
gives the offset of the corresponding “+” exponent.
tag
[optional, str, tuple or any other object] A label for the exponent (often the name of the
bath). It defaults to None.
Attributes
fermionic
[bool] True if the type of the exponent is a Fermionic type (i.e. either “+” or “-”) and
False otherwise.
All of the parameters are also available as attributes.
types
alias of ExponentType
class Bath(exponents)
Represents a list of bath expansion exponents.
Parameters
exponents
[list of BathExponent] The exponents of the correlation function describing the bath.
Attributes
All of the parameters are available as attributes.
class BosonicBath(Q, ck_real, vk_real, ck_imag, vk_imag, combine=True, tag=None)
A helper class for constructing a bosonic bath from the expansion coefficients and frequencies for the real
and imaginary parts of the bath correlation function.
If the correlation functions C(t) is split into real and imaginary parts:
then:
Q
[Qobj] Operator describing the coupling between system and bath.
lam
[float] Coupling strength.
gamma
[float] Bath spectral density cutoff frequency.
T
[float] Bath temperature.
Nk
[int] Number of exponential terms used to approximate the bath correlation functions.
combine
[bool, default True] Whether to combine exponents with the same frequency (and cou-
pling operator). See BosonicBath.combine for details.
tag
[optional, str, tuple or any other object] A label for the bath exponents (for example,
the name of the bath). It defaults to None but can be set to help identify which bath an
exponent is from.
terminator()
Return the Matsubara terminator for the bath and the calculated approximation discrepancy.
Returns
delta: float
The approximation discrepancy. That is, the difference between the true correlation
function of the Drude-Lorentz bath and the sum of the Nk exponential terms is approx-
imately 2 * delta * dirac(t), where dirac(t) denotes the Dirac delta function.
terminator
[Qobj] The Matsubara terminator – i.e. a liouvillian term representing the contribution
to the system-bath dynamics of all exponential expansion terms beyond Nk. It should
be used by adding it to the system liouvillian (i.e. liouvillian(H_sys)).
class DrudeLorentzPadeBath(Q, lam, gamma, T, Nk, combine=True, tag=None)
A helper class for constructing a Padé expansion for a Drude-Lorentz bosonic bath from the bath parameters
(see parameters below).
A Padé approximant is a sum-over-poles expansion ( see https://en.wikipedia.org/wiki/Pad%C3%A9_
approximant).
The application of the Padé method to spectrum decompoisitions is described in “Padé spectrum decom-
positions of quantum distribution functions and optimal hierarchical equations of motion construction for
quantum open systems” [1].
The implementation here follows the approach in the paper.
[1] J. Chem. Phys. 134, 244106 (2011); https://doi.org/10.1063/1.3602466
This is an alternative to the DrudeLorentzBath which constructs a simpler exponential expansion.
Parameters
Q
[Qobj] Operator describing the coupling between system and bath.
lam
[float] Coupling strength.
gamma
[float] Bath spectral density cutoff frequency.
T
[float] Bath temperature.
Nk
[int] Number of Padé exponentials terms used to approximate the bath correlation func-
tions.
combine
[bool, default True] Whether to combine exponents with the same frequency (and cou-
pling operator). See BosonicBath.combine for details.
tag
[optional, str, tuple or any other object] A label for the bath exponents (for example,
the name of the bath). It defaults to None but can be set to help identify which bath an
exponent is from.
terminator()
Return the Padé terminator for the bath and the calculated approximation discrepancy.
Returns
delta: float
The approximation discrepancy. That is, the difference between the true correlation
function of the Drude-Lorentz bath and the sum of the Nk exponential terms is approx-
imately 2 * delta * dirac(t), where dirac(t) denotes the Dirac delta function.
terminator
[Qobj] The Padé terminator – i.e. a liouvillian term representing the contribution to
the system-bath dynamics of all exponential expansion terms beyond Nk. It should be
used by adding it to the system liouvillian (i.e. liouvillian(H_sys)).
class UnderDampedBath(Q, lam, gamma, w0, T, Nk, combine=True, tag=None)
A helper class for constructing an under-damped bosonic bath from the bath parameters (see parameters
below).
Parameters
Q
[Qobj] Operator describing the coupling between system and bath.
lam
[float] Coupling strength.
gamma
[float] Bath spectral density cutoff frequency.
w0
[float] Bath spectral density resonance frequency.
T
[float] Bath temperature.
Nk
[int] Number of exponential terms used to approximate the bath correlation functions.
combine
[bool, default True] Whether to combine exponents with the same frequency (and cou-
pling operator). See BosonicBath.combine for details.
tag
[optional, str, tuple or any other object] A label for the bath exponents (for example,
the name of the bath). It defaults to None but can be set to help identify which bath an
exponent is from.
where the expansions above define the coeffiients ck and the frequencies vk.
Parameters
Q
[Qobj] The coupling operator for the bath.
ck_plus
[list of complex] The coefficients of the expansion terms for the + part of the correlation
function. The corresponding frequencies are passed as vk_plus.
vk_plus
[list of complex] The frequencies (exponents) of the expansion terms for the + part of
the correlation function. The corresponding ceofficients are passed as ck_plus.
ck_minus
[list of complex] The coefficients of the expansion terms for the - part of the correlation
function. The corresponding frequencies are passed as vk_minus.
vk_minus
[list of complex] The frequencies (exponents) of the expansion terms for the - part of
the correlation function. The corresponding ceofficients are passed as ck_minus.
tag
[optional, str, tuple or any other object] A label for the bath exponents (for example,
the name of the bath). It defaults to None but can be set to help identify which bath an
exponent is from.
class LorentzianBath(Q, gamma, w, mu, T, Nk, tag=None)
A helper class for constructing a Lorentzian fermionic bath from the bath parameters (see parameters below).
Note: This Matsubara expansion used in this bath converges very slowly and Nk > 20 may be required to
get good convergence. The Padé expansion used by LorentzianPadeBath converges much more quickly.
Parameters
Q
[Qobj] Operator describing the coupling between system and bath.
gamma
[float] The coupling strength between the system and the bath.
w
[float] The width of the environment.
mu
[float] The chemical potential of the bath.
T
[float] Bath temperature.
Nk
[int] Number of exponential terms used to approximate the bath correlation functions.
tag
[optional, str, tuple or any other object] A label for the bath exponents (for example,
the name of the bath). It defaults to None but can be set to help identify which bath an
exponent is from.
exponents
[list of BathExponent] The exponents of the correlation function describing the bath or
baths.
max_depth
[int] The maximum depth of the hierarchy (i.e. the maximum sum of “excitations” in
the hierarchy ADO labels or maximum ADO level).
Attributes
exponents
[list of BathExponent] The exponents of the correlation function describing the bath or
baths.
max_depth
[int] The maximum depth of the hierarchy (i.e. the maximum sum of “excitations” in
the hierarchy ADO labels).
dims
[list of int] The dimensions of each exponent within the bath(s).
vk
[list of complex] The frequency of each exponent within the bath(s).
ck
[list of complex] The coefficient of each exponent within the bath(s).
ck2: list of complex
For exponents of type “RI”, the coefficient of the exponent within the imaginary expan-
sion. For other exponent types, the entry is None.
sigma_bar_k_offset: list of int
For exponents of type “+” or “-” the offset within the list of modes of the corresponding
“-” or “+” exponent. For other exponent types, the entry is None.
labels: list of tuples
A list of the ADO labels within the hierarchy.
exps(label)
Converts an ADO label into a tuple of exponents, with one exponent for each “excitation” within the
label.
The number of exponents returned is always equal to the level of the label within the hierarchy (i.e. the
sum of the indices within the label).
Parameters
label
[tuple] The ADO label to convert to a list of exponents.
Returns
tuple of BathExponent
A tuple of BathExponents.
Examples
Notes
This implementation of the .idx(...) method is just for reference and documentation. To avoid the
cost of a Python function call, it is replaced with self._label_idx.__getitem__ when the instance
is created.
next(label, k)
Return the ADO label with one more excitation in the k’th exponent dimension or None if adding the
excitation would exceed the dimension or maximum depth of the hierarchy.
Parameters
label
[tuple] The ADO label to add an excitation to.
k
[int] The exponent to add the excitation to.
Returns
tuple or None
The next label.
prev(label, k)
Return the ADO label with one fewer excitation in the k’th exponent dimension or None if the label
has no exciations in the k’th exponent.
Parameters
label
[tuple] The ADO label to remove the excitation from.
k
[int] The exponent to remove the excitation from.
Returns
tuple or None
The previous label.
class HierarchyADOsState(rho, ados, ado_state)
Provides convenient access to the full hierarchy ADO state at a particular point in time, t.
Parameters
rho
[Qobj] The current state of the system (i.e. the 0th component of the hierarchy).
ados
[HierarchyADOs] The description of the hierarchy.
ado_state
[numpy.array] The full state of the hierarchy.
Attributes
rho
[Qobj] The system state.
In addition, all of the attributes of the hierarchy description,
i.e. ``HierarchyADOs``, are provided directly on this class for
convenience. E.g. one can access ``.labels``, or ``.exponents`` or
call ``.idx(label)`` directly.
See :class:`HierarchyADOs` for a full list of the available attributes
and methods.
extract(idx_or_label)
Extract a Qobj representing the specified ADO from a full representation of the ADO states.
Parameters
idx
[int or label] The index of the ADO to extract. If an ADO label, e.g. (0, 1, 0, ...)
is supplied instead, then the ADO is extracted by label instead.
Returns
Qobj
A Qobj representing the state of the specified ADO.
class HEOMResult(e_ops, options: ResultOptions, *, solver=None, stats=None, **kw)
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
raw_data
[bool, default][False] If True, the raw matrix will be passed instead of a Qobj. For
density matrices, the matrices can be column stacked or square depending on the inte-
gration method.
classmethod WienerFeedback(default=None)
Wiener function of the trajectory argument for time dependent systems.
When used as an args:
QobjEvo([op, func], args={"W": SMESolver.WienerFeedback()})
The func will receive a function as W that return an array of wiener processes values at t. The wiener
process for the i-th sc_ops is the i-th element for homodyne detection and the (2i, 2i+1) pairs of process
in heterodyne detection. The process is a step function with step of length options["dt"].
Note: WienerFeedback can’t be added to a running solver when updating arguments between steps:
solver.step(..., args={}).
Parameters
default
[callable, optional] Default function used outside the solver. When not passed, a func-
tion returning np.array([0]) is used.
property options
Options for stochastic solver:
store_final_state: bool, default: False
Whether or not to store the final state of the evolution in the result class.
store_states: None, bool, default: None
Whether or not to store the state vectors or density matrices. On None the states will be saved if
no expectation operators are given.
store_measurement: bool, default: False
Whether to store the measurement for each trajectories. Storing measurements will also store the
wiener process, or brownian noise for each trajectories.
progress_bar: str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}, default: “text”
How to present the solver progress. ‘tqdm’ uses the python module of the same name and raise an
error if not installed. Empty string or False will disable the bar.
progress_kwargs: dict, default: {“chunk_size”:10}
Arguments to pass to the progress_bar. Qutip’s bars use chunk_size.
keep_runs_results: bool, default: False
Whether to store results from all trajectories or just store the averages.
normalize_output: bool
Normalize output state to hide ODE numerical errors.
method: str, default: “platen”
Which differential equation integration method to use.
map: str {“serial”, “parallel”, “loky”, “mpi”}, default: “serial”
How to run the trajectories. “parallel” uses the multiprocessing module to run in parallel while
“loky” and “mpi” use the “loky” and “mpi4py” modules to do so.
state
[Qobj] Initial state of the evolution.
t0
[double] Initial time of the evolution.
seed
[int, SeedSequence, list, optional] Seed for the random number generator. It can be
a single seed used to spawn seeds for each trajectory or a list of seed, one for each
trajectory.
Notes
When using step evolution, only one trajectory can be computed at once.
step(t, *, args=None, copy=True)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
args
[dict, optional] Update the args of the system. The change is effective from the be-
ginning of the interval. Changing args can slow the evolution.
copy
[bool, default: True] Whether to return a copy of the data or the data in the ODE solver.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
class SSESolver(H, sc_ops, heterodyne, *, c_ops=(), options=None)
Stochastic Schrodinger Equation Solver.
Parameters
H
[Qobj, QobjEvo, QobjEvo compatible format.] System Hamiltonian as a Qobj or Qob-
jEvo for time-dependent Hamiltonians. List of [Qobj, Coefficient] or callable that
can be made into QobjEvo are also accepted.
c_ops
[list of (QobjEvo, QobjEvo compatible format)] Deterministic collapse operator which
will contribute with a standard Lindblad type of dissipation.
sc_ops
[list of (QobjEvo, QobjEvo compatible format)] List of stochastic collapse operators.
heterodyne
[bool, default: False] Whether to use heterodyne or homodyne detection.
options
[dict, optional] Options for the solver, see SSESolver.options and SIntegrator for a
list of all options.
classmethod ExpectFeedback(operator, default=0.0)
Expectation value of the instantaneous state of the evolution to be used by a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"E0": Solver.ExpectFeedback(oper)})
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
raw_data
[bool, default][False] If True, the raw matrix will be passed instead of a Qobj. For
density matrices, the matrices can be column stacked or square depending on the inte-
gration method.
classmethod WienerFeedback(default=None)
Wiener function of the trajectory argument for time dependent systems.
When used as an args:
QobjEvo([op, func], args={"W": SMESolver.WienerFeedback()})
The func will receive a function as W that return an array of wiener processes values at t. The wiener
process for the i-th sc_ops is the i-th element for homodyne detection and the (2i, 2i+1) pairs of process
in heterodyne detection. The process is a step function with step of length options["dt"].
Note: WienerFeedback can’t be added to a running solver when updating arguments between steps:
solver.step(..., args={}).
Parameters
default
[callable, optional] Default function used outside the solver. When not passed, a func-
tion returning np.array([0]) is used.
property options
Options for stochastic solver:
store_final_state: bool, default: False
Whether or not to store the final state of the evolution in the result class.
store_states: None, bool, default: None
Whether or not to store the state vectors or density matrices. On None the states will be saved if
no expectation operators are given.
target_tol
[{float, tuple, list}, optional] Target tolerance of the evolution. The evolution will com-
pute trajectories until the error on the expectation values is lower than this tolerance.
The maximum number of trajectories employed is given by ntraj. The error is com-
puted using jackknife resampling. target_tol can be an absolute tolerance or a pair
of absolute and relative tolerance, in that order. Lastly, it can be a list of pairs of (atol,
rtol) for each e_ops.
seeds
[{int, SeedSequence, list}, optional] Seed or list of seeds for each trajectories.
Returns
results
[MultiTrajResult] Results of the evolution. States and/or expect will be saved. You
can control the saved data in the options.
start(state, t0, seed=None)
Set the initial state and time for a step evolution.
Parameters
state
[Qobj] Initial state of the evolution.
t0
[double] Initial time of the evolution.
seed
[int, SeedSequence, list, optional] Seed for the random number generator. It can be
a single seed used to spawn seeds for each trajectory or a list of seed, one for each
trajectory.
Notes
When using step evolution, only one trajectory can be computed at once.
step(t, *, args=None, copy=True)
Evolve the state to t and return the state as a Qobj.
Parameters
t
[double] Time to evolve to, must be higher than the last call.
args
[dict, optional] Update the args of the system. The change is effective from the be-
ginning of the interval. Changing args can slow the evolution.
copy
[bool, default: True] Whether to return a copy of the data or the data in the ODE solver.
property sys_dims
Dimensions of the space that the system use:
qutip.basis(sovler.dims) will create a state with proper dimensions for this solver.
5.1.9 Integrator
interpolate
[bool, default: True] Whether to use interpolation step, faster most of the time.
class IntegratorDiag(system, options)
Integrator solving the ODE by diagonalizing the system and solving analytically. It can only solve constant
system and has a long preparation time, but the integration is fast.
Usable with method="diag"
property options
Supported options by “diag” method:
eigensolver_dtype
[str, default: “dense”] Qutip data type {“dense”, “csr”, etc.} to use when computing the eigenstates.
The dense eigen solver is usually faster and more stable.
class IntegratorKrylov(system, options)
Evolve the state vector (“psi0”) finding an approximation for the time evolution operator of Hamiltonian
(“H”) by obtaining the projection of the time evolution operator on a set of small dimensional Krylov sub-
spaces (m << dim(H)).
property options
Supported options by krylov method:
atol
[float, default: 1e-7] Absolute tolerance.
nsteps
[int, default: 100] Max. number of internal steps/call.
min_step, max_step
[float, default: (1e-5, 1e5)] Minimum and maximum step size.
krylov_dim: int, default: 0
Dimension of Krylov approximation subspaces used for the time evolution approximation. If
the defaut 0 is given, the dimension is calculated from the system size N, using min(int((N +
100)**0.5), N-1).
sub_system_tol: float, default: 1e-7
Tolerance to detect a happy breakdown. A happy breakdown occurs when the initial ket is in a
subspace of the Hamiltonian smaller than krylov_dim.
always_compute_step: bool, default: False
If True, the step length is computed each time a new Krylov subspace is computed. Otherwise it
is computed only once when creating the integrator.
Notes
This method should be used with very small dt. Unlike other methods that will return unphysical state
(negative eigenvalues, Nans) when the time step is too large, this method will return state that seems normal.
property options
Supported options by Rouchon Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-7] Relative tolerance.
class EulerSODE(rhs, options)
A simple generalization of the Euler method for ordinary differential equations to stochastic differential
equations. Only solver which could take non-commuting sc_ops.
• Order: 0.5
property options
Supported options by Explicit Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Tolerance for the time steps.
class Milstein_SODE(rhs, options)
An order 1.0 strong Taylor scheme. Better approximate numerical solution to stochastic differential equa-
tions. See eq. (3.12) of chapter 10.3 of Peter E. Kloeden and Exkhard Platen, Numerical Solution of Stochas-
tic Differential Equations..
• Order strong 1.0
property options
Supported options by Explicit Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Tolerance for the time steps.
class Taylor1_5_SODE(rhs, options)
Order 1.5 strong Taylor scheme. Solver with more terms of the Ito-Taylor expansion. See eq. (4.6) of chapter
10.4 of Peter E. Kloeden and Exkhard Platen, Numerical Solution of Stochastic Differential Equations.
• Order strong 1.5
property options
Supported options by Order 1.5 strong Taylor Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Relative tolerance.
derr_dt
[float, default: 1e-6] Finite time difference used to compute the derrivative of the hamiltonian and
sc_ops.
tol
[float, default: 1e-10] Tolerance for the time steps.
class Explicit1_5_SODE(rhs, options)
Explicit order 1.5 strong schemes. Reproduce the order 1.5 strong Taylor scheme using finite difference
instead of derivatives. Slower than taylor15 but usable when derrivatives cannot be analytically obtained.
See eq. (2.13) of chapter 11.2 of Peter E. Kloeden and Exkhard Platen, Numerical Solution of Stochastic
Differential Equations.
• Order: strong 1.5
property options
Supported options by Explicit Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Tolerance for the time steps.
class PredCorr_SODE(rhs, options)
Generalization of the trapezoidal method to stochastic differential equations. More stable than explicit meth-
ods. See eq. (5.4) of chapter 15.5 of Peter E. Kloeden and Exkhard Platen, Numerical Solution of Stochastic
Differential Equations.
• Order strong 0.5, weak 1.0
• Codes to only correct the stochastic part (𝛼 = 0, 𝜂 = 1/2): 'pred-corr', 'predictor-corrector'
or 'pc-euler'
• Codes to correct both the stochastic and deterministic parts (𝛼 = 1/2, 𝜂 = 1/2): 'pc-euler-imp',
'pc-euler-2' or 'pred-corr-2'
property options
Supported options by Explicit Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Tolerance for the time steps.
alpha
[float, default: 0.] Implicit factor to the drift. eff_drift ~= drift(t) * (1-alpha) + drift(t+dt) * alpha
eta
[float, default: 0.5] Implicit factor to the diffusion. eff_diffusion ~= diffusion(t) * (1-eta) + diffu-
sion(t+dt) * eta
options
[dict] The options for this result class.
solver
[str or None] The name of the solver generating these results.
stats
[dict or None] The stats generated by the solver while producing these results. Note that
the solver may update the stats directly while producing results.
kw
[dict] Additional parameters specific to a result sub-class.
Attributes
times
[list] A list of the times at which the expectation values and states were recorded.
states
[list of Qobj] The state at each time t (if the recording of the state was requested).
final_state
[Qobj:] The final state (if the recording of the final state was requested).
expect
[list of arrays of expectation values] A list containing the values of each e_op. The list is
in the same order in which the e_ops were supplied and empty if no e_ops were given.
Each element is itself a list and contains the values of the corresponding e_op, with one
value for each time in .times.
The same lists of values may be accessed via the .e_data dictionary and the original
e_ops are available via the .e_ops attribute.
e_data
[dict] A dictionary containing the values of each e_op. If the e_ops were supplied as a
dictionary, the keys are the same as in that dictionary. Otherwise the keys are the index
of the e_op in the .expect list.
The lists of expectation values returned are the same lists as those returned by .expect.
e_ops
[dict] A dictionary containing the supplied e_ops as ExpectOp instances. The keys of
the dictionary are the same as for .e_data. Each value is object where .e_ops[k](t,
state) calculates the value of e_op k at time t and the given state, and .e_ops[k].
op is the original object supplied to create the e_op.
solver
[str or None] The name of the solver generating these results.
stats
[dict or None] The stats generated by the solver while producing these results.
options
[dict] The options for this result class.
class MultiTrajResult(e_ops, options: MultiTrajResultOptions, *, solver=None, stats=None, **kw)
Base class for storing results for solver using multiple trajectories.
Parameters
e_ops
[Qobj, QobjEvo, function or list or dict of these] The e_ops parameter defines the set
of values to record at each time step t. If an element is a Qobj or QobjEvo the value
recorded is the expectation value of that operator given the state at t. If the element is a
function, f, the value recorded is f(t, state).
The values are recorded in the .expect attribute of this result object. .expect is a list,
where each item contains the values of the corresponding e_op.
Function e_ops must return a number so the average can be computed.
options
[dict] The options for this result class.
solver
[str or None] The name of the solver generating these results.
stats
[dict or None] The stats generated by the solver while producing these results. Note that
the solver may update the stats directly while producing results.
kw
[dict] Additional parameters specific to a result sub-class.
Attributes
times
[list] A list of the times at which the expectation values and states were recorded.
average_states
[list of Qobj] States averages as density matrices.
runs_states
[list of list of Qobj] States of every runs as states[run][t].
final_state
[Qobj:] Runs final states if available, average otherwise.
runs_final_state
[list of Qobj] The final state for each trajectory (if the recording of the final state and
trajectories was requested).
average_expect
[list of array of expectation values] A list containing the values of each e_op averaged
over each trajectories. The list is in the same order in which the e_ops were supplied
and empty if no e_ops were given.
Each element is itself an array and contains the values of the corresponding e_op, with
one value for each time in .times.
std_expect
[list of array of expectation values] A list containing the standard derivation of each e_op
over each trajectories. The list is in the same order in which the e_ops were supplied
and empty if no e_ops were given.
Each element is itself an array and contains the values of the corresponding e_op, with
one value for each time in .times.
runs_expect
[list of array of expectation values] A list containing the values of each e_op for each
trajectories. The list is in the same order in which the e_ops were supplied and empty
if no e_ops were given. Only available if the storing of trajectories was requested.
The order of the elements is runs_expect[e_ops][trajectory][time].
Each element is itself an array and contains the values of the corresponding e_op, with
one value for each time in .times.
average_e_data
[dict] A dictionary containing the values of each e_op averaged over each trajectories.
If the e_ops were supplied as a dictionary, the keys are the same as in that dictionary.
Otherwise the keys are the index of the e_op in the .expect list.
The lists of expectation values returned are the same lists as those returned by .expect.
average_e_data
[dict] A dictionary containing the standard derivation of each e_op over each trajectories.
If the e_ops were supplied as a dictionary, the keys are the same as in that dictionary.
Otherwise the keys are the index of the e_op in the .expect list.
The lists of expectation values returned are the same lists as those returned by .expect.
runs_e_data
[dict] A dictionary containing the values of each e_op for each trajectories. If the e_ops
were supplied as a dictionary, the keys are the same as in that dictionary. Otherwise the
keys are the index of the e_op in the .expect list. Only available if the storing of
trajectories was requested.
The order of the elements is runs_expect[e_ops][trajectory][time].
The lists of expectation values returned are the same lists as those returned by .expect.
solver
[str or None] The name of the solver generating these results.
stats
[dict or None] The stats generated by the solver while producing these results.
options
[SolverResultsOptions] The options for this result class.
property average_final_state
Last states of each trajectories averaged into a density matrix.
property average_states
States averages as density matrices.
property final_state
Runs final states if available, average otherwise.
property runs_final_states
Last states of each trajectories.
property runs_states
States of every runs as states[run][t].
property states
Runs final states if available, average otherwise.
steady_state(N=0)
Average the states of the last N times of every runs as a density matrix. Should converge to the steady
state in the right circumstances.
Parameters
N
[int [optional]] Number of states from the end of tlist to average. Per default all
states will be averaged.
class McResult(e_ops, options: MultiTrajResultOptions, *, solver=None, stats=None, **kw)
Class for storing Monte-Carlo solver results.
Parameters
e_ops
[Qobj, QobjEvo, function or list or dict of these] The e_ops parameter defines the set
of values to record at each time step t. If an element is a Qobj or QobjEvo the value
recorded is the expectation value of that operator given the state at t. If the element is a
function, f, the value recorded is f(t, state).
The values are recorded in the .expect attribute of this result object. .expect is a list,
where each item contains the values of the corresponding e_op.
options
[SolverResultsOptions] The options for this result class.
solver
[str or None] The name of the solver generating these results.
stats
[dict] The stats generated by the solver while producing these results. Note that the
solver may update the stats directly while producing results. Must include a value for
“num_collapse”.
kw
[dict] Additional parameters specific to a result sub-class.
Attributes
collapse
[list] For each runs, a list of every collapse as a tuple of the time it happened and the
corresponding c_ops index.
property average_final_state
Last states of each trajectories averaged into a density matrix.
property average_states
States averages as density matrices.
property col_times
List of the times of the collapses for each runs.
property col_which
List of the indexes of the collapses for each runs.
property final_state
Runs final states if available, average otherwise.
property photocurrent
Average photocurrent or measurement of the evolution.
property runs_final_states
Last states of each trajectories.
property runs_photocurrent
Photocurrent or measurement of each runs.
property runs_states
States of every runs as states[run][t].
property states
Runs final states if available, average otherwise.
steady_state(N=0)
Average the states of the last N times of every runs as a density matrix. Should converge to the steady
state in the right circumstances.
Parameters
N
[int [optional]] Number of states from the end of tlist to average. Per default all
states will be averaged.
class NmmcResult(e_ops, options: MultiTrajResultOptions, *, solver=None, stats=None, **kw)
Class for storing the results of the non-Markovian Monte-Carlo solver.
Parameters
e_ops
[Qobj, QobjEvo, function or list or dict of these] The e_ops parameter defines the set
of values to record at each time step t. If an element is a Qobj or QobjEvo the value
recorded is the expectation value of that operator given the state at t. If the element is a
function, f, the value recorded is f(t, state).
The values are recorded in the .expect attribute of this result object. .expect is a list,
where each item contains the values of the corresponding e_op.
options
[SolverResultsOptions] The options for this result class.
solver
[str or None] The name of the solver generating these results.
stats
[dict] The stats generated by the solver while producing these results. Note that the
solver may update the stats directly while producing results. Must include a value for
“num_collapse”.
kw
[dict] Additional parameters specific to a result sub-class.
Attributes
average_trace
[list] The average trace (i.e., averaged over all trajectories) at each time.
std_trace
[list] The standard deviation of the trace at each time.
runs_trace
[list of lists] For each recorded trajectory, the trace at each time. Only present if
keep_runs_results is set in the options.
property average_final_state
Last states of each trajectories averaged into a density matrix.
property average_states
States averages as density matrices.
property col_times
List of the times of the collapses for each runs.
property col_which
List of the indexes of the collapses for each runs.
property final_state
Runs final states if available, average otherwise.
property photocurrent
Average photocurrent or measurement of the evolution.
property runs_final_states
Last states of each trajectories.
property runs_photocurrent
Photocurrent or measurement of each runs.
property runs_states
States of every runs as states[run][t].
property states
Runs final states if available, average otherwise.
steady_state(N=0)
Average the states of the last N times of every runs as a density matrix. Should converge to the steady
state in the right circumstances.
Parameters
N
[int [optional]] Number of states from the end of tlist to average. Per default all
states will be averaged.
property trace
Refers to average_trace or runs_trace, depending on whether keep_runs_results is set in the
options.
Examples
Attributes
N: int
The number of two-level systems.
hamiltonian
[Qobj] A Hamiltonian in the Dicke basis.
The matrix dimensions are (nds, nds), with nds being the number of Dicke states. The
Hamiltonian can be built with the operators given by the jspin function in the “dicke”
basis.
emission: float
Incoherent emission coefficient (also nonradiative emission). default: 0.0
dephasing: float
Local dephasing coefficient. default: 0.0
pumping: float
Incoherent pumping coefficient. default: 0.0
collective_emission: float
Collective (superradiant) emmission coefficient. default: 0.0
collective_dephasing: float
Collective dephasing coefficient. default: 0.0
collective_pumping: float
Collective pumping coefficient. default: 0.0
nds: int
The number of Dicke states.
dshape: tuple
The shape of the Hilbert space in the Dicke or uncoupled basis. default: (nds, nds).
c_ops()
Build collapse operators in the full Hilbert space 2^N.
Returns
c_ops_list: list
The list with the collapse operators in the 2^N Hilbert space.
coefficient_matrix()
Build coefficient matrix for ODE for a diagonal problem.
Returns
M: ndarray
The matrix M of the coefficients for the ODE dp/dt = Mp. p is the vector of the diagonal
matrix elements of the density matrix rho in the Dicke basis.
lindbladian()
Build the Lindbladian superoperator of the dissipative dynamics.
Returns
lindbladian
[Qobj] The Lindbladian matrix as a qutip.Qobj.
liouvillian()
Build the total Liouvillian using the Dicke basis.
Returns
liouv
[Qobj] The Liouvillian matrix for the system.
pisolve(initial_state, tlist)
Solve for diagonal Hamiltonians and initial states faster.
Parameters
initial_state
[Qobj] An initial state specified as a density matrix of qutip.Qbj type.
tlist: ndarray
A 1D numpy array of list of timesteps to integrate
Returns
result: list
A dictionary of the type qutip.piqs.Result which holds the results of the evolution.
class Pim(N, emission=0.0, dephasing=0, pumping=0, collective_emission=0, collective_pumping=0,
collective_dephasing=0)
The Permutation Invariant Matrix class.
Initialize the class with the parameters for generating a Permutation Invariant matrix which evolves a given
diagonal initial state p as:
dp/dt = Mp
Parameters
N: int
The number of two-level systems.
emission: float
Incoherent emission coefficient (also nonradiative emission). default: 0.0
dephasing: float
Local dephasing coefficient. default: 0.0
pumping: float
Incoherent pumping coefficient. default: 0.0
collective_emission: float
Collective (superradiant) emmission coefficient. default: 0.0
collective_pumping: float
Collective pumping coefficient. default: 0.0
collective_dephasing: float
Collective dephasing coefficient. default: 0.0
Attributes
N: int
The number of two-level systems.
emission: float
Incoherent emission coefficient (also nonradiative emission). default: 0.0
dephasing: float
Local dephasing coefficient. default: 0.0
pumping: float
Incoherent pumping coefficient. default: 0.0
collective_emission: float
Collective (superradiant) emmission coefficient. default: 0.0
collective_dephasing: float
Collective dephasing coefficient. default: 0.0
collective_pumping: float
Collective pumping coefficient. default: 0.0
M: dict
A nested dictionary of the structure {row: {col: val}} which holds non zero elements of
the matrix M
calculate_j_m(dicke_row, dicke_col)
Get the value of j and m for the particular Dicke space element.
Parameters
dicke_row, dicke_col: int
The row and column from the Dicke space matrix
Returns
j, m: float
The j and m values.
calculate_k(dicke_row, dicke_col)
Get k value from the current row and column element in the Dicke space.
Parameters
dicke_row, dicke_col: int
The row and column from the Dicke space matrix.
Returns
——-
k: int
The row index for the matrix M for given Dicke space element.
coefficient_matrix()
Generate the matrix M governing the dynamics for diagonal cases.
If the initial density matrix and the Hamiltonian is diagonal, the evolution of the system is given by the
simple ODE: dp/dt = Mp.
isdicke(dicke_row, dicke_col)
Check if an element in a matrix is a valid element in the Dicke space. Dicke row: j value index. Dicke
column: m value index. The function returns True if the element exists in the Dicke space and False
otherwise.
Parameters
dicke_row, dicke_col
[int] Index of the element in Dicke space which needs to be checked
solve(rho0, tlist)
Solve the ODE for the evolution of diagonal states and Hamiltonians.
tau1(j, m)
Calculate coefficient matrix element relative to (j, m, m).
tau2(j, m)
Calculate coefficient matrix element relative to (j, m+1, m+1).
tau3(j, m)
Calculate coefficient matrix element relative to (j+1, m+1, m+1).
tau4(j, m)
Calculate coefficient matrix element relative to (j-1, m+1, m+1).
tau5(j, m)
Calculate coefficient matrix element relative to (j+1, m, m).
tau6(j, m)
Calculate coefficient matrix element relative to (j-1, m, m).
tau7(j, m)
Calculate coefficient matrix element relative to (j+1, m-1, m-1).
tau8(j, m)
Calculate coefficient matrix element relative to (j, m-1, m-1).
tau9(j, m)
Calculate coefficient matrix element relative to (j-1, m-1, m-1).
tau_valid(dicke_row, dicke_col)
Find the Tau functions which are valid for this value of (dicke_row, dicke_col) given the number of
TLS. This calculates the valid tau values and reurns a dictionary specifying the tau function name and
the value.
Parameters
dicke_row, dicke_col
[int] Index of the element in Dicke space which needs to be checked.
Returns
taus: dict
A dictionary of key, val as {tau: value} consisting of the valid taus for this row and
column of the Dicke space element.
d
[Distributions] A new instances of Distribution that describes the marginal distribution.
project(dim=0)
Calculate the projection (max value) distribution function along the dimension dim. Return a new
Distribution instance describing this reduced-dimensionality distribution.
Parameters
dim
[int] The dimension (coordinate index) along which to obtain the projected distribution.
Returns
d
[Distributions] A new instances of Distribution that describes the projection.
visualize(fig=None, ax=None, figsize=(8, 6), colorbar=True, cmap=None, style='colormap',
show_xlabel=True, show_ylabel=True)
Visualize the data of the distribution in 1D or 2D, depending on the dimensionality of the underlaying
distribution.
Parameters:
fig
[matplotlib Figure instance] If given, use this figure instance for the visualization,
ax
[matplotlib Axes instance] If given, render the visualization using this axis instance.
figsize
[tuple] Size of the new Figure instance, if one needs to be created.
colorbar: Bool
Whether or not the colorbar (in 2D visualization) should be used.
cmap: matplotlib colormap instance
If given, use this colormap for 2D visualizations.
style
[string] Type of visualization: ‘colormap’ (default) or ‘surface’.
Returns
fig, ax
[tuple] A tuple of matplotlib figure and axes instances.
5.2 Functions
Quantum States
n
[int or list of ints, optional (default 0 for all dimensions)] Integer corresponding to de-
sired number state, defaults to 0 for all dimensions if omitted. The shape must match
dimensions, e.g. if dimensions is a list, then n must either be omitted or a list of
equal length.
offset
[int or list of ints, optional (default 0 for all dimensions)] The lowest number state that is
included in the finite number state representation of the state in the relevant dimension.
dtype
[type or str, optional] storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
state
[Qobj] Qobj representing the requested number state |n>.
Notes
Examples
>>> basis(5,2)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[ 0.+0.j]
[ 0.+0.j]
[ 1.+0.j]
[ 0.+0.j]
[ 0.+0.j]]
>>> basis([2,2,2], [0,1,0])
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket
Qobj data =
[[0.]
[0.]
[1.]
[0.]
[0.]
[0.]
[0.]
[0.]]
bell_state(state='00', *, dtype=None)
Parameters
state
[str [‘00’, ‘01’, ‘10’, ‘11’]] Which bell state to return
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
Bell_state
[qobj] Bell state
bra(seq, dim=2, *, dtype=None)
Produces a multiparticle bra state for a list or string, where each element stands for state of the respective
particle.
Parameters
seq
[str / list of ints or characters] Each element defines state of the respective particle. (e.g.
[1,1,0,1] or a string “1101”). For qubits it is also possible to use the following conven-
tions:
• ‘g’/’e’ (ground and excited state)
• ‘u’/’d’ (spin up and down)
• ‘H’/’V’ (horizontal and vertical polarization)
Note: for dimension > 9 you need to use a list.
dim
[int (default: 2) / list of ints] Space dimension for each particle: int if there are the same,
list if they are different.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
bra
[qobj]
Examples
>>> bra("10")
Quantum object: dims = [[1, 1], [2, 2]], shape = [1, 4], type = bra
Qobj data =
[[ 0. 0. 1. 0.]]
>>> bra("Hue")
Quantum object: dims = [[1, 1, 1], [2, 2, 2]], shape = [1, 8], type = bra
Qobj data =
[[ 0. 1. 0. 0. 0. 0. 0. 0.]]
>>> bra("12", 3)
Quantum object: dims = [[1, 1], [3, 3]], shape = [1, 9], type = bra
Qobj data =
[[ 0. 0. 0. 0. 0. 1. 0. 0. 0.]]
Notes
Select method ‘operator’ (default) or ‘analytic’. With the ‘operator’ method, the coherent state is generated
by displacing the vacuum state using the displacement operator defined in the truncated Hilbert space of size
‘N’. This method guarantees that the resulting state is normalized. With ‘analytic’ method the coherent state
is generated using the analytical formula for the coherent state coefficients in the Fock basis. This method
does not guarantee that the state is normalized if truncated to a small number of Fock states, but would in
that case give more accurate coefficients.
Examples
>>> coherent(5,0.25j)
Quantum object: dims = [[5], [1]], shape = [5, 1], type = ket
Qobj data =
[[ 9.69233235e-01+0.j ]
[ 0.00000000e+00+0.24230831j]
[ -4.28344935e-02+0.j ]
[ 0.00000000e+00-0.00618204j]
[ 7.80904967e-04+0.j ]]
Notes
Select method ‘operator’ (default) or ‘analytic’. With the ‘operator’ method, the coherent density matrix is
generated by displacing the vacuum state using the displacement operator defined in the truncated Hilbert
space of size ‘N’. This method guarantees that the resulting density matrix is normalized. With ‘analytic’
method the coherent density matrix is generated using the analytical formula for the coherent state coefficients
in the Fock basis. This method does not guarantee that the state is normalized if truncated to a small number
of Fock states, but would in that case give more accurate coefficients.
Examples
>>> coherent_dm(3,0.25j)
Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
Qobj data =
[[ 0.93941695+0.j 0.00000000-0.23480733j -0.04216943+0.j ]
[ 0.00000000+0.23480733j 0.05869011+0.j 0.00000000-0.01054025j]
[-0.04216943+0.j 0.00000000+0.01054025j 0.00189294+0.j ]]
Examples
>>> fock(4,3)
Quantum object: dims = [[4], [1]], shape = [4, 1], type = ket
Qobj data =
[[ 0.+0.j]
[ 0.+0.j]
[ 0.+0.j]
[ 1.+0.j]]
offset
[int or list of ints, default: 0 for all dimensions] The lowest number state that is included
in the finite number state representation of the state in the relevant dimension.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
dm
[qobj] Density matrix representation of Fock state.
Examples
>>> fock_dm(3,1)
Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
Qobj data =
[[ 0.+0.j 0.+0.j 0.+0.j]
[ 0.+0.j 1.+0.j 0.+0.j]
[ 0.+0.j 0.+0.j 0.+0.j]]
ghz_state(N_qubit, *, dtype=None)
Parameters
N_qubit
[int] Number of qubits in state
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
G
[qobj] N-qubit GHZ-state
ket
[qobj]
Examples
>>> ket("10")
Quantum object: dims = [[2, 2], [1, 1]], shape = [4, 1], type = ket
Qobj data =
[[ 0.]
[ 0.]
[ 1.]
[ 0.]]
>>> ket("Hue")
Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = [8, 1], type = ket
Qobj data =
[[ 0.]
[ 1.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]]
>>> ket("12", 3)
Quantum object: dims = [[3, 3], [1, 1]], shape = [9, 1], type = ket
Qobj data =
[[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 1.]
[ 0.]
[ 0.]
[ 0.]]
ket2dm(Q)
Takes input ket or bra vector and returns density matrix formed by outer product. This is completely identical
to calling Q.proj().
Parameters
Q
[Qobj] Ket or bra type quantum object.
Returns
dm
[Qobj] Density matrix formed by outer product of Q.
Examples
>>> x=basis(3,2)
>>> ket2dm(x)
Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
Qobj data =
[[ 0.+0.j 0.+0.j 0.+0.j]
[ 0.+0.j 0.+0.j 0.+0.j]
[ 0.+0.j 0.+0.j 1.+0.j]]
maximally_mixed_dm(dimensions, *, dtype=None)
Returns the maximally mixed density matrix for a Hilbert space of dimension N.
Parameters
dimensions
[int or list of ints, Space] Number of basis states in Hilbert space. If a list, then the
resultant object will be a tensor product over spaces with those dimensions.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
dm
[Qobj] Thermal state density matrix.
phase_basis(N, m, phi0=0, *, dtype=None)
Basis vector for the mth phase of the Pegg-Barnett phase operator.
Parameters
N
[int] Number of basis states in Hilbert space.
m
[int] Integer corresponding to the mth discrete phase phi_m = phi0 + 2 * pi * m
/ N
phi0
[float, default: 0] Reference phase angle.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
state
[qobj] Ket vector for mth Pegg-Barnett phase operator basis state.
Notes
The Pegg-Barnett basis states form a complete set over the truncated Hilbert space.
projection(dimensions, n, m, offset=None, *, dtype=None)
The projection operator that projects state |𝑚⟩ on state |𝑛⟩.
Parameters
dimensions
[int or list of ints, Space] Number of basis states in Hilbert space. If a list, then the
resultant object will be a tensor product over spaces with those dimensions.
n, m
[int] The number states in the projection.
offset
[int, default: 0] The lowest number state that is included in the finite number state rep-
resentation of the projector.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Requested projection operator.
qutrit_basis(*, dtype=None)
Basis states for a three level system (qutrit)
dtype
[type or str, optional] storage representation. Any data-layer known to qutip.data.to is accepted.
Returns
qstates
[array] Array of qutrit basis vectors
singlet_state(*, dtype=None)
Returns the two particle singlet-state:
1
|𝑆⟩ = √ (|01⟩ − |10⟩)
2
that is identical to the fourth bell state.
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
Bell_state
[qobj] |𝐵11 ⟩ Bell state
spin_coherent(j, theta, phi, type='ket', *, dtype=None)
Generate the coherent spin state |𝜃, 𝜑⟩.
Parameters
j
[float] The spin of the state.
theta
[float] Angle from z axis.
phi
[float] Angle from x axis.
type
[string {‘ket’, ‘bra’, ‘dm’}, default: ‘ket’] Type of state to generate.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
state
[qobj] Qobj quantum object for spin coherent state
spin_state(j, m, type='ket', *, dtype=None)
Generates the spin state |𝑗, 𝑚⟩, i.e. the eigenstate of the spin-j Sz operator with eigenvalue m.
Parameters
j
[float] The spin of the state ().
m
[int] Eigenvalue of the spin-j Sz operator.
type
[string {‘ket’, ‘bra’, ‘dm’}, default: ‘ket’] Type of state to generate.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
state
[qobj] Qobj quantum object for spin state
state_index_number(dims, index)
Return a quantum number representation given a state index, for a system of composite structure defined by
dims.
Example
Parameters
dims
[list or array] The quantum state dimensions array, as it would appear in a Qobj.
index
[integer] The index of the state in standard enumeration ordering.
Returns
state
[tuple] The state number tuple corresponding to index index in standard enumeration
ordering.
state_number_enumerate(dims, excitations=None)
An iterator that enumerates all the state number tuples (quantum numbers of the form (n1, n2, n3, . . . )) for
a system with dimensions given by dims.
Example
Parameters
dims
[list or array] The quantum state dimensions array, as it would appear in a Qobj.
excitations
[integer, optional] Restrict state space to states with excitation numbers below or equal
to this value.
Returns
state_number
[tuple] Successive state number tuples that can be used in loops and other iterations,
using standard state enumeration by definition.
state_number_index(dims, state)
Return the index of a quantum state corresponding to state, given a system with dimensions given by dims.
Example
Parameters
dims
[list or array] The quantum state dimensions array, as it would appear in a Qobj.
state
[list] State number array.
Returns
idx
[int] The index of the state given by state in standard enumeration ordering.
Example
Parameters
dims
[list or array] The quantum state dimensions array, as it would appear in a Qobj.
state
[list] State number array.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
state
[Qobj] The state as a Qobj instance.
Notes
The ‘operator’ method (default) generates the thermal state using the truncated number operator num(N).
This is the method that should be used in computations. The ‘analytic’ method uses the analytic coeffi-
cients derived in an infinite Hilbert space. The analytic form is not necessarily normalized, if truncated too
aggressively.
Examples
>>> thermal_dm(5, 1)
Quantum object: dims = [[5], [5]], shape = [5, 5], type = oper, isHerm = True
Qobj data =
[[ 0.51612903 0. 0. 0. 0. ]
[ 0. 0.25806452 0. 0. 0. ]
[ 0. 0. 0.12903226 0. 0. ]
[ 0. 0. 0. 0.06451613 0. ]
[ 0. 0. 0. 0. 0.03225806]]
triplet_states(*, dtype=None)
Returns a list of the two particle triplet-states:
1
|𝑇1 ⟩ = |11⟩|𝑇2 ⟩ = √ (|01⟩ + |10⟩)|𝑇3 ⟩ = |00⟩
2
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
trip_states
[list] 2 particle triplet states
w_state(N_qubit, *, dtype=None)
Parameters
N_qubit
[int] Number of qubits in state
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
W
[Qobj] N-qubit W-state
zero_ket(dimensions, *, dtype=None)
Creates the zero ket vector with shape Nx1 and dimensions dims.
Parameters
dimensions
[int or list of ints, Space] Number of basis states in Hilbert space. If a list, then the
resultant object will be a tensor product over spaces with those dimensions.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
zero_ket
[qobj] Zero ket on given Hilbert space.
Quantum Operators
This module contains functions for generating Qobj representation of a variety of commonly occuring quantum
operators.
charge(Nmax, Nmin=None, frac=1, *, dtype=None)
Generate the diagonal charge operator over charge states from Nmin to Nmax.
Parameters
Nmax
[int] Maximum charge state to consider.
Nmin
[int, default: -Nmax] Lowest charge state to consider.
frac
[float, default: 1] Specify fractional charge if needed.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
C
[Qobj] Charge operator over [Nmin, Nmax].
Notes
N
[int] Number of basis states in the Hilbert space.
offset
[int, default: 0] The lowest number state that is included in the finite number state rep-
resentation of the operator.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Qobj for raising operator.
Examples
>>> create(4)
Quantum object: dims=[[4], [4]], shape=(4, 4), type='oper', isherm=False
Qobj data =
[[ 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j]
[ 1.00000000+0.j 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j]
[ 0.00000000+0.j 1.41421356+0.j 0.00000000+0.j 0.00000000+0.j]
[ 0.00000000+0.j 0.00000000+0.j 1.73205081+0.j 0.00000000+0.j]]
Examples
>>> destroy(4)
Quantum object: dims=[[4], [4]], shape=(4, 4), type='oper', isherm=False
Qobj data =
[[ 0.00000000+0.j 1.00000000+0.j 0.00000000+0.j 0.00000000+0.j]
[ 0.00000000+0.j 0.00000000+0.j 1.41421356+0.j 0.00000000+0.j]
[ 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j 1.73205081+0.j]
[ 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j 0.00000000+0.j]]
N
[int] Number of basis states in the Hilbert space.
alpha
[float/complex] Displacement amplitude.
offset
[int, default: 0] The lowest number state that is included in the finite number state rep-
resentation of the operator.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Displacement operator.
Examples
>>> displace(4,0.25)
Quantum object: dims = [[4], [4]], shape = [4, 4], type = oper, isHerm = False
Qobj data =
[[ 0.96923323+0.j -0.24230859+0.j 0.04282883+0.j -0.00626025+0.j]
[ 0.24230859+0.j 0.90866411+0.j -0.33183303+0.j 0.07418172+0.j]
[ 0.04282883+0.j 0.33183303+0.j 0.84809499+0.j -0.41083747+0.j]
[ 0.00626025+0.j 0.07418172+0.j 0.41083747+0.j 0.90866411+0.j]]
Examples
>>> fcreate(2)
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm␣
˓→= False
Qobj data =
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[1. 0. 0. 0.]
[0. 1. 0. 0.]]
Examples
>>> fdestroy(2)
Quantum object: dims=[[2 2], [2 2]], shape=(4, 4), type='oper', isherm=False
Qobj data =
[[0. 0. 1. 0.]
[0. 0. 0. 1.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
identity(dimensions, *, dtype=None)
Identity operator.
Parameters
dimensions
[(int) or (list of int) or (list of list of int), Space] Number of basis states in the Hilbert
space. If provided as a list of ints, then the dimension is the product over this list, but
the dims property of the new Qobj are set to this list. This can produce either oper or
super depending on the passed dimensions.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Identity operator Qobj.
Examples
>>> qeye(3)
Quantum object: dims = [[3], [3]], shape = (3, 3), type = oper, isherm = True
Qobj data =
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
>>> qeye([2,2])
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm =␣
˓→True
Qobj data =
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
Examples
>>> jmat(1)
[ Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
Qobj data =
[[ 0. 0.70710678 0. ]
[ 0.70710678 0. 0.70710678]
[ 0. 0.70710678 0. ]]
Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
Qobj data =
[[ 0.+0.j 0.-0.70710678j 0.+0.j ]
[ 0.+0.70710678j 0.+0.j 0.-0.70710678j]
[ 0.+0.j 0.+0.70710678j 0.+0.j ]]
Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
Qobj data =
[[ 1. 0. 0.]
(continues on next page)
Examples
>>> num(4)
Quantum object: dims=[[4], [4]], shape=(4, 4), type='oper', isherm=True
Qobj data =
[[0 0 0 0]
[0 1 0 0]
[0 0 2 0]
[0 0 0 3]]
phi0
[float, default: 0] Reference phase.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Phase operator with respect to reference phase.
Notes
Examples
qeye(dimensions, *, dtype=None)
Identity operator.
Parameters
dimensions
[(int) or (list of int) or (list of list of int), Space] Number of basis states in the Hilbert
space. If provided as a list of ints, then the dimension is the product over this list, but
the dims property of the new Qobj are set to this list. This can produce either oper or
super depending on the passed dimensions.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Identity operator Qobj.
Examples
>>> qeye(3)
Quantum object: dims = [[3], [3]], shape = (3, 3), type = oper, isherm = True
Qobj data =
[[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
>>> qeye([2,2])
Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm =␣
˓→True
Qobj data =
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
qeye_like(qobj)
Identity operator with the same dims and type as the reference quantum object.
Parameters
qobj
[Qobj, QobjEvo] Reference quantum object to copy the dims from.
Returns
oper
[qobj] Identity operator Qobj.
qutrit_ops(*, dtype=None)
Operators for a three level system (qutrit).
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
opers: array
array of qutrit operators.
qzero(dimensions, dims_right=None, *, dtype=None)
Zero operator.
Parameters
dimensions
[int, list of int, list of list of int, Space] Number of basis states in the Hilbert space. If
provided as a list of ints, then the dimension is the product over this list, but the dims
property of the new Qobj are set to this list. This can produce either oper or super
depending on the passed dimensions.
dims_right
[int, list of int, list of list of int, Space, optional] Number of basis states in the right
Hilbert space when the operator is rectangular.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
qzero
[qobj] Zero operator Qobj.
qzero_like(qobj)
Zero operator of the same dims and type as the reference.
Parameters
qobj
[Qobj, QobjEvo] Reference quantum object to copy the dims from.
Returns
qzero
[qobj] Zero operator Qobj.
sigmam(*, dtype=None)
Annihilation operator for Pauli spins.
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Examples
>>> sigmam()
Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = False
Qobj data =
[[ 0. 0.]
[ 1. 0.]]
sigmap(*, dtype=None)
Creation operator for Pauli spins.
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Examples
>>> sigmap()
Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = False
Qobj data =
[[ 0. 1.]
[ 0. 0.]]
sigmax(*, dtype=None)
Pauli spin 1/2 sigma-x operator
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Examples
>>> sigmax()
Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = False
Qobj data =
[[ 0. 1.]
[ 1. 0.]]
sigmay(*, dtype=None)
Pauli spin 1/2 sigma-y operator.
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Examples
>>> sigmay()
Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = True
Qobj data =
[[ 0.+0.j 0.-1.j]
[ 0.+1.j 0.+0.j]]
sigmaz(*, dtype=None)
Pauli spin 1/2 sigma-z operator.
Parameters
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Examples
>>> sigmaz()
Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = True
Qobj data =
[[ 1. 0.]
[ 0. -1.]]
spin_Jm(j, *, dtype=None)
Spin-j annihilation operator
Parameters
j
[float] Spin of operator
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
op
[Qobj] qobj representation of the operator.
spin_Jp(j, *, dtype=None)
Spin-j creation operator
Parameters
j
[float] Spin of operator
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
op
[Qobj] qobj representation of the operator.
spin_Jx(j, *, dtype=None)
Spin-j x operator
Parameters
j
[float] Spin of operator
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
op
[Qobj] qobj representation of the operator.
spin_Jy(j, *, dtype=None)
Spin-j y operator
Parameters
j
[float] Spin of operator
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
op
[Qobj] qobj representation of the operator.
spin_Jz(j, *, dtype=None)
Spin-j z operator
Parameters
j
[float] Spin of operator
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
op
[Qobj] qobj representation of the operator.
squeeze(N, z, offset=0, *, dtype=None)
Single-mode squeezing operator.
Parameters
N
[int] Dimension of hilbert space.
z
[float/complex] Squeezing parameter.
offset
[int, default: 0] The lowest number state that is included in the finite number state rep-
resentation of the operator.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[Qobj] Squeezing operator.
Examples
squeezing(a1, a2, z)
Generalized squeezing operator.
(︂ (︁ )︁)︂
1 * † †
𝑆(𝑧) = exp 𝑧 𝑎1 𝑎2 − 𝑧𝑎1 𝑎2
2
Parameters
a1
[Qobj] Operator 1.
a2
[Qobj] Operator 2.
z
[float/complex] Squeezing parameter.
Returns
oper
[Qobj] Squeezing operator.
tunneling(N, m=1, *, dtype=None)
Tunneling operator with elements of the form
𝑠𝑢𝑚|𝑁 >< 𝑁 + 𝑚| + |𝑁 + 𝑚 >< 𝑁 |.
Parameters
N
[int] Number of basis states in the Hilbert space.
m
[int, default: 1] Number of excitations in tunneling event.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
T
[Qobj] Tunneling operator.
Quantum Gates
berkeley(*, dtype=None)
Quantum object representing the Berkeley gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
berkeley_gate
[qobj] Quantum object representation of Berkeley gate
cnot(*, dtype=None)
Quantum object representing the CNOT gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
cnot_gate
[qobj] Quantum object representation of CNOT gate
cphase(theta, *, dtype=None)
Returns quantum object representing the controlled phase shift gate.
Parameters
theta
[float] Phase rotation angle.
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
U
[qobj] Quantum object representation of controlled phase gate.
cs_gate(*, dtype=None)
Controlled S gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[Qobj] Quantum object for operator describing the rotation.
csign(*, dtype=None)
Quantum object representing the CSIGN gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
csign_gate
[qobj] Quantum object representation of CSIGN gate
ct_gate(*, dtype=None)
Controlled T gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[Qobj] Quantum object for operator describing the rotation.
cy_gate(*, dtype=None)
Controlled Y gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[Qobj] Quantum object for operator describing the rotation.
cz_gate(*, dtype=None)
Controlled Z gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[Qobj] Quantum object for operator describing the rotation.
fredkin(*, dtype=None)
Quantum object representing the Fredkin gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
fredkin_gate
[qobj] Quantum object representation of Fredkin gate.
globalphase(theta, N=1, *, dtype=None)
Returns quantum object representing the global phase shift gate.
Parameters
theta
[float] Phase rotation angle.
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
phase_gate
[qobj] Quantum object representation of global phase shift gate.
hadamard_transform(N=1, *, dtype=None)
Quantum object representing the N-qubit Hadamard gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
q
[qobj] Quantum object representation of the N-qubit Hadamard gate.
iswap(*, dtype=None)
Quantum object representing the iSWAP gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
iswap_gate
[qobj] Quantum object representation of iSWAP gate
molmer_sorensen(theta, *, dtype=None)
Quantum object of a Mølmer–Sørensen gate.
Parameters
theta: float
The duration of the interaction pulse.
N: int
Number of qubits in the system.
target: int
The indices of the target qubits.
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
molmer_sorensen_gate: Qobj
Quantum object representation of the Mølmer–Sørensen gate.
phasegate(theta, *, dtype=None)
Returns quantum object representing the phase shift gate.
Parameters
theta
[float] Phase rotation angle.
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
phase_gate
[qobj] Quantum object representation of phase shift gate.
phi
[float] Rotation angle
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[qobj] Quantum object for operator describing the rotation.
s_gate(*, dtype=None)
Single-qubit rotation also called Phase gate or the Z90 gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[Qobj] Quantum object for operator describing a 90 degree rotation around the z-axis.
snot(*, dtype=None)
Quantum object representing the SNOT (Hadamard) gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
snot_gate
[qobj] Quantum object representation of SNOT gate.
sqrtiswap(*, dtype=None)
Quantum object representing the square root iSWAP gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
sqrtiswap_gate
[qobj] Quantum object representation of square root iSWAP gate
sqrtnot(*, dtype=None)
Single-qubit square root NOT gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[qobj] Quantum object for operator describing the square root NOT gate.
sqrtswap(*, dtype=None)
Quantum object representing the square root SWAP gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
sqrtswap_gate
[qobj] Quantum object representation of square root SWAP gate
swap(*, dtype=None)
Quantum object representing the SWAP gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
swap_gate
[qobj] Quantum object representation of SWAP gate
swapalpha(alpha, *, dtype=None)
Quantum object representing the SWAPalpha gate.
Parameters
alpha
[float] Angle of the SWAPalpha gate.
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
swapalpha_gate
[qobj] Quantum object representation of SWAPalpha gate
t_gate(*, dtype=None)
Single-qubit rotation related to the S gate by the relationship S=T*T.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
result
[Qobj] Quantum object for operator describing a phase shift of pi/4.
toffoli(*, dtype=None)
Quantum object representing the Toffoli gate.
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
toff_gate
[qobj] Quantum object representation of Toffoli gate.
dm
[Qobj] Thermal state density matrix.
Quantum Objects
The Quantum Object (Qobj) class, for representing quantum states and operators, and related functions.
ptrace(Q, sel)
Partial trace of the Qobj with selected components remaining.
Parameters
Q
[Qobj] Composite quantum object.
sel
[int/list] An int or list of components to keep after partial trace.
Returns
oper
[Qobj] Quantum object representing partial trace with selected components remaining.
Notes
This function is for legacy compatibility only. It is recommended to use the ptrace() Qobj method.
density
[float, default: 0.75] Density between [0,1] of output density matrix. Used by the
“pure”, “eigen” and “herm”.
eigenvalues
[array_like, optional] Eigenvalues of the output Hermitian matrix. The len must match
the shape of the matrix.
rank
[int, optional] When using the “ginibre” distribution, rank of the density matrix. Will
default to a full rank operator when not provided.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator
or a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.
to is accepted.
Returns
oper
[qobj] Density matrix quantum operator.
rand_herm(dimensions, density=0.3, distribution='fill', *, eigenvalues=(), seed=None, dtype=None)
Creates a random sparse Hermitian quantum object.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If provided as a
list of ints, then the dimension is the product over this list, but the dims property of the
new Qobj are set to this list. This can produce either oper or super depending on the
passed dimensions.
density
[float, default: 0.30] Density between [0,1] of output Hermitian operator.
distribution
[str {“fill”, “pos_def”, “eigen”}, default: “fill”] Method used to obtain the density ma-
trices.
• “fill” : Uses 𝐻 = 0.5*(𝑋 +𝑋 + ) where 𝑋 is a randomly generated quantum operator
with elements uniformly distributed between [-1, 1] + [-1j, 1j].
• “eigen” : A density matrix with the given eigenvalues. It uses random complex
Jacobi rotations to shuffle the operator.
• “pos_def” : Return a positive semi-definite matrix by diagonal dominance.
eigenvalues
[array_like, optional] Eigenvalues of the output Hermitian matrix. The len must match
the shape of the matrix.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[Qobj] Hermitian quantum operator.
Notes
If given a list of eigenvalues the object is created using complex Jacobi rotations. While this method is fast
for small matrices, it should not be repeatedly used for generating matrices larger than ~1000x1000.
rand_ket(dimensions, density=1, distribution='haar', *, seed=None, dtype=None)
Creates a random ket vector.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If provided as a
list of ints, then the dimension is the product over this list, but the dims property of the
new Qobj are set to this list. This can produce either oper or super depending on the
passed dimensions.
density
[float, default: 1] Density between [0,1] of output ket state when using the fill method.
distribution
[str {“haar”, “fill”}, default: “haar”] Method used to obtain the kets.
• haar : Haar random pure state obtained by applying a Haar random unitary to a fixed
pure state.
• fill : Fill the ket with uniformly distributed random complex number.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Ket quantum state vector.
rand_kraus_map(dimensions, *, seed=None, dtype=None)
Creates a random CPTP map on an N-dimensional Hilbert space in Kraus form.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If provided as a
list of ints, then the dimension is the product over this list, but the dims property of the
new Qobj are set to this list. This can produce either oper or super depending on the
passed dimensions.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper_list
[list of qobj] N^2 x N x N qobj operators.
rand_stochastic(dimensions, density=0.75, kind='left', *, seed=None, dtype=None)
Generates a random stochastic matrix.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If provided as a
list of ints, then the dimension is the product over this list, but the dims property of the
new Qobj are set to this list. This can produce either oper or super depending on the
passed dimensions.
density
[float, default: 0.75] Density between [0,1] of output density matrix.
kind
[str {“left”, “right”}, default: “left”] Generate ‘left’ or ‘right’ stochastic matrix.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Quantum operator form of stochastic matrix.
rand_super(dimensions, *, superrep='super', seed=None, dtype=None)
Returns a randomly drawn superoperator acting on operators acting on N dimensions.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If provided as a
list of ints, then the dimension is the product over this list, but the dims property of the
new Qobj are set to this list. This can produce either oper or super depending on the
passed dimensions.
superrop
[str, default: “super”] Representation of the super operator
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
rand_super_bcsz(dimensions, enforce_tp=True, rank=None, *, superrep='super', seed=None, dtype=None)
Returns a random superoperator drawn from the Bruzda et al ensemble for CPTP maps [BCSZ08]. Note
that due to finite numerical precision, for ranks less than full-rank, zero eigenvalues may become slightly
negative, such that the returned operator is not actually completely positive.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If an int is provided,
it is understood as the Square root of the dimension of the superoperator to be returned,
with the corresponding dims as [[[N],[N]], [[N],[N]]]. If provided as a list of ints,
then the dimensions is understood as the space of density matrices this superoperator is
applied to: dimensions=[2,2] dims=[[[2,2],[2,2]], [[2,2],[2,2]]].
enforce_tp
[bool, default: True] If True, the trace-preserving condition of [BCSZ08] is enforced;
otherwise only complete positivity is enforced.
rank
[int, optional] Rank of the sampled superoperator. If None, a full-rank superoperator is
generated.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
superrop
[str, default: “super”] representation of the
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
rho
[Qobj] A superoperator acting on vectorized dim × dim density operators, sampled from
the BCSZ distribution.
rand_unitary(dimensions, density=1, distribution='haar', *, seed=None, dtype=None)
Creates a random sparse unitary quantum object.
Parameters
dimensions
[(int) or (list of int) or (list of list of int)] Dimension of Hilbert space. If provided as a
list of ints, then the dimension is the product over this list, but the dims property of the
new Qobj are set to this list. This can produce either oper or super depending on the
passed dimensions.
density
[float, default: 1] Density between [0,1] of output unitary operator.
distribution
[str {“haar”, “exp”}, default: “haar”] Method used to obtain the unitary matrices.
• haar : Haar random unitary matrix using the algorithm of [Mez07].
• exp : Uses exp(−𝑖𝐻), where H is a randomly generated Hermitian operator.
seed
[int, SeedSequence, Generator, optional] Seed to create the random number generator or
a pre prepared generator. When none is suplied, a default generator is used.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Unitary quantum operator.
operator_to_vector(op)
Create a vector representation given a quantum operator in matrix form. The passed object should have a
Qobj.type of ‘oper’ or ‘super’; this function is not designed for general-purpose matrix reshaping.
Parameters
op
[Qobj or QobjEvo] Quantum operator in matrix form. This must have a type of ‘oper’
or ‘super’.
Returns
Qobj or QobjEvo
The same object, but re-cast into a column-stacked-vector form of type ‘operator-ket’.
The output is the same type as the passed object.
spost(A)
Superoperator formed from post-multiplication by operator A
Parameters
A
[Qobj or QobjEvo] Quantum operator for post multiplication.
Returns
super
[Qobj or QobjEvo] Superoperator formed from input qauntum object.
spre(A)
Superoperator formed from pre-multiplication by operator A.
Parameters
A
[Qobj or QobjEvo] Quantum operator for pre-multiplication.
Returns
super :Qobj or QobjEvo
Superoperator formed from input quantum object.
sprepost(A, B)
Superoperator formed from pre-multiplication by A and post-multiplication by B.
Parameters
A
[Qobj or QobjEvo] Quantum operator for pre-multiplication.
B
[Qobj or QobjEvo] Quantum operator for post-multiplication.
Returns
super
[Qobj or QobjEvo] Superoperator formed from input quantum objects.
vector_to_operator(op)
Create a matrix representation given a quantum operator in vector form. The passed object should have a
Qobj.type of ‘operator-ket’; this function is not designed for general-purpose matrix reshaping.
Parameters
op
[Qobj or QobjEvo] Quantum operator in column-stacked-vector form. This must have a
type of ‘operator-ket’.
Returns
Qobj or QobjEvo
The same object, but re-cast into “standard” operator form. The output is the same type
as the passed object.
Superoperator Representations
This module implements transformations between superoperator representations, including supermatrix, Kraus,
Choi and Chi (process) matrix formalisms.
kraus_to_choi(kraus_ops)
Convert a list of Kraus operators into Choi representation of the channel.
Essentially,∑︀
kraus operators are a decomposition of a Choi matrix, and its reconstruction from them should
go as 𝐸 = 𝑖 |𝐾𝑖 ⟩⟩⟨⟨𝐾𝑖 |, where we use vector representation of Kraus operators.
Parameters
kraus_ops
[list[Qobj]] The list of Kraus operators to be converted to Choi representation.
Returns
choi
[Qobj] A quantum object representing the same map as kraus_ops, such that choi.
superrep == "choi".
kraus_to_super(kraus_list)
Convert a list of Kraus operators to a superoperator.
Parameters
kraus_list
[list of Qobj] The list of Kraus super operators to convert.
to_chi(q_oper)
Converts a Qobj representing a quantum map to a representation as a chi (process) matrix in the Pauli basis,
such that the trace of the returned operator is equal to the dimension of the system.
Parameters
q_oper
[Qobj] Superoperator to be converted to Chi representation. If q_oper is type="oper",
then it is taken to act by conjugation, such that to_chi(A) == to_chi(sprepost(A,
A.dag())).
Returns
chi
[Qobj] A quantum object representing the same map as q_oper, such that chi.
superrep == "chi".
Raises
TypeError:
If the given quantum object is not a map, or cannot be converted to Chi representation.
to_choi(q_oper)
Converts a Qobj representing a quantum map to the Choi representation, such that the trace of the returned
operator is equal to the dimension of the system.
Parameters
q_oper
[Qobj] Superoperator to be converted to Choi representation. If q_oper is
type="oper", then it is taken to act by conjugation, such that to_choi(A) ==
to_choi(sprepost(A, A.dag())).
Returns
choi
[Qobj] A quantum object representing the same map as q_oper, such that choi.
superrep == "choi".
Raises
TypeError:
If the given quantum object is not a map, or cannot be converted to Choi representation.
to_kraus(q_oper, tol=1e-09)
Converts a Qobj representing a quantum map to a list of quantum objects, each representing an operator in
the Kraus decomposition of the given map.
Parameters
q_oper
[Qobj] Superoperator to be converted to Kraus representation. If q_oper is
type="oper", then it is taken to act by conjugation, such that to_kraus(A) ==
to_kraus(sprepost(A, A.dag())) == [A].
tol
[Float, default: 1e-9] Optional threshold parameter for eigenvalues/Kraus ops to be dis-
carded.
Returns
kraus_ops
[list of Qobj] A list of quantum objects, each representing a Kraus operator in the de-
composition of q_oper.
Raises
TypeError: if the given quantum object is not a map, or cannot be
decomposed into Kraus operators.
to_stinespring(q_oper, threshold=1e-10)
Converts a Qobj representing a quantum map Λ to a pair of partial isometries A and B such that Λ(𝑋) =
Tr2 (𝐴𝑋𝐵 † ) for all inputs X, where the partial trace is taken over a a new index on the output dimensions of
A and B.
For completely positive inputs, A will always equal B up to precision errors.
Parameters
q_oper
[Qobj] Superoperator to be converted to a Stinespring pair.
threshold
[float, default: 1e-10] Threshold parameter for eigenvalues/Kraus ops to be discarded.
Returns
A, B
[Qobj] Quantum objects representing each of the Stinespring matrices for the input Qobj.
to_super(q_oper)
Converts a Qobj representing a quantum map to the supermatrix (Liouville) representation.
Parameters
q_oper
[Qobj] Superoperator to be converted to supermatrix representation. If q_oper is
type="oper", then it is taken to act by conjugation, such that to_super(A) ==
sprepost(A, A.dag()).
Returns
superop
[Qobj] A quantum object representing the same map as q_oper, such that superop.
superrep == "super".
Raises
TypeError
If the given quantum object is not a map, or cannot be converted to supermatrix repre-
sentation.
Examples
>>> ket.dims
[[2, 3], [1]]
>>> to_tensor_rep(ket).shape
(2, 3, 1)
>>> oper.dims
[[2, 3], [2, 3]]
>>> to_tensor_rep(oper).shape
(2, 3, 2, 3)
>>> super_oper.dims
[[[2, 3], [2, 3]], [[2, 3], [2, 3]]]
>>> to_tensor_rep(super_oper).shape
(2, 3, 2, 3, 2, 3, 2, 3)
Expectation Values
expect(oper, state)
Calculate the expectation value for operator(s) and state(s). The expectation of state k on operator A is defined
as k.dag() @ A @ k, and for density matrix R on operator A it is trace(A @ R).
Parameters
oper
[qobj/array-like] A single or a list of operators for expectation value.
state
[qobj/array-like] A single or a list of quantum states or density matrices.
Returns
expt
[float/complex/array-like] Expectation value. real if oper is Hermitian, complex oth-
erwise. A (nested) array of expectaction values if state or oper are arrays.
Examples
variance(oper, state)
Variance of an operator for the given state vector or density matrix.
Parameters
oper
[qobj] Operator for expectation value.
state
[qobj/list] A single or list of quantum states or density matrices..
Returns
var
[float] Variance of operator ‘oper’ for given state.
Tensor
Module for the creation of composite quantum objects via the tensor product.
composite(*args)
Given two or more operators, kets or bras, returns the Qobj corresponding to a composite system over each
argument. For ordinary operators and vectors, this is the tensor product, while for superoperators and vec-
torized operators, this is the column-reshuffled tensor product.
If a mix of Qobjs supported on Hilbert and Liouville spaces are passed in, the former are promoted. Ordinary
operators are assumed to be unitaries, and are promoted using to_super, while kets and bras are promoted
by taking their projectors and using operator_to_vector(ket2dm(arg)).
super_tensor(*args)
Calculate the tensor product of input superoperators, by tensoring together the underlying Hilbert spaces on
which each vectorized operator acts.
Parameters
args
[array_like] list or array of quantum objects with type="super".
Returns
obj
[qobj] A composite quantum object.
tensor(*args)
Calculates the tensor product of input operators.
Parameters
args
[array_like] list or array of quantum objects for tensor product.
Returns
obj
[qobj] A composite quantum object.
Examples
Qobj data =
[[ 0.+0.j 0.+0.j 0.+0.j 1.+0.j]
[ 0.+0.j 0.+0.j 1.+0.j 0.+0.j]
[ 0.+0.j 1.+0.j 0.+0.j 0.+0.j]
[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]]
tensor_contract(qobj, *pairs)
Contracts a qobj along one or more index pairs. Note that this uses dense representations and thus should
not be used for very large Qobjs.
Parameters
qobj: Qobj
Operator to contract subspaces on.
pairs
[tuple] One or more tuples (i, j) indicating that the i and j dimensions of the original
qobj should be contracted.
Returns
cqobj
[Qobj] The original Qobj with all named index pairs contracted away.
Partial Transpose
mask
[list / array] A mask that selects which subsystems should be transposed.
method
[str {“dense”, “sparse”}, default: “dense”] Choice of method. The “sparse” implemen-
tation can be faster for large and sparse systems (hundreds of quantum states).
Returns
rho_pr: Qobj
A density matrix with the selected subsystems transposed.
Entropy Functions
concurrence(rho)
Calculate the concurrence entanglement measure for a two-qubit state.
Parameters
state
[qobj] Ket, bra, or density matrix for a two-qubit state.
Returns
concur
[float] Concurrence
References
[1]
entropy_conditional(rho, selB, base=2.718281828459045, sparse=False)
Calculates the conditional entropy 𝑆(𝐴|𝐵) = 𝑆(𝐴, 𝐵) − 𝑆(𝐵) of a selected density matrix component.
Parameters
rho
[qobj] Density matrix of composite object
selB
[int/list] Selected components for density matrix B
base
[{e, 2}, default: e] Base of logarithm.
sparse
[bool, default: False] Use sparse eigensolver.
Returns
ent_cond
[float] Value of conditional entropy
entropy_linear(rho)
Linear entropy of a density matrix.
Parameters
rho
[qobj] sensity matrix or ket/bra vector.
Returns
entropy
[float] Linear entropy of rho.
Examples
>>> rho=0.5*fock_dm(2,0)+0.5*fock_dm(2,1)
>>> entropy_linear(rho)
0.5
References
See Nielsen & Chuang, “Quantum Computation and Quantum Information”, Section 11.3.1, pg. 511 for a
detailed explanation of quantum relative entropy.
Examples
Then we calculate their relative entropy using base 2 (i.e. log2) and base e (i.e. log).
Examples
>>> rho=0.5*fock_dm(2,0)+0.5*fock_dm(2,1)
>>> entropy_vn(rho,2)
1.0
This module contains a collection of functions for calculating metrics (distance measures) between states and
operators.
average_gate_fidelity(oper, target=None)
Returns the average gate fidelity of a quantum channel to the target channel, or to the identity channel if no
target is given.
Parameters
oper
[Qobj/list] A unitary operator, or a superoperator in supermatrix, Choi or chi-matrix
form, or a list of Kraus operators
target
[Qobj] A unitary operator
Returns
fid
[float] Average gate fidelity between oper and target, or between oper and identity.
Notes
The average gate fidelity is defined for example in: A. Gilchrist, N.K. Langford, M.A. Nielsen, Phys. Rev.
A 71, 062310 (2005). The definition of state fidelity that the average gate fidelity is based on is the one
from R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994). It is the square of the fidelity implemented in
qutip.core.metrics.fidelity which follows Nielsen & Chuang, “Quantum Computation and Quan-
tum Information”
bures_angle(A, B)
Returns the Bures Angle between two density matrices A & B.
The Bures angle ranges from 0, for states with unit fidelity, to pi/2.
Parameters
A
[qobj] Density matrix or state vector.
B
[qobj] Density matrix or state vector with same dimensions as A.
Returns
angle
[float] Bures angle between density matrices.
bures_dist(A, B)
Returns the Bures distance between two density matrices A & B.
The Bures distance ranges from 0, for states with unit fidelity, to sqrt(2).
Parameters
A
[qobj] Density matrix or state vector.
B
[qobj] Density matrix or state vector with same dimensions as A.
Returns
dist
[float] Bures distance between density matrices.
dnorm(A, B=None, solver='CVXOPT', verbose=False, force_solve=False, sparse=True)
Calculates the diamond norm of the quantum map q_oper, using the simplified semidefinite program of
[Wat13].
The diamond norm SDP is solved by using CVXPY.
Parameters
A
[Qobj] Quantum map to take the diamond norm of.
B
[Qobj or None] If provided, the diamond norm of 𝐴 − 𝐵 is taken instead.
solver
[str {“CVXOPT”, “SCS”}, default: “CVXOPT”] Solver to use with CVXPY. “SCS”
tends to be significantly faster, but somewhat less accurate.
verbose
[bool, default: False] If True, prints additional information about the solution.
force_solve
[bool, default: False] If True, forces dnorm to solve the associated SDP, even if a special
case is known for the argument.
sparse
[bool, default: True] Whether to use sparse matrices in the convex optimisation problem.
Default True.
Returns
dn
[float] Diamond norm of q_oper.
Raises
ImportError
If CVXPY cannot be imported.
fidelity(A, B)
Calculates the fidelity (pseudo-metric) between two density matrices.
Parameters
A
[qobj] Density matrix or state vector.
B
[qobj] Density matrix or state vector with same dimensions as A.
Returns
fid
[float] Fidelity pseudo-metric between A and B.
Notes
Uses the definition from Nielsen & Chuang, “Quantum Computation and Quantum Information”. It is the
square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994), used in qutip.
core.metrics.process_fidelity.
Examples
>>> x = fock_dm(5,3)
>>> y = coherent_dm(5,1)
>>> np.testing.assert_almost_equal(fidelity(x,y), 0.24104350624628332)
A
[Qobj] Density matrix or state vector.
B
[Qobj] Density matrix or state vector with same dimensions as A.
tol
[float, default: 0] Tolerance used by sparse eigensolver, if used. (0 = Machine precision)
sparse
[bool, default: False] Use sparse eigensolver.
Returns
hellinger_dist
[float] Quantum Hellinger distance between A and B. Ranges from 0 to sqrt(2).
Examples
>>> x = fock_dm(5,3)
>>> y = coherent_dm(5,1)
>>> np.allclose(hellinger_dist(x, y), 1.3725145002591095)
True
hilbert_dist(A, B)
Returns the Hilbert-Schmidt distance between two density matrices A & B.
Parameters
A
[qobj] Density matrix or state vector.
B
[qobj] Density matrix or state vector with same dimensions as A.
Returns
dist
[float] Hilbert-Schmidt distance between density matrices.
Notes
Notes
Since Qutip 5.0, this function computes the process fidelity as defined for example in: A. Gilchrist, N.K.
Langford, M.A. Nielsen, Phys. Rev. A 71, 062310 (2005). Previously, it computed a function that is now
implemented as get_fidelity in qutip-qtrl.
The definition of state fidelity that the process fidelity is based on is the one from R. Jozsa, Journal of Modern
Optics, 41:12, 2315 (1994). It is the square of the one implemented in qutip.core.metrics.fidelity
which follows Nielsen & Chuang, “Quantum Computation and Quantum Information”
tracedist(A, B, sparse=False, tol=0)
Calculates the trace distance between two density matrices.. See: Nielsen & Chuang, “Quantum Computa-
tion and Quantum Information”
Parameters
A
[qobj] Density matrix or state vector.
B
[qobj] Density matrix or state vector with same dimensions as A.
tol
[float, default: 0] Tolerance used by sparse eigensolver, if used. (0 = Machine precision)
sparse
[bool, default: False] Use sparse eigensolver.
Returns
tracedist
[float] Trace distance between A and B.
Examples
>>> x=fock_dm(5,3)
>>> y=coherent_dm(5,1)
>>> np.testing.assert_almost_equal(tracedist(x,y), 0.9705143161472971)
unitarity(oper)
Returns the unitarity of a quantum map, defined as the Frobenius norm of the unital block of that map’s
superoperator representation.
Parameters
oper
[Qobj] Quantum map under consideration.
Returns
u
[float] Unitarity of oper.
Continuous Variables
This module contains a collection functions for calculating continuous variable quantities from fock-basis repre-
sentation of the state of multi-mode fields.
correlation_matrix(basis, rho=None)
Given a basis set of operators {𝑎}𝑛 , calculate the correlation matrix:
𝐶𝑚𝑛 = ⟨𝑎𝑚 𝑎𝑛 ⟩
Parameters
basis
[list] List of operators that defines the basis for the correlation matrix.
rho
[Qobj, optional] Density matrix for which to calculate the correlation matrix. If rho is
None, then a matrix of correlation matrix operators is returned instead of expectation
values of those operators.
Returns
corr_mat
[ndarray] A 2-dimensional array of correlation values or operators.
correlation_matrix_field(a1, a2, rho=None)
Calculates the correlation matrix for given field operators 𝑎1 and 𝑎2 . If a density matrix is given the expec-
tation values are calculated, otherwise a matrix with operators is returned.
Parameters
a1
[Qobj] Field operator for mode 1.
a2
[Qobj] Field operator for mode 2.
rho
[Qobj, optional] Density matrix for which to calculate the covariance matrix.
Returns
cov_mat
[ndarray] Array of complex numbers or Qobj’s A 2-dimensional array of covariance
values, or, if rho=0, a matrix of operators.
correlation_matrix_quadrature(a1, a2, rho=None, g=1.4142135623730951)
Calculate the quadrature correlation matrix with given field operators 𝑎1 and 𝑎2 . If a density matrix is given
the expectation values are calculated, otherwise a matrix with operators is returned.
Parameters
a1
[Qobj] Field operator for mode 1.
a2
[Qobj] Field operator for mode 2.
rho
[Qobj, optional] Density matrix for which to calculate the covariance matrix.
g
[float, default: sqrt(2)] Scaling factor for a = 0.5 * g * (x + iy), default g =
sqrt(2). The value of g is related to the value of hbar in the commutation relation
[x, y] = i * hbar via hbar=2/g ** 2 giving the default value hbar=1.
Returns
corr_mat
[ndarray] Array of complex numbers or Qobj’s A 2-dimensional array of covariance
values for the field quadratures, or, if rho=0, a matrix of operators.
covariance_matrix(basis, rho, symmetrized=True)
Given a basis set of operators {𝑎}𝑛 , calculate the covariance matrix:
1
𝑉𝑚𝑛 = ⟨𝑎𝑚 𝑎𝑛 + 𝑎𝑛 𝑎𝑚 ⟩ − ⟨𝑎𝑚 ⟩⟨𝑎𝑛 ⟩
2
or, if of the optional argument symmetrized=False,
Parameters
basis
[list] List of operators that defines the basis for the covariance matrix.
rho
[Qobj] Density matrix for which to calculate the covariance matrix.
symmetrized
[bool, default: True] Flag indicating whether the symmetrized (default) or non-
symmetrized correlation matrix is to be calculated.
Returns
corr_mat
[ndarray] A 2-dimensional array of covariance values.
logarithmic_negativity(V, g=1.4142135623730951)
Calculates the logarithmic negativity given a symmetrized covariance matrix, see qutip.
continuous_variables.covariance_matrix. Note that the two-mode field state that is described by V
must be Gaussian for this function to applicable.
Parameters
V
[ndarray] The covariance matrix.
g
[float, default: sqrt(2)] Scaling factor for a = 0.5 * g * (x + iy), default g =
sqrt(2). The value of g is related to the value of hbar in the commutation relation
[x, y] = i * hbar via hbar=2/g ** 2 giving the default value hbar=1.
Returns
N
[float] The logarithmic negativity for the two-mode Gaussian state that is described by
the the Wigner covariance matrix V.
wigner_covariance_matrix(a1=None, a2=None, R=None, rho=None, g=1.4142135623730951)
Calculates the Wigner covariance matrix 𝑉𝑖𝑗 = 21 (𝑅𝑖𝑗 + 𝑅𝑗𝑖 ), given the quadrature correlation matrix
𝑅𝑖𝑗 = ⟨𝑅𝑖 𝑅𝑗 ⟩ − ⟨𝑅𝑖 ⟩⟨𝑅𝑗 ⟩, where 𝑅 = (𝑞1 , 𝑝1 , 𝑞2 , 𝑝2 )𝑇 is the vector with quadrature operators for the two
modes.
Alternatively, if R = None, and if annihilation operators a1 and a2 for the two modes are supplied instead,
the quadrature correlation matrix is constructed from the annihilation operators before then the covariance
matrix is calculated.
Parameters
a1
[Qobj, optional] Field operator for mode 1.
a2
[Qobj, optional] Field operator for mode 2.
R
[ndarray, optional] The quadrature correlation matrix.
rho
[Qobj, optional] Density matrix for which to calculate the covariance matrix.
g
[float, default: sqrt(2)] Scaling factor for a = 0.5 * g * (x + iy), default g =
sqrt(2). The value of g is related to the value of hbar in the commutation relation
[x, y] = i * hbar via hbar=2/g ** 2 giving the default value hbar=1.
Returns
cov_mat
[ndarray] A 2-dimensional array of covariance values.
5.2.3 Measurement
Parameters
state
[Qobj] The ket or density matrix specifying the state to measure.
ops
[Qobj or list of Qobj]
• measurement observable (Qobj); or
• list of measurement operators 𝑀𝑖 or kets (list of Qobj) Either:
1. specifying a POVM s.t. 𝐸𝑖 = 𝑀𝑖† 𝑀𝑖
2. projection operators if ops correspond to projectors (s.t. 𝐸𝑖 = 𝑀𝑖† = 𝑀𝑖 )
3. kets (transformed to projectors)
tol
[float, optional] Smallest value for the probabilities. Default is qutip’s core settings’
atol.
state
[Qobj] The ket or density matrix specifying the state to measure.
op
[Qobj] The measurement operator.
tol
[float, optional] Smallest value for the probabilities. Default is qutip’s core settings’
atol.
Returns
measured_value
[float] The result of the measurement (one of the eigenvalues of op).
state
[Qobj] The new state (a ket if a ket was given, otherwise a density matrix).
Examples
Since the spin-up basis is an eigenstate of sigmaz, this measurement always returns 1 as the measurement
result (the eigenvalue of the spin-up basis) and the original state (up to a global phase).
Measure the x-component of the spin of the spin-down basis state:
This measurement returns 1 fifty percent of the time and -1 the other fifty percent of the time. The new state
returned is the corresponding eigenstate of sigmax.
One may also perform a measurement on a density matrix. Below we perform the same measurement as
above, but on the density matrix representing the pure spin-down state:
The measurement result is the same, but the new state is returned as a density matrix.
measure_povm(state, ops, tol=None)
Perform a measurement specified by list of POVMs.
This function simulates a POVM measurement. The measurement collapses the state to one of the resultant
states of the measurement and returns the index of the operator corresponding to the collapsed state as well
as the collapsed state.
Parameters
state
[Qobj] The ket or density matrix specifying the state to measure.
ops
[list of Qobj] List of measurement operators 𝑀𝑖 or kets. Either:
1. specifying a POVM s.t. 𝐸𝑖 = 𝑀𝑖† 𝑀𝑖
2. projection operators if ops correspond to projectors (s.t. 𝐸𝑖 = 𝑀𝑖† = 𝑀𝑖 )
3. kets (transformed to projectors)
tol
[float, optional] Smallest value for the probabilities. Default is qutip’s core settings’
atol.
Returns
index
[float] The resultant index of the measurement.
state
[Qobj] The new state (a ket if a ket was given, otherwise a density matrix).
measurement_statistics(state, ops, tol=None)
A dispatch method that provides measurement statistics handling both observable style measurements and
projector style measurements(POVMs and PVMs).
For return signatures, please check:
• measurement_statistics_observable for observable measurements.
• measurement_statistics_povm for POVM measurements.
Parameters
state
[Qobj] The ket or density matrix specifying the state to measure.
ops
[Qobj or list of Qobj]
• measurement observable (:class:.Qobj); or
• list of measurement operators 𝑀𝑖 or kets (list of Qobj) Either:
1. specifying a POVM s.t. 𝐸𝑖 = 𝑀𝑖† * 𝑀𝑖
2. projection operators if ops correspond to projectors (s.t. 𝐸𝑖 = 𝑀𝑖† = 𝑀𝑖 )
3. kets (transformed to projectors)
tol
[float, optional] Smallest value for the probabilities. Default is qutip’s core settings’
atol.
tol
[float, optional] Smallest value for the probabilities. Default is qutip’s core settings’
atol.
Returns
eigenvalues: list of float
The list of eigenvalues of the measurement operator.
projectors: list of Qobj
Return the projectors onto the eigenstates.
probabilities: list of float
The probability of measuring the state as being in the corresponding eigenstate (and the
measurement result being the corresponding eigenvalue).
measurement_statistics_povm(state, ops, tol=None)
Returns measurement statistics (resultant states and probabilities) for a measurement specified by a set of
positive operator valued measurements on a specified ket or density matrix.
Parameters
state
[Qobj] The ket or density matrix specifying the state to measure.
ops
[list of Qobj] List of measurement operators 𝑀𝑖 or kets. Either:
1. specifying a POVM s.t. 𝐸𝑖 = 𝑀𝑖† 𝑀𝑖
2. projection operators if ops correspond to projectors (s.t. 𝐸𝑖 = 𝑀𝑖† = 𝑀𝑖 )
3. kets (transformed to projectors)
tol
[float, optional] Smallest value for the probabilities. Smaller probabilities will be
rounded to 0. Default is qutip’s core settings’ atol.
Returns
collapsed_states
[list of Qobj] The collapsed states obtained after measuring the qubits and obtaining the
qubit specified by the target in the state specified by the index.
probabilities
[list of floats] The probability of measuring a state in a the state specified by the index.
Schrödinger Equation
For time-dependent problems, H and c_ops can be a QobjEvo or object that can be interpreted as QobjEvo
such as a list of (Qobj, Coefficient) pairs or a function.
Parameters
H
[Qobj, QobjEvo, QobjEvo compatible format.] System Hamiltonian as a Qobj or Qob-
jEvo for time-dependent Hamiltonians. List of [Qobj, Coefficient] or callable that
can be made into QobjEvo are also accepted.
psi0
[Qobj] initial state vector (ket) or initial unitary operator psi0 = U
tlist
[list / array] list of times for 𝑡.
e_ops
[Qobj, callable, or list, optional] Single operator or list of operators for which to evaluate
expectation values or callable or list of callable. Callable signature must be, f(t: float,
state: Qobj). See expect for more detail of operator expectation.
args
[dict, optional] dictionary of parameters for time-dependent Hamiltonians
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• method : str [“adams”, “bdf”, “lsoda”, “dop853”, “vern9”, etc.]
Which differential equation integration method to use.
• atol, rtol : float
Absolute and relative tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• max_step : float
Maximum lenght of one internal step. When using pulses, it should be less than half
the width of the thinnest pulse.
Other options could be supported depending on the integration method, see Integrator.
Returns
result: Result
An instance of the class Result, which contains a list of array result.expect of
expectation values for the times specified by tlist, and/or a list result.states of
state vectors or density matrices corresponding to the times in tlist [if e_ops is an
empty list of store_states=True in options].
Master Equation
This module provides solvers for the Lindblad master equation and von Neumann equation.
mesolve(H, rho0, tlist, c_ops=None, e_ops=None, args=None, options=None, **kwargs)
Master equation evolution of a density matrix for a given Hamiltonian and set of collapse operators, or a
Liouvillian.
Evolve the state vector or density matrix (rho0) using a given Hamiltonian or Liouvillian (H) and an optional
set of collapse operators (c_ops), by integrating the set of ordinary differential equations that define the
system. In the absence of collapse operators the system is evolved according to the unitary evolution of the
Hamiltonian.
The output is either the state vector at arbitrary points in time (tlist), or the expectation values of the
supplied operators (e_ops). If e_ops is a callback function, it is invoked for each time in tlist with time
and the state as arguments, and the function does not use any return values.
If either H or the Qobj elements in c_ops are superoperators, they will be treated as direct contributions to
the total system Liouvillian. This allows the solution of master equations that are not in standard Lindblad
form.
Time-dependent operators
For time-dependent problems, H and c_ops can be a QobjEvo or object that can be interpreted as QobjEvo
such as a list of (Qobj, Coefficient) pairs or a function.
Additional options
Additional options to mesolve can be set via the options argument. Many ODE integration options can
be set this way, and the store_states and store_final_state options can be used to store states even
though expectation values are requested via the e_ops argument.
Parameters
H
[Qobj, QobjEvo, QobjEvo compatible format.] Possibly time-dependent system Liou-
villian or Hamiltonian as a Qobj or QobjEvo. List of [Qobj, Coefficient] or callable
that can be made into QobjEvo are also accepted.
rho0
[Qobj] initial density matrix or state vector (ket).
tlist
[list / array] list of times for 𝑡.
c_ops
[list of (QobjEvo, QobjEvo compatible format)] Single collapse operator, or list of col-
lapse operators, or a list of Liouvillian superoperators. None is equivalent to an empty
list.
e_ops
[list of Qobj / callback function, optional] Single operator or list of operators for which
to evaluate expectation values or callable or list of callable. Callable signature must be,
f(t: float, state: Qobj). See expect for more detail of operator expectation.
args
[dict, optional] dictionary of parameters for time-dependent Hamiltonians and collapse
operators.
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• method : str [“adams”, “bdf”, “lsoda”, “dop853”, “vern9”, etc.]
Which differential equation integration method to use.
• atol, rtol : float
Absolute and relative tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• max_step : float
Maximum lenght of one internal step. When using pulses, it should be less than half
the width of the thinnest pulse.
Other options could be supported depending on the integration method, see Integrator.
Returns
result: Result
An instance of the class Result, which contains a list of array result.expect of
expectation values for the times specified by tlist, and/or a list result.states of
state vectors or density matrices corresponding to the times in tlist [if e_ops is an
empty list of store_states=True in options].
Notes
When no collapse operator are given and the H is not a superoperator, it will defer to sesolve.
c_ops
[list] A list of collapse operators in any input type that QobjEvo accepts (see
QobjEvo’s documentation). They must be operators even if H is a superoperator. If
none are given, the solver will defer to sesolve or mesolve.
e_ops
[list, optional] A list of operator as Qobj, QobjEvo or callable with signature of (t,
state: Qobj) for calculating expectation values. When no e_ops are given, the solver
will default to save the states.
ntraj
[int, default: 500] Maximum number of trajectories to run. Can be cut short if a time
limit is passed with the timeout keyword or if the target tolerance is reached, see
target_tol.
args
[dict, optional] Arguments for time-dependent Hamiltonian and collapse operator terms.
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• method : str [“adams”, “bdf”, “lsoda”, “dop853”, “vern9”, etc.]
Which differential equation integration method to use.
• atol, rtol : float
Absolute and relative tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• max_step : float
Maximum length of one internal step. When using pulses, it should be less than half
the width of the thinnest pulse.
• keep_runs_results : bool, [False]
Whether to store results from all trajectories or just store the averages.
• map : str {“serial”, “parallel”, “loky”, “mpi”}
How to run the trajectories. “parallel” uses the multiprocessing module to run in
parallel while “loky” and “mpi” use the “loky” and “mpi4py” modules to do so.
• num_cpus : int
Number of cpus to use when running in parallel. None detect the number of
available cpus.
• norm_t_tol, norm_tol, norm_steps : float, float, int
Parameters used to find the collapse location. norm_t_tol and norm_tol are the
tolerance in time and norm respectively. An error will be raised if the collapse could
not be found within norm_steps tries.
• mc_corr_eps : float
seeds=prev_result.seeds
target_tol
[float, tuple, list, optional] Target tolerance of the evolution. The evolution will compute
trajectories until the error on the expectation values is lower than this tolerance. The
maximum number of trajectories employed is given by ntraj. The error is computed
using jackknife resampling. target_tol can be an absolute tolerance or a pair of ab-
solute and relative tolerance, in that order. Lastly, it can be a list of pairs of (atol, rtol)
for each e_ops.
timeout
[float, optional] Maximum time for the evolution in second. When reached, no more
trajectories will be computed.
Returns
results
[McResult] Object storing all results from the simulation. Which results is saved de-
pends on the presence of e_ops and the options used. collapse and photocurrent
is available to Monte Carlo simulation results.
Notes
The simulation will end when the first end condition is reached between ntraj, timeout and target_tol.
nm_mcsolve(H, state, tlist, ops_and_rates=(), e_ops=None, ntraj=500, *, args=None, options=None,
seeds=None, target_tol=None, timeout=None)
Monte-Carlo evolution corresponding to a Lindblad equation with “rates” that may be negative. Usage of this
function is analogous to mcsolve, but the c_ops parameter is replaced by an ops_and_rates parameter to
allow for negative rates. Options for the underlying ODE solver are given by the Options class.
Parameters
H
[Qobj, QobjEvo, list, callable.] System Hamiltonian as a Qobj, QobjEvo. It can also
be any input type that QobjEvo accepts (see QobjEvo’s documentation). H can also be a
superoperator (liouvillian) if some collapse operators are to be treated deterministically.
state
[Qobj] Initial state vector.
tlist
[array_like] Times at which results are recorded.
ops_and_rates
[list] A list of tuples (L, Gamma), where the Lindblad operator L is a Qobj and Gamma
represents the corresponding rate, which is allowed to be negative. The Lindblad oper-
ators must be operators even if H is a superoperator. If none are given, the solver will
defer to sesolve or mesolve. Each rate Gamma may be just a number (in the case of a
constant rate) or, otherwise, specified using any format accepted by coefficient.
e_ops
[list, optional] A list of operator as Qobj, QobjEvo or callable with signature of (t,
state: Qobj) for calculating expectation values. When no e_ops are given, the solver
will default to save the states.
ntraj
[int, default: 500] Maximum number of trajectories to run. Can be cut short if a time
limit is passed with the timeout keyword or if the target tolerance is reached, see
target_tol.
args
[dict, optional] Arguments for time-dependent Hamiltonian and collapse operator terms.
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• method : str [“adams”, “bdf”, “lsoda”, “dop853”, “vern9”, etc.]
Which differential equation integration method to use.
• atol, rtol : float
Absolute and relative tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• max_step : float
Maximum length of one internal step. When using pulses, it should be less than half
the width of the thinnest pulse.
• keep_runs_results : bool, [False]
Whether to store results from all trajectories or just store the averages.
• map : str {“serial”, “parallel”, “loky”, “mpi”}
How to run the trajectories. “parallel” uses the multiprocessing module to run in
parallel while “loky” and “mpi” use the “loky” and “mpi4py” modules to do so.
• num_cpus : int
Number of cpus to use when running in parallel. None detect the number of
available cpus.
• norm_t_tol, norm_tol, norm_steps : float, float, int
Parameters used to find the collapse location. norm_t_tol and norm_tol are the
tolerance in time and norm respectively. An error will be raised if the collapse could
not be found within norm_steps tries.
• mc_corr_eps : float
Small number used to detect non-physical collapse caused by numerical imprecision.
• completeness_rtol, completeness_atol : float, float
seeds=prev_result.seeds
target_tol
[float, tuple, list, optional] Target tolerance of the evolution. The evolution will compute
trajectories until the error on the expectation values is lower than this tolerance. The
maximum number of trajectories employed is given by ntraj. The error is computed
using jackknife resampling. target_tol can be an absolute tolerance or a pair of ab-
solute and relative tolerance, in that order. Lastly, it can be a list of pairs of (atol, rtol)
for each e_ops.
timeout
[float, optional] Maximum time for the evolution in seconds. When reached, no more
trajectories will be computed.
Returns
results
[NmmcResult] Object storing all results from the simulation. Compared to a result re-
turned by mcsolve, this result contains the additional field trace (and runs_trace if
store_final_state is set). Note that the states on the individual trajectories are not
normalized. This field contains the average of their trace, which will converge to one in
the limit of sufficiently many trajectories.
tlist
[list / array] list of times for 𝑡.
krylov_dim: int
Dimension of Krylov approximation subspaces used for the time evolution approxima-
tion.
e_ops
[Qobj, callable, or list, optional] Single operator or list of operators for which to evaluate
expectation values or callable or list of callable. Callable signature must be, f(t: float,
state: Qobj). See expect for more detail of operator expectation.
args
[dict, optional] dictionary of parameters for time-dependent Hamiltonians
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• atol: float
Absolute tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• min_step, max_step : float
Miniumum and maximum lenght of one internal step.
• always_compute_step: bool
If True, the step lenght is computed each time a new Krylov subspace is computed.
Otherwise it is computed only once when creating the integrator.
• sub_system_tol: float
Tolerance to detect an happy breakdown. An happy breakdown happens when the
initial ket is in a subspace of the Hamiltonian smaller than krylov_dim.
Returns
result: Result
An instance of the class Result, which contains a list of array result.expect of
expectation values for the times specified by tlist, and/or a list result.states of
state vectors or density matrices corresponding to the times in tlist [if e_ops is an
empty list of store_states=True in options].
This module provides solvers for the Lindblad master equation and von Neumann equation.
brmesolve(H, psi0, tlist, a_ops=(), e_ops=(), c_ops=(), args=None, sec_cutoff=0.1, options=None, **kwargs)
Solves for the dynamics of a system using the Bloch-Redfield master equation, given an input Hamiltonian,
Hermitian bath-coupling terms and their associated spectral functions, as well as possible Lindblad collapse
operators.
Parameters
H
[Qobj, QobjEvo] Possibly time-dependent system Liouvillian or Hamiltonian as a Qobj
or QobjEvo. list of [Qobj, Coefficient] or callable that can be made into QobjEvo
are also accepted.
psi0: Qobj
Initial density matrix or state vector (ket).
tlist
[array_like] List of times for evaluating evolution
a_ops
[list of (a_op, spectra)] Nested list of system operators that couple to the environment,
and the corresponding bath spectra.
a_op
[Qobj, QobjEvo] The operator coupling to the environment. Must be hermitian.
spectra
[Coefficient, str, func] The corresponding bath spectral responce. Can be a Coeffi-
cient using an ‘w’ args, a function of the frequence or a string. Coefficient build from
a numpy array are understood as a function of w instead of t. Function are expected
to be of the signature f(w) or f(t, w, **args).
The spectra function can depend on t if the corresponding a_op is a QobjEvo.
Example:
a_ops = [
(a+a.dag(), ('w>0', args={"w": 0})),
(QobjEvo(a+a.dag()), 'w > exp(-t)'),
(QobjEvo([b+b.dag(), lambda t: ...]), lambda w: ...)),
(c+c.dag(), SpectraCoefficient(coefficient(array, tlist=ws))),
]
e_ops
[list of Qobj / callback function, optional] Single operator or list of operators for which
to evaluate expectation values or callable or list of callable. Callable signature must be,
f(t: float, state: Qobj). See expect for more detail of operator expectation
c_ops
[list of (QobjEvo, QobjEvo compatible format), optional] List of collapse operators.
args
[dict, optional] Dictionary of parameters for time-dependent Hamiltonians and collapse
operators. The key w is reserved for the spectra function.
sec_cutoff
[float, default: 0.1] Cutoff for secular approximation. Use -1 if secular approximation
is not used when evaluating bath-coupling terms.
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• tensor_type : str [‘sparse’, ‘dense’, ‘data’]
Which data type to use when computing the brtensor. With a cutoff ‘sparse’ is
usually the most efficient.
• sparse_eigensolver : bool {False} Whether to use the sparse eigensolver
• method : str [“adams”, “bdf”, “lsoda”, “dop853”, “vern9”, etc.] Which differential
equation integration method to use.
• atol, rtol : float
Absolute and relative tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• max_step : float, 0
Maximum lenght of one internal step. When using pulses, it should be less than half
the width of the thinnest pulse.
Other options could be supported depending on the integration method, see Integrator.
Returns
result: Result
An instance of the class qutip.solver.Result, which contains either an array of ex-
pectation values, for operators given in e_ops, or a list of states for the times specified
by tlist.
spectra_cb
[list callback functions] List of callback functions that compute the noise power spectrum
as a function of frequency for the collapse operators in c_ops.
w_th
[float, default: 0.0] The temperature in units of frequency.
kmax
[int, default: 5] The truncation of the number of sidebands (default 5).
nT
[int, default: 100] The number of integration steps (for calculating X) within one period.
Returns
output
[array] The Floquet-Markov master equation tensor R.
fmmesolve(H, rho0, tlist, c_ops=None, e_ops=None, spectra_cb=None, T=0, w_th=0.0, args=None,
options=None)
Solve the dynamics for the system using the Floquet-Markov master equation.
Parameters
H
[Qobj, QobjEvo, QobjEvo compatible format.] Periodic system Hamiltonian as
QobjEvo. List of [Qobj, Coefficient] or callable that can be made into QobjEvo
are also accepted.
rho0 / psi0
[Qobj] Initial density matrix or state vector (ket).
tlist
[list / array] List of times for 𝑡.
c_ops
[list of Qobj, optional] List of collapse operators. Time dependent collapse operators
are not supported. Fall back on fsesolve if not provided.
e_ops
[list of Qobj / callback function, optional] List of operators for which to evaluate expec-
tation values. The states are reverted to the lab basis before applying the
spectra_cb
[list callback functions, default: lambda w: (w > 0)] List of callback functions that
compute the noise power spectrum as a function of frequency for the collapse operators
in c_ops.
T
[float, default=tlist[-1]] The period of the time-dependence of the hamiltonian. The de-
fault value 0 indicates that the ‘tlist’ spans a single period of the driving.
w_th
[float, default: 0.0] The temperature of the environment in units of frequency. For ex-
ample, if the Hamiltonian written in units of 2pi GHz, and the temperature is given in
K, use the following conversion:
temperature = 25e-3 # unit K h = 6.626e-34 kB = 1.38e-23 args[‘w_th’] = temper-
ature * (kB / h) * 2 * pi * 1e-9
args
[dict, optional] Dictionary of parameters for time-dependent Hamiltonian
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• store_floquet_states : bool
Whether or not to store the density matrices in the floquet basis in
result.floquet_states.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• method : str [“adams”, “bdf”, “lsoda”, “dop853”, “vern9”, etc.]
Which differential equation integration method to use.
• atol, rtol : float
Absolute and relative tolerance of the ODE integrator.
• nsteps : int
Maximum number of (internally defined) steps allowed in one tlist step.
• max_step : float
Maximum lenght of one internal step. When using pulses, it should be less than half
the width of the thinnest pulse.
Other options could be supported depending on the integration method, see Integrator.
Returns
result: Result
An instance of the class Result, which contains the expectation values for the times
specified by tlist, and/or the state density matrices corresponding to the times.
fsesolve(H, psi0, tlist, e_ops=None, T=0.0, args=None, options=None)
Solve the Schrodinger equation using the Floquet formalism.
Parameters
H
[Qobj, QobjEvo, QobjEvo compatible format.] Periodic system Hamiltonian as
QobjEvo. List of [Qobj, Coefficient] or callable that can be made into QobjEvo
are also accepted.
psi0
[Qobj] Initial state vector (ket). If an operator is provided,
tlist
[list / array] List of times for 𝑡.
e_ops
[list of Qobj / callback function, optional] List of operators for which to evaluate expec-
tation values. If this list is empty, the state vectors for each time in tlist will be returned
instead of expectation values.
T
[float, default=tlist[-1]] The period of the time-dependence of the hamiltonian.
args
[dictionary, optional] Dictionary with variables required to evaluate H.
options
[dict, optional] Options for the results.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
Returns
output
[Result] An instance of the class Result, which contains either an array of expectation
values or an array of state vectors, for the times specified by tlist.
seeds
[int, SeedSequence, list, optional] Seed for the random number generator. It can be
a single seed used to spawn seeds for each trajectory or a list of seeds, one for each
trajectory. Seeds are saved in the result and they can be reused with:
seeds=prev_result.seeds
Additional options are listed under options. More options may be available depending
on the selected differential equation integration method, see SIntegrator.
Returns
output: Result
An instance of the class Result.
ssesolve(H, psi0, tlist, sc_ops=(), heterodyne=False, *, e_ops=(), args={}, ntraj=500, options=None,
seeds=None, target_tol=None, timeout=None, **kwargs)
Solve stochastic Schrodinger equation.
Parameters
H
[Qobj, QobjEvo, QobjEvo compatible format.] System Hamiltonian as a Qobj or Qob-
jEvo for time-dependent Hamiltonians. List of [Qobj, Coefficient] or callable that
can be made into QobjEvo are also accepted.
psi0
[Qobj] Initial state vector (ket).
tlist
[list / array] List of times for 𝑡.
sc_ops
[list of (QobjEvo, QobjEvo compatible format)] List of stochastic collapse operators.
e_ops
[qobj, callable, or list, optional] Single operator or list of operators for which to evaluate
expectation values or callable or list of callable. Callable signature must be, f(t: float,
state: Qobj). See expect for more detail of operator expectation.
args
[dict, optional] Dictionary of parameters for time-dependent Hamiltonians and collapse
operators.
ntraj
[int, default: 500] Number of trajectories to compute.
heterodyne
[bool, default: False] Whether to use heterodyne or homodyne detection.
seeds
[int, SeedSequence, list, optional] Seed for the random number generator. It can be
a single seed used to spawn seeds for each trajectory or a list of seeds, one for each
trajectory. Seeds are saved in the result and they can be reused with:
seeds=prev_result.seeds
target_tol
[{float, tuple, list}, optional] Target tolerance of the evolution. The evolution will com-
pute trajectories until the error on the expectation values is lower than this tolerance.
The maximum number of trajectories employed is given by ntraj. The error is com-
puted using jackknife resampling. target_tol can be an absolute tolerance or a pair
of absolute and relative tolerance, in that order. Lastly, it can be a list of pairs of (atol,
rtol) for each e_ops.
timeout
[float, optional] Maximum time for the evolution in second. When reached, no more
trajectories will be computed. Overwrite the option of the same name.
options
[dict, optional] Dictionary of options for the solver.
• store_final_state : bool
Whether or not to store the final state of the evolution in the result class.
• store_states : bool, None
Whether or not to store the state vectors or density matrices. On None the states will
be saved if no expectation operators are given.
• store_measurement: bool Whether to store the measurement and wiener process, or
brownian noise for each trajectories.
• keep_runs_results : bool
Whether to store results from all trajectories or just store the averages.
• normalize_output : bool
Normalize output state to hide ODE numerical errors. Only normalize the state if the
initial state is already normalized.
• progress_bar : str {‘text’, ‘enhanced’, ‘tqdm’, ‘’}
How to present the solver progress. ‘tqdm’ uses the python module of the same
name and raise an error if not installed. Empty string or False will disable the bar.
• progress_kwargs : dict
kwargs to pass to the progress_bar. Qutip’s bars use chunk_size.
• method : str
Which stochastic differential equation integration method to use. Main ones are
{“euler”, “rouchon”, “platen”, “taylor1.5_imp”}
• map : str {“serial”, “parallel”, “loky”, “mpi”}
How to run the trajectories. “parallel” uses the multiprocessing module to run in
parallel while “loky” and “mpi” use the “loky” and “mpi4py” modules to do so.
• num_cpus : NoneType, int
Number of cpus to use when running in parallel. None detect the number of
available cpus.
• dt : float
The finite steps lenght for the Stochastic integration method. Default change
depending on the integrator.
Additional options are listed under options. More options may be available depending
on the selected differential equation integration method, see SIntegrator.
Returns
output: Result
An instance of the class Result.
For string based coeffients, the string must be a compilable python code resulting in a complex. The following
symbols are defined:
sin, cos, tan, asin, acos, atan, pi, sinh, cosh, tanh, asinh, acosh, atanh, exp, log, log10, erf, zerf,
sqrt, real, imag, conj, abs, norm, arg, proj, numpy as np, scipy.special as spe (python interface)
and cython_special (scipy cython interface)
Examples:
‘args’ is needed for string coefficient at compilation. It is a dict of (name:object). The keys must be a valid
variables string.
Compilation options can be passed as “compile_opt=CompilationOptions(. . . )”.
For numpy array format, the array must be an 1d of dtype float or complex. A list of times (float64) at which
the coeffients must be given (tlist). The coeffients array must have the same len as the tlist. The time of the
tlist do not need to be equidistant, but must be sorted. By default, a cubic spline interpolation will be used
to compute the coefficient at time t. The keyword order sets the order of the interpolation. When order =
0, the interpolation is step function that evaluates to the most recent value.
Examples:
tlist = np.logspace(-5,0,100)
H = QobjEvo(np.exp(-1j*tlist), tlist=tlist)
scipy.interpolate’s CubicSpline, PPoly and Bspline are also converted to interpolated coefficients
(the same kind of coefficient created from ndarray). Other interpolation methods from scipy are converted
to a function-based coefficient (the same kind of coefficient created from callables).
Parameters
base
[object] Base object to make into a Coefficient.
args
[dict, optional] Dictionary of arguments to pass to the function or string coefficient.
order
[int, default=3] Order of the spline for array based coefficient.
tlist
[iterable, optional] Times for each element of an array based coefficient.
function_style
[str {“dict”, “pythonic”, None}, optional] Function signature of function based coeffi-
cients.
args_ctypes
[dict, optional] C type for the args when compiling array based coefficients.
compile_opt
[CompilationOptions, optional] Sets of options for the compilation of string based coef-
ficients.
boundary_conditions: 2-tupule, str or None, optional
Specify boundary conditions for spline interpolation.
**kwargs
Extra arguments to pass the the coefficients.
This module provides solvers for system-bath evoluation using the HEOM (hierarchy equations of motion).
See https://en.wikipedia.org/wiki/Hierarchical_equations_of_motion for a very basic introduction to the technique.
The implementation is derived from the BoFiN library (see https://github.com/tehruhn/bofin) which was itself
derived from an earlier implementation in QuTiP itself.
For backwards compatibility with QuTiP 4.6 and below, a new version of HSolverDL (the Drude-Lorentz specific
HEOM solver) is provided. It is implemented on top of the new HEOMSolver but should largely be a drop-in
replacement for the old HSolverDL.
heomsolve(H, bath, max_depth, state0, tlist, *, e_ops=None, args=None, options=None)
Hierarchical Equations of Motion (HEOM) solver that supports multiple baths.
The baths must be all either bosonic or fermionic baths.
If you need to run many evolutions of the same system and bath, consider using HEOMSolver directly to
avoid having to continually reconstruct the equation hierarchy for every evolution.
Parameters
H
[Qobj, QobjEvo] Possibly time-dependent system Liouvillian or Hamiltonian as a Qobj
or QobjEvo. list of [Qobj, Coefficient] or callable that can be made into QobjEvo
are also accepted.
bath
[Bath or list of Bath] A Bath containing the exponents of the expansion of the bath
correlation funcion and their associated coefficients and coupling operators, or a list of
baths.
If multiple baths are given, they must all be either fermionic or bosonic baths.
max_depth
[int] The maximum depth of the heirarchy (i.e. the maximum number of bath exponent
“excitations” to retain).
state0
[Qobj or HierarchyADOsState or array-like] If rho0 is a Qobj the it is the initial state
of the system (i.e. a Qobj density matrix).
If it is a HierarchyADOsState or array-like, then rho0 gives the initial state of all
ADOs.
Usually the state of the ADOs would be determine from a previous call to .run(..
.) with the solver results option store_ados set to True. For example, result =
HEOMResult
The results of the simulation run, with the following important attributes:
• times: the times t (i.e. the tlist).
• states: the system state at each time t (only available if e_ops was None or if the
solver option store_states was set to True).
• ado_states: the full ADO state at each time (only available if the re-
sults option ado_return was set to True). Each element is an instance of
HierarchyADOsState. The state of a particular ADO may be extracted from
result.ado_states[i] by calling extract.
• expect: a list containing the values of each e_ops at time t.
• e_data: a dictionary containing the values of each e_ops at tme t. The keys are
those given by e_ops if it was a dict, otherwise they are the indexes of the supplied
e_ops.
See HEOMResult and Result for the complete list of attributes.
Correlation Functions
⟨𝐴† (𝜏 )𝐴(0)⟩
𝑔 (1) (𝜏 ) = √︀
⟨𝐴† (𝜏 )𝐴(𝜏 )⟩⟨𝐴† (0)𝐴(0)⟩
using the quantum regression theorem and the evolution solver indicated by the solver parameter.
Parameters
H
[Qobj, QobjEvo] System Hamiltonian, may be time-dependent for solver choice of me.
state0
[Qobj] Initial state density matrix 𝜌(𝑡0 ) or state vector 𝜓(𝑡0 ). If ‘state0’ is ‘None’, then
the steady state will be used as the initial state. The ‘steady-state’ is only implemented
if c_ops are provided and the Hamiltonian is constant.
taulist
[array_like] List of times for 𝜏 . taulist must be positive and contain the element 0.
c_ops
[list of {Qobj, QobjEvo}] List of collapse operators
a_op
[Qobj, QobjEvo] Operator A.
solver
[str {‘me’, ‘es’}, default: ‘me’] Choice of solver, me for master-equation, and es for
exponential series. es is equivalent to me with options={"method": "diag"}.
args
[dict, optional] dictionary of parameters for time-dependent Hamiltonians
options
[dict, optional] Options for the solver.
Returns
g1, G1
[tuple] The normalized and unnormalized second-order coherence function.
reverse
[bool, default: False] If True, calculate ⟨𝐴(𝑡)𝐵(𝑡 + 𝜏 )⟩ instead of ⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩.
solver
[str {‘me’, ‘es’}, default: ‘me’] Choice of solver, me for master-equation, and es for
exponential series. es is equivalent to me with options={"method": "diag"}.
options
[dict, optional] Options for the solver.
Returns
corr_vec
[ndarray] An array of correlation values for the times specified by taulist.
See also:
correlation_3op
Similar function supporting various solver types.
References
Returns
corr_mat
[ndarray] An 2-dimensional array (matrix) of correlation values for the times specified
by tlist (first index) and taulist (second index).
See also:
correlation_3op
Similar function supporting various solver types.
References
taulist
[array_like] List of times for 𝜏 . taulist must be positive and contain the element 0.
c_ops
[list of {Qobj, QobjEvo}] List of collapse operators
a_op
[Qobj, QobjEvo] Operator A.
b_op
[Qobj, QobjEvo] Operator B.
c_op
[Qobj, QobjEvo] Operator C.
solver
[str {‘me’, ‘es’}, default: ‘me’] Choice of solver, me for master-equation, and es for
exponential series. es is equivalent to me with options={"method": "diag"}.
options
[dict, optional] Options for the solver.
Returns
corr_vec
[array] An array of correlation values for the times specified by taulist.
See also:
correlation_3op
Similar function supporting various solver types.
References
b_op
[Qobj, QobjEvo] Operator B.
c_op
[Qobj, QobjEvo] Operator C.
solver
[str {‘me’, ‘es’}, default: ‘me’] Choice of solver, me for master-equation, and es for
exponential series. es is equivalent to me with options={"method": "diag"}.
options
[dict, optional] Options for the solver. Only used with me solver.
Returns
corr_mat
[array] An 2-dimensional array (matrix) of correlation values for the times specified by
tlist (first index) and taulist (second index).
See also:
correlation_3op
Similar function supporting various solver types.
References
using the solver indicated by the solver parameter. Note: this spectrum is only defined for stationary
statistics (uses steady state rho0)
Parameters
H
[qobj] system Hamiltonian.
wlist
[array_like] List of frequencies for 𝜔.
c_ops
[list] List of collapse operators.
a_op
[Qobj] Operator A.
b_op
[Qobj] Operator B.
solver
[str, {‘es’, ‘pi’, ‘solve’}, default: ‘es’] Choice of solver, es for exponential series and pi
for psuedo-inverse, solve for generic solver.
Returns
spectrum
[array] An array with spectrum 𝑆(𝜔) for the frequencies specified in wlist.
spectrum_correlation_fft(tlist, y, inverse=False)
Calculate the power spectrum corresponding to a two-time correlation function using FFT.
Parameters
tlist
[array_like] list/array of times 𝑡 which the correlation function is given.
y
[array_like] list/array of correlations corresponding to time delays 𝑡.
inverse: bool, default: False
boolean parameter for using a positive exponent in the Fourier Transform instead. De-
fault is False.
Returns
w, S
[tuple] Returns an array of angular frequencies ‘w’ and the corresponding two-sided
power spectrum ‘S(w)’.
Steady-state Solvers
R
[Qobj] Returns a Qobj instance representing the pseudo inverse of L.
Notes
In general the inverse of a sparse matrix will be dense. If you are applying the inverse to a density matrix
then it is better to cast the problem as an Ax=b type problem where the explicit calculation of the inverse
is not required. See page 67 of “Electrons in nanostructures” C. Flindt, PhD Thesis available online: https:
//orbit.dtu.dk/en/publications/electrons-in-nanostructures-coherent-manipulation-and-counting-st
Note also that the definition of the pseudo-inverse herein is different from numpys pinv() alone, as it includes
pre and post projection onto the subspace defined by the projector Q.
steadystate(A, c_ops=[], *, method='direct', solver=None, **kwargs)
Calculates the steady state for quantum evolution subject to the supplied Hamiltonian or Liouvillian operator
and (if given a Hamiltonian) a list of collapse operators.
If the user passes a Hamiltonian then it, along with the list of collapse operators, will be converted into a
Liouvillian operator in Lindblad form.
Parameters
A
[Qobj] A Hamiltonian or Liouvillian operator.
c_op_list
[list] A list of collapse operators.
method
[str, {“direct”, “eigen”, “svd”, “power”}, default: “direct”] The allowed methods are
composed of 2 parts, the steadystate method: - “direct”: Solving L(rho_ss) = 0
- “eigen” : Eigenvalue problem - “svd” : Singular value decomposition - “power” :
Inverse-power method
solver
[str, optional] ‘direct’ and ‘power’ methods only. Solver to use when solving the
L(rho_ss) = 0 equation. Default supported solver are:
• “solve”, “lstsq” dense solver from numpy.linalg
• “spsolve”, “gmres”, “lgmres”, “bicgstab” sparse solver from scipy.sparse.linalg
• “mkl_spsolve” sparse solver by mkl.
Extension to qutip, such as qutip-tensorflow, can use come with their own solver. When A
and c_ops use these data backends, see the corresponding libraries linalg for available
solver.
Extra options for these solver can be passed in **kw.
use_rcm
[bool, default: False] Use reverse Cuthill-Mckee reordering to minimize fill-in in the LU
factorization of the Liouvillian. Used with ‘direct’ or ‘power’ method.
use_wbm
[bool, default: False] Use Weighted Bipartite Matching reordering to make the Liouvil-
lian diagonally dominant. This is useful for iterative preconditioners only. Used with
‘direct’ or ‘power’ method.
weight
[float, optional] Sets the size of the elements used for adding the unity trace condition to
the linear solvers. This is set to the average abs value of the Liouvillian elements if not
specified by the user. Used with ‘direct’ method.
power_tol
[float, default: 1e-12] Tolerance for the solution when using the ‘power’ method.
power_maxiter
[int, default: 10] Maximum number of iteration to use when looking for a solution when
using the ‘power’ method.
power_eps: double, default: 1e-15
Small weight used in the “power” method.
sparse: bool, default: True
Whether to use the sparse eigen solver with the “eigen” method (default sparse). With
“direct” and “power” method, when the solver is not specified, it is used to set whether
“solve” or “spsolve” is used as default solver.
**kwargs
Extra options to pass to the linear system solver. See the documentation of the used
solver in numpy.linalg or scipy.sparse.linalg to see what extra arguments are
supported.
Returns
dm
[qobj] Steady state density matrix.
info
[dict, optional] Dictionary containing solver-specific information about the solution.
Notes
The SVD method works only for dense operators (i.e. small systems).
steadystate_floquet(H_0, c_ops, Op_t, w_d=1.0, n_it=3, sparse=False, solver=None, **kwargs)
Parameters
H_0
[Qobj] A Hamiltonian or Liouvillian operator.
c_ops
[list] A list of collapse operators.
Op_t
[Qobj] The the interaction operator which is multiplied by the cosine
w_d
[float, default: 1.0] The frequency of the drive
n_it
[int, default: 3] The number of iterations for the solver
sparse
[bool, default: False] Solve for the steady state using sparse algorithms.
solver
[str, optional] Solver to use when solving the linear system. Default supported solver
are:
• “solve”, “lstsq” dense solver from numpy.linalg
• “spsolve”, “gmres”, “lgmres”, “bicgstab” sparse solver from scipy.sparse.linalg
• “mkl_spsolve” sparse solver by mkl.
Extensions to qutip, such as qutip-tensorflow, may provide their own solvers. When H_0
and c_ops use these data backends, see their documentation for the names and details
of additional solvers they may provide.
**kwargs:
Extra options to pass to the linear system solver. See the documentation of the used
solver in numpy.linalg or scipy.sparse.linalg to see what extra arguments are
supported.
Returns
dm
[qobj] Steady state density matrix.
Notes
Propagators
Returns
a
[Qobj] Instance representing the steady-state density matrix.
Returns
temporal_basis_vector
[Qobj] A basis vector representing photon scattering at the specified indices. If there
are W waveguides, T times, and N photon emissions, then the basis vector has dimen-
sionality (W*T)^N.
temporal_scattered_state(H, psi0, n_emissions, c_ops, tlist, system_zero_state=None,
construct_effective_hamiltonian=True)
Compute the scattered n-photon state projected onto the temporal basis.
Parameters
H
[Qobj or list] System-waveguide(s) Hamiltonian or effective Hamiltonian in Qobj or list-
callback format. If construct_effective_hamiltonian is not specified, an effective Hamil-
tonian is constructed from H and c_ops.
psi0
[Qobj] Initial state density matrix 𝜌(𝑡0 ) or state vector 𝜓(𝑡0 ).
n_emissions
[int] Number of photon emissions to calculate.
c_ops
[list] List of collapse operators for each waveguide; these are assumed to include spon-
√
taneous decay rates, e.g. 𝜎 = 𝛾 · 𝑎
tlist
[array_like] List of times for 𝜏𝑖 . tlist should contain 0 and exceed the pulse duration /
temporal region of interest.
system_zero_state
[Qobj, optional] State representing zero excitations in the system. Defaults to 𝜓(𝑡0 )
construct_effective_hamiltonian
[bool, default: True] Whether
∑︀ an effective Hamiltonian should be constructed from H
and c_ops: 𝐻𝑒𝑓 𝑓 = 𝐻 − 2𝑖 𝑛 𝜎𝑛† 𝜎𝑛 Default: True.
Returns
phi_n
[Qobj] The scattered bath state projected onto the temporal basis given by tlist. If there
are W waveguides, T times, and N photon emissions, then the state is a tensor product
state with dimensionality T^(W*N).
Permutational Invariance
Returns
a_minus: float
The value of 𝑎− .
ap(j, m)
Calculate the coefficient ap by applying 𝐽+ |𝑗, 𝑚⟩.
The action of ap is given by: 𝐽+ |𝑗, 𝑚⟩ = 𝐴+ (𝑗, 𝑚)|𝑗, 𝑚 + 1⟩
Parameters
j, m: float
The value for j and m in the dicke basis |𝑗, 𝑚⟩.
Returns
a_plus: float
The value of 𝑎+ .
block_matrix(N, elements='ones')
Construct the block-diagonal matrix for the Dicke basis.
Parameters
N
[int] Number of two-level systems.
elements
[str {‘ones’, ‘degeneracy’}, default: ‘ones’]
Returns
block_matr
[ndarray] A 2D block-diagonal matrix with dimension (nds,nds), where nds is the num-
ber of Dicke states for N two-level systems. Filled with ones or the value of degeneracy
at each matrix element.
collapse_uncoupled(N, emission=0.0, dephasing=0.0, pumping=0.0, collective_emission=0.0,
collective_dephasing=0.0, collective_pumping=0.0)
Create the collapse operators (c_ops) of the Lindbladian in the uncoupled basis
These operators are in the uncoupled basis of the two-level system (TLS) SU(2) Pauli matrices.
Parameters
N: int
The number of two-level systems.
emission: float, default: 0.0
Incoherent emission coefficient (also nonradiative emission).
dephasing: float, default: 0.0
Local dephasing coefficient.
pumping: float, default: 0.0
Incoherent pumping coefficient.
collective_emission: float, default: 0.0
Collective (superradiant) emmission coefficient.
collective_pumping: float, default: 0.0
Collective pumping coefficient.
collective_dephasing: float, default: 0.0
Collective dephasing coefficient.
Returns
c_ops: list
The list of collapse operators as Qobj for the system.
Notes
The collapse operator list can be given to qutip.mesolve. Notice that the operators are placed in a Hilbert
space of dimension 2𝑁 . Thus the method is suitable only for small N (of the order of 10).
css(N, x=0.7071067811865475, y=0.7071067811865475, basis='dicke', coordinates='cartesian')
Generate the density matrix of the Coherent Spin State (CSS).
∏︀𝑁
It can be defined as, |𝐶𝑆𝑆⟩ = 𝑖 (𝑎|1⟩𝑖 + 𝑏|0⟩𝑖 ) with 𝑎 = 𝑠𝑖𝑛( 𝜃2 ), 𝑏 = 𝑒𝑖𝜑 cos 𝜃2 . The default basis is
(︀ )︀
that of Dicke space |𝑗, 𝑚⟩⟨𝑗, 𝑚′ |. The default state is the symmetric CSS, |𝐶𝑆𝑆⟩ = |+⟩.
Parameters
N: int
The number of two-level systems.
x, y: float, default: sqrt(1/2)
The coefficients of the CSS state.
basis: str {“dicke”, “uncoupled”}, default: “dicke”
The basis to use.
coordinates: str {“cartesian”, “polar”}, default: “cartesian”
If polar then the coefficients are constructed as 𝑠𝑖𝑛(𝑥/2), 𝑐𝑜𝑠(𝑥/2)𝑒( 𝑖𝑦)‘.
Returns
rho: Qobj
The CSS state density matrix.
dicke(N, j, m)
Generate a Dicke state as a pure density matrix in the Dicke basis.
For instance, the superradiant state given by |𝑗, 𝑚⟩ = |1, 0⟩ for N = 2, and the state is represented as a density
matrix of size (nds, nds) or (4, 4), with the (1, 1) element set to 1.
Parameters
N: int
The number of two-level systems.
j: float
The eigenvalue j of the Dicke state (j, m).
m: float
The eigenvalue m of the Dicke state (j, m).
Returns
rho: Qobj
The density matrix.
dicke_basis(N, jmm1)
Initialize the density matrix of a Dicke state for several (j, m, m1).
This function can be used to build arbitrary states in the Dicke basis |𝑗, 𝑚⟩⟨𝑗, 𝑚′ |. We create coefficients
for each (j, m, m1) value in the dictionary jmm1. The mapping for the (i, k) index of the density matrix to
the |𝑗, 𝑚⟩ values is given by the cythonized function jmm1_dictionary. A density matrix is created from the
given dictionary of coefficients for each (j, m, m1).
Parameters
N: int
The number of two-level systems.
jmm1: dict
A dictionary of {(j, m, m1): p} that gives a density p for the (j, m, m1) matrix element.
Returns
rho: Qobj
The density matrix in the Dicke basis.
dicke_blocks(rho)
Create the list of blocks for block-diagonal density matrix in the Dicke basis.
Parameters
rho
[Qobj] A 2D block-diagonal matrix of ones with dimension (nds,nds), where nds is the
number of Dicke states for N two-level systems.
Returns
square_blocks: list of np.ndarray
Give back the blocks list.
dicke_blocks_full(rho)
Give the full (2^N-dimensional) list of blocks for a Dicke-basis matrix.
Parameters
rho
[Qobj] A 2D block-diagonal matrix of ones with dimension (nds,nds), where nds is the
number of Dicke states for N two-level systems.
Returns
full_blocks
[list] The list of blocks expanded in the 2^N space for N qubits.
dicke_function_trace(f, rho)
Calculate the trace of a function on a Dicke density matrix. :param f: A Taylor-expandable function of rho.
:type f: function :param rho: A density matrix in the Dicke basis. :type rho: Qobj
Returns
res
[float] Trace of a nonlinear function on rho.
energy_degeneracy(N, m)
Calculate the number of Dicke states with same energy.
The use of the Decimals class allows to explore N > 1000, unlike the built-in function scipy.special.
binom.
Parameters
N: int
The number of two-level systems.
m: float
Total spin z-axis projection eigenvalue. This is proportional to the total energy.
Returns
degeneracy: int
The energy degeneracy
entropy_vn_dicke(rho)
Von Neumann Entropy of a Dicke-basis density matrix.
Parameters
rho
[Qobj] A 2D block-diagonal matrix of ones with dimension (nds, nds), where nds is the
number of Dicke states for N two-level systems.
Returns
entropy_dm: float
Entropy. Use degeneracy to multiply each block.
excited(N, basis='dicke')
Generate the density matrix for the excited state.
This state is given by (N/2, N/2) in the default Dicke basis. If the argument basis is “uncoupled” then it
generates the state in a 2**N dim Hilbert space.
Parameters
N: int
The number of two-level systems.
basis: str, {“dicke”, “uncoupled”}, default: “dicke”
The basis to use.
Returns
state: Qobj
The excited state density matrix in the requested basis.
ghz(N, basis='dicke')
Generate the density matrix of the GHZ state.
If the argument basis is “uncoupled” then it generates the state in a 2𝑁 -dimensional Hilbert space.
Parameters
N: int
The number of two-level systems.
basis: str, {“dicke”, “uncoupled”}, default: “dicke”
The basis to use.
Returns
state: Qobj
The GHZ state density matrix in the requested basis.
ground(N, basis='dicke')
Generate the density matrix of the ground state.
This state is given by (N/2, -N/2) in the Dicke basis. If the argument basis is “uncoupled” then it generates
the state in a 2𝑁 -dimensional Hilbert space.
Parameters
N: int
The number of two-level systems.
basis: str, {“dicke”, “uncoupled”}, default: “dicke”
The basis to use.
Returns
state: Qobj
The ground state density matrix in the requested basis.
identity_uncoupled(N)
Generate the identity in a 2𝑁 -dimensional Hilbert space.
The identity matrix is formed from the tensor product of N TLSs.
Parameters
N: int
The number of two-level systems.
Returns
identity: Qobj
The identity matrix.
isdiagonal(mat)
Check if the input matrix is diagonal.
Parameters
mat: ndarray/Qobj
A 2D numpy array
Returns
diag: bool
True/False depending on whether the input matrix is diagonal.
jspin(N, op=None, basis='dicke')
Calculate the list of collective operators of the total algebra.
The Dicke basis |𝑗, 𝑚⟩⟨𝑗, 𝑚′ | is used by default. Otherwise with “uncoupled” the operators are in a 2𝑁
space.
Parameters
N: int
Number of two-level systems.
op: str {‘x’, ‘y’, ‘z’, ‘+’, ‘-‘}, optional
The operator to return ‘x’,’y’,’z’,’+’,’-‘. If no operator given, then output is the list of
operators for [‘x’,’y’,’z’].
basis: str {“dicke”, “uncoupled”}, default: “dicke”
The basis of the operators.
Returns
j_alg: list or Qobj
A list of qutip.Qobj representing all the operators in the “dicke” or “uncoupled” basis or
a single operator requested.
m_degeneracy(N, m)
Calculate the number of Dicke states |𝑗, 𝑚⟩ with same energy.
Parameters
N: int
The number of two-level systems.
m: float
Total spin z-axis projection eigenvalue (proportional to the total energy).
Returns
degeneracy: int
The m-degeneracy.
num_dicke_ladders(N)
Calculate the total number of ladders in the Dicke space.
For a collection of N two-level systems it counts how many different “j” exist or the number of blocks in the
block-diagonal matrix.
Parameters
N: int
The number of two-level systems.
Returns
Nj: int
The number of Dicke ladders.
num_dicke_states(N)
Calculate the number of Dicke states.
Parameters
N: int
The number of two-level systems.
Returns
nds: int
The number of Dicke states.
num_tls(nds)
Calculate the number of two-level systems.
Parameters
nds: int
The number of Dicke states.
Returns
N: int
The number of two-level systems.
purity_dicke(rho)
Calculate purity of a density matrix in the Dicke basis. It accounts for the degenerate blocks in the density
matrix.
Parameters
rho
[Qobj] Density matrix in the Dicke basis of qutip.piqs.jspin(N), for N spins.
Returns
purity
[float] The purity of the quantum state. It’s 1 for pure states, 0<=purity<1 for mixed
states.
spin_algebra(N, op=None)
Create the list [sx, sy, sz] with the spin operators.
The operators are constructed for a collection of N two-level systems (TLSs). Each element of the list, i.e.,
sx, is a vector of qutip.Qobj objects (spin matrices), as it cointains the list of the SU(2) Pauli matrices for
the N TLSs. Each TLS operator sx[i], with i = 0, . . . , (N-1), is placed in a 2𝑁 -dimensional Hilbert space.
Parameters
N: int
The number of two-level systems.
Returns
spin_operators: list or Qobj
A list of qutip.Qobj operators - [sx, sy, sz] or the requested operator.
Notes
sx[i] is 𝜎𝑥
2 in the composite Hilbert space.
state_degeneracy(N, j)
Calculate the degeneracy of the Dicke state.
Each state |𝑗, 𝑚⟩ includes D(N,j) irreducible representations |𝑗, 𝑚, 𝛼⟩.
Uses Decimals to calculate higher numerator and denominators numbers.
Parameters
N: int
The number of two-level systems.
j: float
Total spin eigenvalue (cooperativity).
Returns
degeneracy: int
The state degeneracy.
superradiant(N, basis='dicke')
Generate the density matrix of the superradiant state.
This state is given by (N/2, 0) or (N/2, 0.5) in the Dicke basis. If the argument basis is “uncoupled” then it
generates the state in a 2**N dim Hilbert space.
Parameters
N: int
The number of two-level systems.
basis: str, {“dicke”, “uncoupled”}, default: “dicke”
The basis to use.
Returns
state: Qobj
The superradiant state density matrix in the requested basis.
tau_column(tau, k, j)
Determine the column index for the non-zero elements of the matrix for a particular row k and the value of
j from the Dicke space.
Parameters
tau: str
The tau function to check for this k and j.
k: int
The row of the matrix M for which the non zero elements have to be calculated.
j: float
The value of j for this row.
5.2.5 Visualization
Pseudoprobability Functions
QFunc
a class-based version, more efficient if you want to calculate the Husimi-Q function for several states
over the same coordinates.
References
[1] Lee Loh, Y., & Kim, M. (2015). American J. of Phys., 83(1), 30–35. https://doi.org/10.1119/1.4898595
spin_wigner(rho, theta, phi)
Wigner function for a spin-j system.
The spin W function is normal when integrated over the surface of the sphere
√︂ ∫︁ ∫︁
4𝜋
𝑊 (𝜃, 𝜑) sin(𝜃)𝑑𝜃𝑑𝜑 = 1
2𝑗 + 1 𝜑 𝜃
Parameters
state
[qobj] A state vector or density matrix for a spin-j quantum system.
theta
[array_like] Polar (colatitude) angle at which to calculate the W function.
phi
[array_like] Azimuthal angle at which to calculate the W function.
Returns
W, THETA, PHI
[2d-array] Values representing the spin Wigner function at the values specified by
THETA and PHI.
References
and in general recommended, but the ‘laguerre’ method is more efficient for very sparse
density matrices (e.g., superpositions of Fock states in a large Hilbert space). The ‘clen-
shaw’ method is the preferred method for dealing with density matrices that have a large
number of excitations (>~50). ‘clenshaw’ is a fast and numerically stable method.
sparse
[bool, optional] Tells the default solver whether or not to keep the input density matrix
in sparse format. As the dimensions of the density matrix grow, setthing this flag can
result in increased performance.
parfor
[bool, optional] Flag for calculating the Laguerre polynomial based Wigner function
method=’laguerre’ in parallel using the parfor function.
Returns
W
[array] Values representing the Wigner function calculated over the specified range
[xvec,yvec].
yvex
[array] FFT ONLY. Returns the y-coordinate values calculated via the Fourier transform.
Notes
The ‘fft’ method accepts only an xvec input for the x-coordinate. The y-coordinates are calculated internally.
References
Ulf Leonhardt, Measuring the Quantum State of Light, (Cambridge University Press, 1997)
Functions for visualizing results of quantum dynamics simulations, visualizations of quantum states and processes.
Note: Hinton plots of superoperators are currently only supported for qubits.
x_basis
[list of strings, optional] list of x ticklabels to represent x basis of the input.
y_basis
[list of strings, optional] list of y ticklabels to represent y basis of the input.
color_style
[str, {“scaled”, “threshold”, “phase”}, default: “scaled”] Determines how colors are
assigned to each square:
• If set to "scaled" (default), each color is chosen by passing the absolute value of the
corresponding matrix element into cmap with the sign of the real part.
• If set to "threshold", each square is plotted as the maximum of cmap for the positive
real part and as the minimum for the negative part of the matrix element; note that this
generalizes “threshold” to complex numbers.
• If set to "phase", each color is chosen according to the angle of the corresponding
matrix element.
label_top
[bool, default: True] If True, x ticklabels will be placed on top, otherwise they will
appear below the plot.
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.
colorbar
[bool, default: True] Whether (True) or not (False) a colorbar should be attached.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The ax context in which the plot will be drawn.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
Raises
ValueError
Input argument is not a quantum object.
Examples
>>> dm = qutip.rand_dm(4)
>>> fig, ax = qutip.hinton(dm)
>>> fig.show()
y_basis
[list of strings, optional] list of y ticklabels
limits
[list/array with two float numbers, optional] The z-axis limits [min, max]
bar_style
[str, {“real”, “img”, “abs”, “phase”}, default: “real”]
• If set to "real" (default), each bar is plotted as the real part of the corresponding
matrix element
• If set to "img", each bar is plotted as the imaginary part of the corresponding matrix
element
• If set to "abs", each bar is plotted as the absolute value of the corresponding matrix
element
• If set to "phase" (default), each bar is plotted as the angle of the corresponding matrix
element
color_limits
[list/array with two float numbers, optional] The limits of colorbar [min, max]
color_style
[str, {“real”, “img”, “abs”, “phase”}, default: “real”] Determines how colors are as-
signed to each square:
• If set to "real" (default), each color is chosen according to the real part of the corre-
sponding matrix element.
• If set to "img", each color is chosen according to the imaginary part of the corre-
sponding matrix element.
• If set to "abs", each color is chosen according to the absolute value of the correspond-
ing matrix element.
• If set to "phase", each color is chosen according to the angle of the corresponding
matrix element.
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.
colorbar
[bool, default: True] show colorbar
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
options
[dict, optional] A dictionary containing extra options for the plot. The names (keys) and
values of the options are described below:
‘zticks’
[list of numbers, optional] A list of z-axis tick locations.
‘bars_spacing’
[float, default: 0.1] spacing between bars.
‘bars_alpha’
[float, default: 1.] transparency of bars, should be in range 0 - 1
‘bars_lw’
[float, default: 0.5] linewidth of bars’ edges.
‘bars_edgecolor’
[color, default: ‘k’] The colors of the bars’ edges. Examples: ‘k’, (0.1, 0.2, 0.5) or
‘#0f0f0f80’.
‘shade’
[bool, default: True] Whether to shade the dark sides of the bars (True) or not (False).
The shading is relative to plot’s source of light.
‘azim’
[float, default: -35] The azimuthal viewing angle.
‘elev’
[float, default: 35] The elevation viewing angle.
‘stick’
[bool, default: False] Changes xlim and ylim in such a way that bars next to XZ and
YZ planes will stick to those planes. This option has no effect if ax is passed as a
parameter.
‘cbar_pad’
[float, default: 0.04] The fraction of the original axes between the colorbar and the
new image axes. (i.e. the padding between the 3D figure and the colorbar).
‘cbar_to_z’
[bool, default: False] Whether to set the color of maximum and minimum z-values to
the maximum and minimum colors in the colorbar (True) or not (False).
‘threshold’: float, optional
Threshold for when bars of smaller height should be transparent. If not set, all bars
are colored according to the color map.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
Raises
ValueError
Input argument is not valid.
plot_energy_levels(H_list, h_labels=None, energy_levels=None, N=0, *, fig=None, ax=None)
Plot the energy level diagrams for a list of Hamiltonians. Include up to N energy levels. For each element
in H_list, the energy levels diagram for the cummulative Hamiltonian sum(H_list[0:n]) is plotted, where n
is the index of an element in H_list.
Parameters
H_list
[List of Qobj] A list of Hamiltonians.
h_lables
[List of string, optional] A list of xticklabels for each Hamiltonian
energy_levels
[List of string, optional] A list of yticklabels to the left of energy levels of the initial
Hamiltonian.
N
[int, default: 0] The number of energy levels to plot
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
Returns
fig, ax
[tuple] A tuple of the matplotlib figure and axes instances used to produce the figure.
Raises
ValueError
Input argument is not valid.
plot_expectation_values(results, ylabels=None, *, fig=None, axes=None)
Visualize the results (expectation values) for an evolution solver. results is assumed to be an instance of
Result, or a list of Result instances.
Parameters
results
[(list of) Result] List of results objects returned by any of the QuTiP evolution solvers.
ylabels
[list of strings, optional] The y-axis labels. List should be of the same length as results.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
axes
[(list of) axes instances, optional] The axes context in which the plot will be drawn.
Returns
fig, axes
[tuple] A tuple of the matplotlib figure and array of axes instances used to produce the
figure.
plot_fock_distribution(rho, fock_numbers=None, color='green', unit_y_range=True, *, fig=None,
ax=None)
Plot the Fock distribution for a density matrix (or ket) that describes an oscillator mode.
Parameters
rho
[Qobj] The density matrix (or ket) of the state to visualize.
fock_numbers
[list of strings, optional] list of x ticklabels to represent fock numbers
color
[color or list of colors, default: “green”] The colors of the bar faces.
unit_y_range
[bool, default: True] Set y-axis limits [0, 1] or not
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
Parameters
ket
[Qobj] Pure state for plotting.
theme
[str {‘light’, ‘dark’}, default: ‘light’] Set coloring theme for mapping complex values
into colors. See: complex_array_to_rgb.
how
[str {‘pairs’, ‘pairs_skewed’ or ‘before_after’}, default: ‘pairs’] Type of Qubism plotting.
Options:
• ‘pairs’ - typical coordinates,
• ‘pairs_skewed’ - for ferromagnetic/antriferromagnetic plots,
• ‘before_after’ - related to Schmidt plot (see also: plot_schmidt).
grid_iteration
[int, default: 1] Helper lines to be drawn on plot. Show tiles for 2*grid_iteration particles
vs all others.
legend_iteration
[int or ‘grid_iteration’ or ‘all’, default: 0] Show labels for first 2*legend_iteration
particles. Option ‘grid_iteration’ sets the same number of particles as for grid_iteration.
Option ‘all’ makes label for all particles. Typically it should be 0, 1, 2 or perhaps 3.
fig
[a matplotlib figure instance, optional] The figure canvas on which the plot will be drawn.
ax
[a matplotlib axis instance, optional] The axis context in which the plot will be drawn.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
Notes
References
[1]
plot_schmidt(ket, theme='light', splitting=None, labels_iteration=(3, 2), *, fig=None, ax=None)
Plotting scheme related to Schmidt decomposition. Converts a state into a matrix (A_ij -> A_i^j), where
rows are first particles and columns - last.
See also: plot_qubism with how=’before_after’ for a similar plot.
Parameters
ket
[Qobj] Pure state for plotting.
theme
[str {‘light’, ‘dark’}, default: ‘light’] Set coloring theme for mapping complex values
into colors. See: complex_array_to_rgb.
splitting
[int, optional] Plot for a number of first particles versus the rest. If not given, it is (number
of particles + 1) // 2.
labels_iteration
[int or pair of ints, default: (3, 2)] Number of particles to be shown as tick labels, for
first (vertical) and last (horizontal) particles, respectively.
fig
[a matplotlib figure instance, optional] The figure canvas on which the plot will be drawn.
ax
[a matplotlib axis instance, optional] The axis context in which the plot will be drawn.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
plot_wigner(rho, xvec=None, yvec=None, method='clenshaw', projection='2d', g=1.4142135623730951,
sparse=False, parfor=False, *, cmap=None, colorbar=False, fig=None, ax=None)
Plot the the Wigner function for a density matrix (or ket) that describes an oscillator mode.
Parameters
rho
[Qobj] The density matrix (or ket) of the state to visualize.
xvec
[array_like, optional] x-coordinates at which to calculate the Wigner function.
yvec
[array_like, optional] y-coordinates at which to calculate the Wigner function. Does not
apply to the ‘fft’ method.
method
[str {‘clenshaw’, ‘iterative’, ‘laguerre’, ‘fft’}, default: ‘clenshaw’] The method used for
calculating the wigner function. See the documentation for qutip.wigner for details.
projection: str {‘2d’, ‘3d’}, default: ‘2d’
Specify whether the Wigner function is to be plotted as a contour graph (‘2d’) or surface
plot (‘3d’).
g
[float] Scaling factor for a = 0.5 * g * (x + iy), default g = sqrt(2). See the documentation
for qutip.wigner for details.
sparse
[bool {False, True}] Flag for sparse format. See the documentation for qutip.wigner for
details.
parfor
[bool {False, True}] Flag for parallel calculation. See the documentation for
qutip.wigner for details.
cmap
[a matplotlib cmap instance, optional] The colormap.
colorbar
[bool, default: False] Whether (True) or not (False) a colorbar should be attached to the
Wigner function graph.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
plot_wigner_sphere(wigner, reflections=False, *, cmap=None, colorbar=True, fig=None, ax=None)
Plots a coloured Bloch sphere.
Parameters
wigner
[a wigner transformation] The wigner transformation at steps different theta and phi.
reflections
[bool, default: False] If the reflections of the sphere should be plotted as well.
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.
colorbar
[bool, default: True] Whether (True) or not (False) a colorbar should be attached.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The ax context in which the plot will be drawn.
Returns
fig, output
[tuple] A tuple of the matplotlib figure and the axes instance or animation instance used
to produce the figure.
Notes
rhos
[Result or list of Qobj] The density matrix (or ket) of the state to visualize.
fock_numbers
[list of strings, optional] list of x ticklabels to represent fock numbers
color
[color or list of colors, default: “green”] The colors of the bar faces.
unit_y_range
[bool, default: True] Set y-axis limits [0, 1] or not
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
anim_hinton(rhos, x_basis=None, y_basis=None, color_style='scaled', label_top=True, *, cmap=None,
colorbar=True, fig=None, ax=None)
Draws an animation of Hinton diagram.
Parameters
rhos
[Result or list of Qobj] Input density matrix or superoperator.
Note: Hinton plots of superoperators are currently only supported for qubits.
x_basis
[list of strings, optional] list of x ticklabels to represent x basis of the input.
y_basis
[list of strings, optional] list of y ticklabels to represent y basis of the input.
color_style
[str, {“scaled”, “threshold”, “phase”}, default: “scaled”] Determines how colors are
assigned to each square:
• If set to "scaled" (default), each color is chosen by passing the absolute value of the
corresponding matrix element into cmap with the sign of the real part.
• If set to "threshold", each square is plotted as the maximum of cmap for the positive
real part and as the minimum for the negative part of the matrix element; note that this
generalizes “threshold” to complex numbers.
• If set to "phase", each color is chosen according to the angle of the corresponding
matrix element.
label_top
[bool, default: True] If True, x ticklabels will be placed on top, otherwise they will
appear below the plot.
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.
colorbar
[bool, default: True] Whether (True) or not (False) a colorbar should be attached.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The ax context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
Raises
ValueError
Input argument is not a quantum object.
anim_matrix_histogram(Ms, x_basis=None, y_basis=None, limits=None, bar_style='real',
color_limits=None, color_style='real', options=None, *, cmap=None,
colorbar=True, fig=None, ax=None)
Draw an animation of a histogram for the matrix M, with the given x and y labels.
Parameters
Ms
[list of matrices or Result] The matrix to visualize
x_basis
[list of strings, optional] list of x ticklabels
y_basis
[list of strings, optional] list of y ticklabels
limits
[list/array with two float numbers, optional] The z-axis limits [min, max]
bar_style
[str, {“real”, “img”, “abs”, “phase”}, default: “real”]
• If set to "real" (default), each bar is plotted as the real part of the corresponding
matrix element
• If set to "img", each bar is plotted as the imaginary part of the corresponding matrix
element
• If set to "abs", each bar is plotted as the absolute value of the corresponding matrix
element
• If set to "phase" (default), each bar is plotted as the angle of the corresponding matrix
element
color_limits
[list/array with two float numbers, optional] The limits of colorbar [min, max]
color_style
[str, {“real”, “img”, “abs”, “phase”}, default: “real”] Determines how colors are as-
signed to each square:
• If set to "real" (default), each color is chosen according to the real part of the corre-
sponding matrix element.
• If set to "img", each color is chosen according to the imaginary part of the corre-
sponding matrix element.
• If set to "abs", each color is chosen according to the absolute value of the correspond-
ing matrix element.
• If set to "phase", each color is chosen according to the angle of the corresponding
matrix element.
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.
colorbar
[bool, default: True] show colorbar
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
options
[dict, optional] A dictionary containing extra options for the plot. The names (keys) and
values of the options are described below:
‘zticks’
[list of numbers, optional] A list of z-axis tick locations.
‘bars_spacing’
[float, default: 0.1] spacing between bars.
‘bars_alpha’
[float, default: 1.] transparency of bars, should be in range 0 - 1
‘bars_lw’
[float, default: 0.5] linewidth of bars’ edges.
‘bars_edgecolor’
[color, default: ‘k’] The colors of the bars’ edges. Examples: ‘k’, (0.1, 0.2, 0.5) or
‘#0f0f0f80’.
‘shade’
[bool, default: True] Whether to shade the dark sides of the bars (True) or not (False).
The shading is relative to plot’s source of light.
‘azim’
[float, default: -35] The azimuthal viewing angle.
‘elev’
[float, default: 35] The elevation viewing angle.
‘stick’
[bool, default: False] Changes xlim and ylim in such a way that bars next to XZ and
YZ planes will stick to those planes. This option has no effect if ax is passed as a
parameter.
‘cbar_pad’
[float, default: 0.04] The fraction of the original axes between the colorbar and the
new image axes. (i.e. the padding between the 3D figure and the colorbar).
‘cbar_to_z’
[bool, default: False] Whether to set the color of maximum and minimum z-values to
the maximum and minimum colors in the colorbar (True) or not (False).
‘threshold’: float, optional
Threshold for when bars of smaller height should be transparent. If not set, all bars
are colored according to the color map.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
Raises
ValueError
Input argument is not valid.
anim_qubism(kets, theme='light', how='pairs', grid_iteration=1, legend_iteration=0, *, fig=None, ax=None)
Animation of Qubism plot for pure states of many qudits. Works best for spin chains, especially with even
number of particles of the same dimension. Allows to see entanglement between first 2k particles and the
rest.
Parameters
kets
[Result or list of Qobj] Pure states for animation.
theme
[str {‘light’, ‘dark’}, default: ‘light’] Set coloring theme for mapping complex values
into colors. See: complex_array_to_rgb.
how
[str {‘pairs’, ‘pairs_skewed’, ‘before_after’}, default: ‘pairs’] Type of Qubism plotting.
Options:
• ‘pairs’ - typical coordinates,
• ‘pairs_skewed’ - for ferromagnetic/antriferromagnetic plots,
• ‘before_after’ - related to Schmidt plot (see also: plot_schmidt).
grid_iteration
[int, default: 1] Helper lines to be drawn on plot. Show tiles for 2*grid_iteration particles
vs all others.
legend_iteration
[int or ‘grid_iteration’ or ‘all’, default: 0] Show labels for first 2*legend_iteration
particles. Option ‘grid_iteration’ sets the same number of particles as for grid_iteration.
Option ‘all’ makes label for all particles. Typically it should be 0, 1, 2 or perhaps 3.
fig
[a matplotlib figure instance, optional] The figure canvas on which the plot will be drawn.
ax
[a matplotlib axis instance, optional] The axis context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
Notes
References
[1]
anim_schmidt(kets, theme='light', splitting=None, labels_iteration=(3, 2), *, fig=None, ax=None)
Animation of Schmidt decomposition. Converts a state into a matrix (A_ij -> A_i^j), where rows are first
particles and columns - last.
See also: plot_qubism with how=’before_after’ for a similar plot.
Parameters
ket
[Result or list of Qobj] Pure states for animation.
theme
[str {‘light’, ‘dark’}, default: ‘light’] Set coloring theme for mapping complex values
into colors. See: complex_array_to_rgb.
splitting
[int, optional] Plot for a number of first particles versus the rest. If not given, it is (number
of particles + 1) // 2.
labels_iteration
[int or pair of ints, default: (3, 2)] Number of particles to be shown as tick labels, for
first (vertical) and last (horizontal) particles, respectively.
fig
[a matplotlib figure instance, optional] The figure canvas on which the plot will be drawn.
ax
[a matplotlib axis instance, optional] The axis context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
colorbar
[bool, default: True] Whether (True) or not (False) a colorbar should be attached.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
anim_spin_distribution(Ps, THETA, PHI, projection='2d', *, cmap=None, colorbar=False, fig=None,
ax=None)
Animation of a spin distribution (given as meshgrid data).
Parameters
Ps
[list of matrices] Distribution values as a meshgrid matrix.
THETA
[matrix] Meshgrid matrix for the theta coordinate. Its range is between 0 and pi
PHI
[matrix] Meshgrid matrix for the phi coordinate. Its range is between 0 and 2*pi
projection: str {‘2d’, ‘3d’}, default: ‘2d’
Specify whether the spin distribution function is to be plotted as a 2D projection where
the surface of the unit sphere is mapped on the unit disk (‘2d’) or surface plot (‘3d’).
cmap
[a matplotlib cmap instance, optional] The colormap.
colorbar
[bool, default: False] Whether (True) or not (False) a colorbar should be attached to the
Wigner function graph.
fig
[a matplotlib figure instance, optional] The figure canvas on which the plot will be drawn.
ax
[a matplotlib axis instance, optional] The axis context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
anim_wigner(rhos, xvec=None, yvec=None, method='clenshaw', projection='2d', g=1.4142135623730951,
sparse=False, parfor=False, *, cmap=None, colorbar=False, fig=None, ax=None)
Animation of the Wigner function for a density matrix (or ket) that describes an oscillator mode.
Parameters
rhos
[Result or list of Qobj] The density matrix (or ket) of the state to visualize.
xvec
[array_like, optional] x-coordinates at which to calculate the Wigner function.
yvec
[array_like, optional] y-coordinates at which to calculate the Wigner function. Does not
apply to the ‘fft’ method.
method
[str {‘clenshaw’, ‘iterative’, ‘laguerre’, ‘fft’}, default: ‘clenshaw’] The method used for
calculating the wigner function. See the documentation for qutip.wigner for details.
projection: str {‘2d’, ‘3d’}, default: ‘2d’
Specify whether the Wigner function is to be plotted as a contour graph (‘2d’) or surface
plot (‘3d’).
g
[float] Scaling factor for a = 0.5 * g * (x + iy), default g = sqrt(2). See the documentation
for qutip.wigner for details.
sparse
[bool {False, True}] Flag for sparse format. See the documentation for qutip.wigner for
details.
parfor
[bool {False, True}] Flag for parallel calculation. See the documentation for
qutip.wigner for details.
cmap
[a matplotlib cmap instance, optional] The colormap.
colorbar
[bool, default: False] Whether (True) or not (False) a colorbar should be attached to the
Wigner function graph.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The axes context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
anim_wigner_sphere(wigners, reflections=False, *, cmap=None, colorbar=True, fig=None, ax=None)
Animate a coloured Bloch sphere.
Parameters
wigners
[list of transformations] The wigner transformation at steps different theta and phi.
reflections
[bool, default: False] If the reflections of the sphere should be plotted as well.
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.
colorbar
[bool, default: True] Whether (True) or not (False) a colorbar should be attached.
fig
[a matplotlib Figure instance, optional] The Figure canvas in which the plot will be
drawn.
ax
[a matplotlib axes instance, optional] The ax context in which the plot will be drawn.
Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.
Notes
Notes
The ‘shift’ parameter allows you to vary where the colormap begins to highlight negative colors. This is
beneficial in cases where there are small negative Wigner elements due to numerical round-off and/or trun-
cation.
qpt(U, op_basis_list)
Calculate the quantum process tomography chi matrix for a given (possibly nonunitary) transformation ma-
trix U, which transforms a density matrix in vector form according to:
vec(rho) = U * vec(rho0)
or
rho = unstack_columns(U * stack_columns(rho0))
U can be calculated for an open quantum system using the QuTiP propagator function.
Parameters
U
[Qobj] Transformation operator. Can be calculated using QuTiP propagator function.
op_basis_list
[list] A list of Qobj’s representing the basis states.
Returns
chi
[array] QPT chi matrix
qpt_plot(chi, lbls_list, title=None, fig=None, axes=None)
Visualize the quantum process tomography chi matrix. Plot the real and imaginary parts separately.
Parameters
chi
[array] Input QPT chi matrix.
lbls_list
[list] List of labels for QPT plot axes.
title
[str, optional] Plot title.
fig
[figure instance, optional] User defined figure instance used for generating QPT plot.
axes
[list of figure axis instance, optional] User defined figure axis instance (list of two axes)
used for generating QPT plot.
Returns
fig, ax
[tuple] A tuple of the matplotlib figure and axes instances used to produce the figure.
qpt_plot_combined(chi, lbls_list, title=None, fig=None, ax=None, figsize=(8, 6), threshold=None)
Visualize the quantum process tomography chi matrix. Plot bars with height and color corresponding to the
absolute value and phase, respectively.
Parameters
chi
[array] Input QPT chi matrix.
lbls_list
[list] List of labels for QPT plot axes.
title
[str, optional] Plot title.
fig
[figure instance, optional] User defined figure instance used for generating QPT plot.
figsize
[(int, int), default: (8, 6)] Size of the figure when the fig is not provided.
ax
[figure axis instance, optional] User defined figure axis instance used for generating QPT
plot (alternative to the fig argument).
threshold: float, optional
Threshold for when bars of smaller height should be transparent. If not set, all bars are
colored according to the color map.
Returns
fig, ax
[tuple] A tuple of the matplotlib figure and axes instances used to produce the figure.
This module contains an implementation of the non-Markovian transfer tensor method (TTM), introduced in [1].
[1] Javier Cerrillo and Jianshu Cao, Phys. Rev. Lett 112, 110401 (2014)
ttmsolve(dynmaps, state0, times, e_ops=(), num_learning=0, options=None)
Expand time-evolution using the Transfer Tensor Method [1], based on a set of precomputed dynamical
maps.
Parameters
dynmaps
[list of Qobj, callable] List of precomputed dynamical maps (superoperators) for the first
times of times or a callback function that returns the superoperator at a given time.
state0
[Qobj] Initial density matrix or state vector (ket).
times
[array_like] List of times 𝑡𝑛 at which to compute results. Must be uniformily spaced.
e_ops
[Qobj, callable, or list, optional] Single operator or list of operators for which to evaluate
expectation values or callable or list of callable. Callable signature must be, f(t: float,
state: Qobj). See expect for more detail of operator expectation.
num_learning
[int, default: 0] Number of times used to construct the dynmaps operators when dynmaps
is a callable.
options
[dictionary, optional] Dictionary of options for the solver.
• store_final_state : bool Whether or not to store the final state of the evolution in the
result class.
• store_states : bool, None Whether or not to store the state vectors or density matrices.
On None the states will be saved if no expectation operators are given.
• normalize_output : bool Normalize output state to hide ODE numerical errors.
• threshold : float Threshold for halting. Halts if ||𝑇𝑛 − 𝑇𝑛−1 || is below treshold.
Returns
output: Result
An instance of the class Result.
Utility Functions
This module contains utility functions that are commonly needed in other qutip modules.
clebsch(j1, j2, j3, m1, m2, m3)
Calculates the Clebsch-Gordon coefficient for coupling (j1,m1) and (j2,m2) to give (j3,m3).
Parameters
j1
[float] Total angular momentum 1.
j2
[float] Total angular momentum 2.
j3
[float] Total angular momentum 3.
m1
[float] z-component of angular momentum 1.
m2
[float] z-component of angular momentum 2.
m3
[float] z-component of angular momentum 3.
Returns
cg_coeff
[float] Requested Clebsch-Gordan coefficient.
convert_unit(value, orig='meV', to='GHz')
Convert an energy from unit orig to unit to.
Parameters
value
[float / array] The energy in the old unit.
orig
[str, {“J”, “eV”, “meV”, “GHz”, “mK”}, default: “meV”] The name of the original unit.
to
[str, {“J”, “eV”, “meV”, “GHz”, “mK”}, default: “GHz”] The name of the new unit.
Returns
value_new_unit
[float / array] The energy in the new unit.
n_thermal(w, w_th)
Return the number of photons in thermal equilibrium for an harmonic oscillator mode with frequency ‘w’,
at the temperature described by ‘w_th’ where 𝜔th = 𝑘𝐵 𝑇 /ℏ.
Parameters
w
[float or ndarray] Frequency of the oscillator.
w_th
[float] The temperature in units of frequency (or the same units as w).
Returns
n_avg
[float or array] Return the number of average photons in thermal equilibrium for a an
oscillator with the given frequency and temperature.
file_data_read(filename, sep=None)
Retrieves an array of data from the requested file.
Parameters
filename
[str or pathlib.Path] Name of file containing reqested data.
sep
[str, optional] Seperator used to store data.
Returns
data
[array_like] Data from selected file.
file_data_store(filename, data, numtype='complex', numformat='decimal', sep=',')
Stores a matrix of data to a file to be read by an external program.
Parameters
filename
[str or pathlib.Path] Name of data file to be stored, including extension.
data: array_like
Data to be written to file.
numtype
[str {‘complex, ‘real’}, default: ‘complex’] Type of numerical data.
numformat
[str {‘decimal’,’exp’}, default: ‘decimal’] Format for written data.
sep
[str, default: ‘,’] Single-character field seperator. Usually a tab, space, comma, or semi-
colon.
qload(filename)
Loads data file from file filename in current directory.
Parameters
filename
[str or pathlib.Path] Name of data file to be loaded.
Returns
qobject
[instance / array_like] Object retrieved from requested file.
qsave(data, name='qutip_data')
Saves given data to file named ‘filename.qu’ in current directory.
Parameters
data
[instance/array_like] Input Python object to be stored.
filename
[str or pathlib.Path, default: “qutip_data”] Name of output data file.
Parallelization
This module provides functions for parallel execution of loops and function mappings, using the builtin Python
module multiprocessing or the loky parallel execution library.
loky_pmap(task, values, task_args=None, task_kwargs=None, reduce_func=None, map_kw=None,
progress_bar=None, progress_bar_kwargs={})
Parallel execution of a mapping of values to the function task. This is functionally equivalent to:
Uses the mpi4py module to execute the tasks asynchronously with MPI processes. For more information,
consult the documentation of mpi4py and the mpi4py.MPIPoolExecutor class.
Note: in keeping consistent with the API of parallel_map, the parameter determining the number of
requested worker processes is called num_cpus. The value of map_kw[‘num_cpus’] is passed to the
MPIPoolExecutor as its max_workers argument. If this parameter is not provided, the environment vari-
able QUTIP_NUM_PROCESSES is used instead. If this environment variable is not set either, QuTiP will
use default values that might be unsuitable for MPI applications.
Parameters
task
[a Python function] The function that is to be called for each value in task_vec.
values
[array / list] The list or array of values for which the task function is to be evaluated.
task_args
[list, optional] The optional additional arguments to the task function.
task_kwargs
[dictionary, optional] The optional additional keyword arguments to the task function.
reduce_func
[func, optional] If provided, it will be called with the output of each task instead of
storing them in a list. Note that the order in which results are passed to reduce_func is
not defined. It should return None or a number. When returning a number, it represents
the estimation of the number of tasks left. On a return <= 0, the map will end early.
progress_bar
[str, optional] Progress bar options’s string for showing progress.
progress_bar_kwargs
[dict, optional] Options for the progress bar.
map_kw: dict, optional
Dictionary containing entry for: - timeout: float, Maximum time (sec) for the whole
map. - num_cpus: int, Number of jobs to run at once. - fail_fast: bool, Abort at the first
error. All remaining entries of map_kw will be passed to the mpi4py.MPIPoolExecutor
constructor.
Returns
result
[list] The result list contains the value of task(value, *task_args,
**task_kwargs) for each value in values. If a reduce_func is provided, and
empty list will be returned.
parallel_map(task, values, task_args=None, task_kwargs=None, reduce_func=None, map_kw=None,
progress_bar=None, progress_bar_kwargs={})
Parallel execution of a mapping of values to the function task. This is functionally equivalent to:
Parameters
task
[a Python function] The function that is to be called for each value in task_vec.
values
[array / list] The list or array of values for which the task function is to be evaluated.
task_args
[list, optional] The optional additional arguments to the task function.
task_kwargs
[dictionary, optional] The optional additional keyword arguments to the task function.
reduce_func
[func, optional] If provided, it will be called with the output of each task instead of
storing them in a list. Note that the order in which results are passed to reduce_func is
not defined. It should return None or a number. When returning a number, it represents
the estimation of the number of tasks left. On a return <= 0, the map will end early.
progress_bar
[str, optional] Progress bar options’s string for showing progress.
progress_bar_kwargs
[dict, optional] Options for the progress bar.
map_kw: dict, optional
Dictionary containing entry for: - timeout: float, Maximum time (sec) for the whole
map. - num_cpus: int, Number of jobs to run at once. - fail_fast: bool, Abort at the first
error.
Returns
result
[list] The result list contains the value of task(value, *task_args,
**task_kwargs) for each value in values. If a reduce_func is provided, and
empty list will be returned.
This module contains utility functions for using QuTiP with IPython notebooks.
version_table(verbose=False)
Print an HTML-formatted table with version numbers for QuTiP and its dependencies. Use it in a IPython
notebook to show which versions of different packages that were used to run the notebook. This should make
it possible to reproduce the environment and the calculation later on.
Parameters
verbose
[bool, default: False] Add extra information about install location.
Returns
version_table: str
Return an HTML-formatted string containing version information for QuTiP dependen-
cies.
Miscellaneous
about()
About box for QuTiP. Gives version numbers for QuTiP, NumPy, SciPy, Cython, and MatPlotLib.
simdiag(ops, evals: bool = True, *, tol: float = 1e-14, safe_mode: bool = True)
Simultaneous diagonalization of commuting Hermitian matrices.
Parameters
ops
[list, array] list or array of qobjs representing commuting Hermitian operators.
evals
[bool, default: True] Whether to return the eigenvalues for each ops and eigenvectors or
just the eigenvectors.
tol
[float, default: 1e-14] Tolerance for detecting degenerate eigenstates.
safe_mode
[bool, default: True] Whether to check that all ops are Hermitian and commuting. If
set to False and operators are not commuting, the eigenvectors returned will often be
eigenvectors of only the first operator.
Returns
eigs
[tuple] Tuple of arrays representing eigvecs and eigvals of quantum objects correspond-
ing to simultaneous eigenvectors and eigenvalues for each operator.
Change Log
• Fixed rounding error in dicke_trace_function that resulted in negative eigenvalues. (#2466, by Andrey
Nikitin)
6.2.2 Documentation
6.2.3 Miscellaneous
391
QuTiP: Quantum Toolbox in Python, Release 5.0.4
6.3.2 Documentation
6.3.3 Miscellaneous
QuTiP 5 is a redesign of many of the core components of QuTiP (Qobj, QobjEvo, solvers) to make them more
consistent and more flexible.
Qobj may now be stored in either sparse or dense representations, and the two may be mixed sensibly as needed.
QobjEvo is now used consistently throughout QuTiP, and the implementation has been substantially cleaned up.
A new Coefficient class is used to represent the time-dependent factors inside QobjEvo.
The solvers have been rewritten to work well with the new data layer and the concept of Integrators which solve
ODEs has been introduced. In future, new data layers may provide their own Integrators specialized to their
representation of the underlying data.
Much of the user-facing API of QuTiP remains familiar, but there have had to be many small breaking changes. If
we can make changes to easy migrating code from QuTiP 4 to QuTiP 5, please let us know.
6.5.1 Contributors
QuTiP 5 has been a large effort by many people over the last three years.
In particular:
• Jake Lishman led the implementation of the new data layer and coefficients.
• Eric Giguère led the implementation of the new QobjEvo interface and solvers.
• Boxi Li led the updating of QuTiP’s QIP support and the creation of qutip_qip.
Other members of the QuTiP Admin team have been heavily involved in reviewing, testing and designing QuTiP
5:
• Alexander Pitchford
• Asier Galicia
• Nathan Shammah
• Shahnawaz Ahmed
• Neill Lambert
• Simon Cross
• Paul Menczel
Two Google Summer of Code contributors updated the tutorials and benchmarks to QuTiP 5:
• Christian Staufenbiel updated many of the tutorials (<https://github.com/qutip/qutip-tutorials/>).
• Xavier Sproken update the benchmarks (<https://github.com/qutip/qutip-benchmark/>).
During an internship at RIKEN, Patrick Hopf created a new quantum control method and improved the existing
methods interface:
• Patrick Hopf created new quantum control package (<https://github.com/qutip/qutip-qoc/>).
Four experimental data layers backends were written either as part of Google Summer of Code or as separate
projects. While these are still alpha quality, they helped significantly to test the data layer API:
• qutip-tensorflow: a TensorFlow backend by Asier Galicia (<https://github.com/qutip/qutip-
tensorflow>)
• qutip-cupy: a CuPy GPU backend by Felipe Bivort Haiek (<https://github.com/qutip/qutip-cupy/>)`
• qutip-tensornetwork: a TensorNetwork backend by Asier Galicia (<https://github.com/qutip/qutip-
tensornetwork>)
• qutip-jax: a JAX backend by Eric Giguère (<https://github.com/qutip/qutip-jax/>)
Finally, Yuji Tamakoshi updated the visualization function and added animation functions as part of Google Sum-
mer of Code project.
We have also had many other contributors, whose specific contributions are detailed below:
• Pieter Eendebak (updated the required SciPy to 1.5+, #1982 <https://github.com/qutip/qutip/pull/1982>).
• Pieter Eendebak (reduced import times by setting logger names, #1981
<https://github.com/qutip/qutip/pull/1981>)
• Pieter Eendebak (Allow scipy 1.12 to be used with qutip, #2354 <https://github.com/qutip/qutip/pull/2354>)
• Xavier Sproken (included C header files in the source distribution, #1971
<https://github.com/qutip/qutip/pull/1971>)
• Christian Staufenbiel (added support for multiple collapse operators to the Floquet solver, #1962
<https://github.com/qutip/qutip/pull/1962>)
• Christian Staufenbiel (fixed the basis used in the Floquet Master Equation solver, #1952
<https://github.com/qutip/qutip/pull/1952>)
• Christian Staufenbiel (allowed the bloch_redfield_tensor function to accept strings and callables for
a_ops, #1951 <https://github.com/qutip/qutip/pull/1951>)
• Christian Staufenbiel (Add a guide on Superoperators, Pauli Basis and Channel Contraction, #1984
<https://github.com/qutip/qutip/pull/1984>)
• Henrique Silvéro (allowed qutip_qip to be imported as qutip.qip, #1920
<https://github.com/qutip/qutip/pull/1920>)
• Florian Hopfmueller (added a vastly improved implementations of process_fidelity
and average_gate_fidelity, #1712 <https://github.com/qutip/qutip/pull/1712>, #1748
<https://github.com/qutip/qutip/pull/1748>, #1788 <https://github.com/qutip/qutip/pull/1788>)
• Felipe Bivort Haiek (fixed inaccuracy in docstring of the dense implementation of negation, #1608
<https://github.com/qutip/qutip/pull/1608/>)
• Rajath Shetty (added support for specifying colors for individual points, vectors and states display by
qutip.Bloch, #1335 <https://github.com/qutip/qutip/pull/1335>)
• Rochisha Agarwal (Add dtype to printed ouput of qobj, #2352 <https://github.com/qutip/qutip/pull/2352>)
• Kosuke Mizuno (Add arguments of plot_wigner() and plot_wigner_fock_distribution() to specify parameters
for wigner(), #2057 <https://github.com/qutip/qutip/pull/2057>)
• Matt Ord (Only pre-compute density matrices if keep_runs_results is False, #2303
<https://github.com/qutip/qutip/pull/2303>)
• Daniel Moreno Galán (Add the possibility to customize point colors as in V4 and fix point plot behavior for
‘l’ style, #2303 <https://github.com/qutip/qutip/pull/2303>)
• Sola85 (Fixed simdiag not returning orthonormal eigenvectors, #2269
<https://github.com/qutip/qutip/pull/2269>)
• Edward Thomas (Fix LaTeX display of Qobj state in Jupyter cell outputs, #2272
<https://github.com/qutip/qutip/pull/2272>)
• Bogdan Reznychenko (Rework kraus_to_choi making it faster, #2284
<https://github.com/qutip/qutip/pull/2284>)
• gabbence95 (Fix typos in expect documentation, #2331 <https://github.com/qutip/qutip/pull/2331>)
• lklivingstone (Added __repr__ to QobjEvo, #2111 <https://github.com/qutip/qutip/pull/2111>)
• Yuji Tamakoshi (Improve print(qutip.settings) by make it shorter, #2113
<https://github.com/qutip/qutip/pull/2113>)
• khnikhil (Added fermionic annihilation and creation operators, #2166
<https://github.com/qutip/qutip/pull/2166>)
• Daniel Weiss (Improved sampling algorithm for mcsolve, #2218 <https://github.com/qutip/qutip/pull/2218>)
• SJUW (Increase missing colorbar padding for matrix_histogram_complex() from 0 to 0.05, #2181
<https://github.com/qutip/qutip/pull/2181>)
• Valan Baptist Mathuranayagam (Changed qutip-notebooks to qutip-tutorials and fixed the typo in the link
redirecting to the changelog section in the PR template, #2107 <https://github.com/qutip/qutip/pull/2107>)
• Gerardo Jose Suarez (Added information on sec_cutoff to the documentation, #2136
<https://github.com/qutip/qutip/pull/2136>)
• Cristian Emiliano Godinez Ramirez (Added inherited members to API doc of MESolver, SMESolver, SSE-
Solver, NonMarkovianMCSolver, #2167 <https://github.com/qutip/qutip/pull/2167>)
• Andrey Rakhubovsky (Corrected grammar in Bloch-Redfield master equation documentation, #2174
<https://github.com/qutip/qutip/pull/2174>)
• Rushiraj Gadhvi (qutip.ipynbtools.version_table() can now be called without Cython installed, #2110
<https://github.com/qutip/qutip/pull/2110>)
• Harsh Khilawala (Moved HTMLProgressBar from qutip/ipynbtools.py to qutip/ui/progressbar.py, #2112
<https://github.com/qutip/qutip/pull/2112>)
• Avatar Srinidhi P V (Added new argument bc_type to take boundary conditions when creating QobjEvo,
#2114 <https://github.com/qutip/qutip/pull/2114>)
• Andrey Rakhubovsky (Fix types in docstring of projection(), #2363
<https://github.com/qutip/qutip/pull/2363>)
Previously Qobj data was stored in a SciPy-like sparse matrix. Now the representation is flexible. Implementations
for dense and sparse formats are included in QuTiP and custom implementations are possible. QuTiP’s performance
on dense states and operators is significantly improved as a result.
Some highlights:
• The data is still acessible via the .data attribute, but is now an instance of the underlying data type instead of
a SciPy-like sparse matrix. The operations available in qutip.core.data may be used on .data, regardless
of the data type.
• Qobj with different data types may be mixed in arithmetic and other operations. A sensible output type will
be automatically determined.
• The new .to(...) method may be used to convert a Qobj from one data type to another. E.g. .
to("dense") will convert to the dense representation and .to("csr") will convert to the sparse type.
• Many Qobj methods and methods that create Qobj now accepted a dtype parameter that allows the data
type of the returned Qobj to specified.
• The new & operator may be used to obtain the tensor product.
• The new @ operator may be used to obtain the matrix / operator product. bar @ ket returns a scalar.
• The new .contract() method will collapse 1D subspaces of the dimensions of the Qobj.
• The new .logm() method returns the matrix logarithm of an operator.
• The methods .set_data, .get_data, .extract_state, .eliminate_states, .evaluate and .
check_isunitary have been removed.
• The property dtype return the representation of the data used.
• The new data_as allow to obtain the data as a common python formats: numpy array, scipy sparse matrix,
JAX Array, etc.
The QobjEvo type for storing time-dependent quantum objects has been significantly expanded, standardized and
extended. The time-dependent coefficients are now represented using a new Coefficient type that may be inde-
pendently created and manipulated if required.
Some highlights:
• The .compile() method has been removed. Coefficients specified as strings are automatically compiled if
possible and the compilation is cached across different Python runs and instances.
• Mixing coefficient types within a single Qobj is now supported.
• Many new attributes were added to QobjEvo for convenience. Examples include .dims, .shape, .
superrep and .isconstant.
• Many old attributes such as .cte, .use_cython, .type, .const, and .coeff_file were removed.
• A new Spline coefficient supports spline interpolations of different orders. The old Cubic_Spline coef-
ficient has been removed.
• The new .arguments(...) method allows additional arguments to the underlying coefficient functions to
be updated.
• The _step_func_coeff argument has been replaced by the order parameter. _step_func_coeff=False
is equivalent to order=3. _step_func_coeff=True is equivalent to order=0. Higher values of order
gives spline interpolations of higher orders.
• The spline type can take bc_type to control the boundary conditions.
• QobjEvo can be creating from the multiplication of a Qobj with a coefficient: oper * qutip.
coefficient(f, args=args) is equivalent to qutip.QobjEvo([[oper, f]], args=args).
• Coefficient function can be defined in a pythonic manner: def f(t, A, w). The dictionary args second
argument is no longer needed. Function using the exact f(t, args) signature will use the old method for
backward compatibility.
The solvers in QuTiP have been heavily reworked and standardized. Under the hood solvers now make use of
swappable ODE Integrators. Many Integrators are included (see the list below) and custom implementations
are possible. Solvers now consistently accept a QobjEvo instance at the Hamiltonian or Liouvillian, or any object
which can be passed to the QobjEvo constructor.
A breakdown of highlights follows.
All solvers:
• Solver options are now supplied in an ordinary Python dict. qutip.Options is deprecated and returns a
dict for backwards compatibility.
• A specific ODE integrator may be selected by supplying a method option.
• Each solver provides a class interface. Creating an instance of the class allows a solver to be run multiple
times for the same system without having to repeatedly reconstruct the right-hand side of the ODE to be
integrated.
• A QobjEvo instance is accepted for most operators, e.g., H, c_ops, e_ops, a_ops.
• The progress bar is now selected using the progress_bar option. A new progess bar using the tqdm Python
library is provided.
• Dynamic arguments, where the value of an operator depends on the current state of the evolution interface
reworked. Now a property of the solver is to be used as an arguments: args={"state": MESolver.
StateFeedback(default=rho0)}
Integrators:
• The SciPy zvode integrator is available with the BDF and Adams methods as bdf and adams.
• The SciPy dop853 integrator (an eighth order Runge-Kutta method by Dormand & Prince) is available as
dop853.
• The SciPy lsoda integrator is available as lsoda.
• QuTiP’s own implementation of Verner’s “most efficient” Runge-Kutta methods of order 7 and 9 are available
as vern7 and vern9. See http://people.math.sfu.ca/~jverner/ for a description of the methods.
• QuTiP’s own implementation of a solver that directly diagonalizes the the system to be integrated is available
as diag. It only works on time-independent systems and is slow to setup, but once the diagonalization is
complete, it generates solutions very quickly.
• QuTiP’s own implementatoin of an approximate Krylov subspace integrator is available as krylov. This
integrator is only usable with sesolve.
Result class:
• A new .e_data attribute provides expectation values as a dictionary. Unlike .expect, the values are pro-
vided in a Python list rather than a numpy array, which better supports non-numeric types.
• The contents of the .stats attribute changed significantly and is now more consistent across solvers.
Monte-Carlo Solver (mcsolve):
• The system, H, may now be a super-operator.
• The seed parameter now supports supplying numpy SeedSequence or Generator types.
• The new timeout and target_tol parameters allow the solver to exit early if a timeout or target tolerance
is reached.
• The ntraj option no longer supports a list of numbers of trajectories. Instead, just run the solver multiple
times and use the class MCSolver if setting up the solver uses a significant amount of time.
• The map_func parameter has been replaced by the map option.
• A loky based parallel map as been added.
• A mpi based parallel map as been added.
• The result returned by mcsolve now supports calculating photocurrents and calculating the steady state over
N trajectories.
• The old parfor parallel execution function has been removed from qutip.parallel. Use parallel_map,
loky_map or mpi_pmap instead.
• Added improved sampling options which converge much faster when the probability of collapse is small.
Non Markovian Monte-Carlo Solver (nm_mcsolve):
• New Monte-Carlo Solver supporting negative decay rates.
• Based on the influence martingale approach, Donvil et al., Nat Commun 13, 4140 (2022).
• Most of the improvements made to the regular Monte-Carlo solver are also available here.
• The value of the influence martingale is available through the .trace attribute of the result.
Stochastic Equation Solvers (ssesolve, smesolve)
• Function call greatly changed: many keyword arguments are now options.
• m_ops and dW_factors are now changed from the default from the new class interface only.
• Use the same parallel maps as mcsolve: support for loky and mpi map added.
• End conditions timeout and target_tol added.
• The seed parameter now supports supplying numpy SeedSequence.
• Wiener function is now available as a feedback.
Bloch-Redfield Master Equation Solver (brmesolve):
• The a_ops and spectra support implementations been heavily reworked to reuse the techniques from the
new Coefficient and QobjEvo classes.
• The use_secular parameter has been removed. Use sec_cutoff=-1 instead.
• The required tolerance is now read from qutip.settings.
Krylov Subspace Solver (krylovsolve):
• The Krylov solver is now implemented using SESolver and the krylov ODE integrator. The function
krylovsolve is maintained for convenience and now supports many more options.
• The sparse parameter has been removed. Supply a sparse Qobj for the Hamiltonian instead.
Floquet Solver (fsesolve and fmmesolve):
• The Floquet solver has been rewritten to use a new FloquetBasis class which manages the transformations
from lab to Floquet basis and back.
• Many of the internal methods used by the old Floquet solvers have been removed. The Floquet tensor may
still be retried using the function floquet_tensor.
• The Floquet Markov Master Equation solver has had many changes and new options added. The environment
temperature may be specified using w_th, and the result states are stored in the lab basis and optionally in
the Floquet basis using store_floquet_state.
• The spectra functions supplied to fmmesolve must now be vectorized (i.e. accept and return numpy arrays
for frequencies and densities) and must accept negative frequence (i.e. usually include a w > 0 factor so that
the returned densities are zero for negative frequencies).
• The number of sidebands to keep, kmax may only be supplied when using the FMESolver
• The Tsteps parameter has been removed from both fsesolve and fmmesolve. The precompute option
to FloquetBasis may be used instead.
Evolution of State Solver (essovle):
• The function essolve has been removed. Use the diag integration method with sesolve or mesolve
instead.
Steady-state solvers (steadystate module):
• The method parameter and solver parameters have been separated. Previously they were mixed together
in the method parameter.
• The previous options are now passed as parameters to the steady state solver and mostly passed through to
the underlying SciPy functions.
• The logging and statistics have been removed.
Correlation functions (correlation module):
• A new correlation_3op function has been added. It supports MESolver or BRMESolver.
• The correlation, correlation_4op, and correlation_ss functions have been removed.
• Support for calculating correlation with mcsolve has been removed.
Propagators (propagator module):
• A class interface, qutip.Propagator, has been added for propagators.
• Propagation of time-dependent systems is now supported using QobjEvo.
• The unitary_mode and parallel options have been removed.
Correlation spectra (spectrum module):
• The functions spectrum_ss and spectrum_pi have been removed and are now internal functions.
• The use_pinv parameter for spectrum has been removed and the functionality merged into the solver
parameter. Use solver="pi" instead.
Hierarchical Equation of Motion Solver (HEOM)
• Updated the solver to use the new QuTiP integrators and data layer.
• Updated all the HEOM tutorials to QuTiP 5.
• Added support for combining bosonic and fermionic baths.
• Sped up the construction of the RHS of the HEOM solver by a factor of 4x.
• As in QuTiP 4, the HEOM supports arbitrary spectral densities, bosonic and fermionic baths, Páde and
Matsubara expansions of the correlation functions, calculating the Matsubara terminator and inspection of
the ADOs (auxiliary density operators).
There have been numerous other small changes to core QuTiP features:
• qft(...) the function that returns the quantum Fourier transform operator was moved from qutip.qip.
algorithm into qutip.
• The Bloch-Redfield solver tensor, brtensor, has been moved into qutip.core. See the section above on
the Bloch-Redfield solver for details.
• The functions mat2vec and vec2mat for transforming states to and from super-operator states have been
renamed to stack_columns and unstack_columns.
• The function liouvillian_ref has been removed. Used liouvillian instead.
• The superoperator transforms super_to_choi, choi_to_super, choi_to_kraus, choi_to_chi and
chi_to_choi have been removed. Used to_choi, to_super, to_kraus and to_chi instead.
• All of the random object creation functions now accepted a numpy Generator as a seed.
• The dims parameter of all random object creation functions has been removed. Supply the dimensions as
the first parameter if explicit dimensions are required.
• The function rand_unitary_haar has been removed. Use rand_unitary(distribution="haar") in-
stead.
• The functions rand_dm_hs and rand_dm_ginibre have been removed. Use
rand_dm(distribution="hs") and rand_dm(distribution="ginibre") instead.
• The function rand_ket_haar has been removed. Use rand_ket(distribution="haar") instead.
• The measurement functions have had the target parameter for expanding the measurement operator re-
moved. Used expand_operator to expand the operator instead.
• qutip.Bloch now supports applying colours per-point, state or vector in add_point, add_states, and
add_vectors.
• Dimensions use a class instead of layered lists.
• Allow measurement functions to support degenerate operators.
• Add qeye_like and qzero_like.
• Added fermionic annihilation and creation operators.
Previously qutip.settings was an ordinary module. Now qutip.settings is an instance of a settings class.
All the runtime modifiable settings for core operations are in qutip.settings.core. The other settings are not
modifiable at runtime.
• Removed load. reset and save functions.
• Removed .debug, .fortran, .openmp_thresh.
• New .compile stores the compilation options for compiled coefficients.
• New .core["rtol"] core option gives the default relative tolerance used by QuTiP.
• The absolute tolerance setting .atol has been moved to .core["atol"].
6.5.7 Visualization
• qutip.qip has been moved into its own package, qutip-qip. Once installed, qutip-qip is available as either
qutip.qip or qutip_qip. Some widely useful gates have been retained in qutip.gates.
• qutip.control has been moved to qutip-qtrl and once installed qutip-qtrl is available as either qutip.
control or qutip_qtrl. Note that quitp_qtrl is provided primarily for backwards compatibility. Im-
provements to optimal control will take place in the new qutip_qoc package.
• qutip.lattice has been moved into its own package, qutip-lattice. It is available from
<https://github.com/qutip/qutip-lattice>.
• qutip.sparse has been removed. It contained the old sparse matrix representation and is replaced by the
new implementation in qutip.data.
• qutip.piqs functions are no longer available from the qutip namespace. They are accessible from qutip.
piqs instead.
6.5.9 Miscellaneous
• Support has been added for 64-bit integer sparse matrix indices, allowing sparse matrices with up to 2**63
rows and columns. This support needs to be enabled at compilation time by calling setup.py and passing
--with-idxint-64.
• Support for OpenMP has been removed. If there is enough demand and a good plan for how to organize it,
OpenMP support may return in a future QuTiP release.
• The qutip.parfor function has been removed. Use qutip.parallel_map instead.
• qutip.graph has been removed and replaced by SciPy’s graph functions.
• qutip.topology has been removed. It contained only one function berry_curvature.
• The ~/.qutip/qutiprc config file is no longer supported. It contained settings for the OpenMP support.
• Deprecate three_level_atom
• Deprecate orbital
6.5.12 Features
6.5.13 Miscellaneous
6.6.1 Features
• Add the possibility to customize point colors as in V4 and fix point plot behavior for ‘l’ style (#1974, by
Daniel Moreno Galán)
• Disabled broken “improved sampling” for nm_mcsolve. (#2234, by Paul)
• Fixed result objects storing a reference to the solver through options._feedback. (#2262, by Paul)
• Fixed simdiag not returning orthonormal eigenvectors. (#2269, by Sola85)
• Fix LaTeX display of Qobj state in Jupyter cell outputs (#2272, by Edward Thomas)
• Improved behavior of parallel_map and loky_pmap in the case of timeouts, errors or keyboard interrupts
(#2280, by Paul)
• Ignore deprecation warnings from cython 0.29.X in tests. (#2288)
• Fixed two problems with the steady_state() solver in the HEOM method. (#2333)
6.6.3 Miscellaneous
6.7.1 Features
6.7.3 Removals
6.7.4 Documentation
• Add a guide on Superoperators, Pauli Basis and Channel Contraction. (#1984 by christian512)
• Added information on sec_cutoff to the documentation (#2136 by Gerardo Jose Suarez)
• Added inherited members to API doc of MESolver, SMESolver, SSESolver, NonMarkovianMCSolver
(#2167 by Cristian Emiliano Godinez Ramirez)
• Corrected grammar in Bloch-Redfield master equation documentation (#2174 by Andrey Rakhubovsky)
6.7.5 Miscellaneous
QuTiP 5 is a redesign of many of the core components of QuTiP (Qobj, QobjEvo, solvers) to make them more
consistent and more flexible.
Qobj may now be stored in either sparse or dense representations, and the two may be mixed sensibly as needed.
QobjEvo is now used consistently throughout QuTiP, and the implementation has been substantially cleaned up.
A new Coefficient class is used to represent the time-dependent factors inside QobjEvo.
The solvers have been rewritten to work well with the new data layer and the concept of Integrators which solve
ODEs has been introduced. In future, new data layers may provide their own Integrators specialized to their
representation of the underlying data.
Much of the user-facing API of QuTiP remains familiar, but there have had to be many small breaking changes. If
we can make changes to easy migrating code from QuTiP 4 to QuTiP 5, please let us know.
Any extensive list of changes follows.
6.7.6 Contributors
QuTiP 5 has been a large effort by many people over the last three years.
In particular:
• Jake Lishman led the implementation of the new data layer and coefficients.
• Eric Giguère led the implementation of the new QobjEvo interface and solvers.
• Boxi Li led the updating of QuTiP’s QIP support and the creation of qutip_qip.
Other members of the QuTiP Admin team have been heavily involved in reviewing, testing and designing QuTiP
5:
• Alexander Pitchford
• Asier Galicia
• Nathan Shammah
• Shahnawaz Ahmed
• Neill Lambert
• Simon Cross
Two Google Summer of Code contributors updated the tutorials and benchmarks to QuTiP 5:
• Christian Staufenbiel updated many of the tutorials (<https://github.com/qutip/qutip-tutorials/>).
• Xavier Sproken update the benchmarks (<https://github.com/qutip/qutip-benchmark/>).
Four experimental data layers backends were written either as part of Google Summer of Code or as separate
projects. While these are still alpha quality, the helped significantly to test the data layer API:
• qutip-tensorflow: a TensorFlow backend by Asier Galicia (<https://github.com/qutip/qutip-
tensorflow>)
• qutip-cupy: a CuPy GPU backend by Felipe Bivort Haiek (<https://github.com/qutip/qutip-cupy/>)`
• qutip-tensornetwork: a TensorNetwork backend by Asier Galicia (<https://github.com/qutip/qutip-
tensornetwork>)
• qutip-jax: a JAX backend by Eric Giguère (<https://github.com/qutip/qutip-jax/>)
We have also had many other contributors, whose specific contributions are detailed below:
• Pieter Eendebak (updated the required SciPy to 1.4+, #1982 <https://github.com/qutip/qutip/pull/1982>).
• Pieter Eendebak (reduced import times by setting logger names, #1981
<https://github.com/qutip/qutip/pull/1981>)
• Xavier Sproken (included C header files in the source distribution, #1971
<https://github.com/qutip/qutip/pull/1971>)
• Christian Staufenbiel (added support for multiple collapse operators to the Floquet solver, #1962
<https://github.com/qutip/qutip/pull/1962>)
• Christian Staufenbiel (fixed the basis used in the Floquet Master Equation solver, #1952
<https://github.com/qutip/qutip/pull/1952>)
• Christian Staufenbiel (allowed the bloch_redfield_tensor function to accept strings and callables for
a_ops, #1951 <https://github.com/qutip/qutip/pull/1951>)
Previously Qobj data was stored in a SciPy-like sparse matrix. Now the representation is flexible. Implementations
for dense and sparse formats are included in QuTiP and custom implementations are possible. QuTiP’s performance
on dense states and operators is significantly improved as a result.
Some highlights:
• The data is still acessible via the .data attribute, but is now an instance of the underlying data type instead of
a SciPy-like sparse matrix. The operations available in qutip.core.data may be used on .data, regardless
of the data type.
• Qobj with different data types may be mixed in arithmetic and other operations. A sensible output type will
be automatically determined.
• The new .to(...) method may be used to convert a Qobj from one data type to another. E.g. .
to("dense") will convert to the dense representation and .to("csr") will convert to the sparse type.
• Many Qobj methods and methods that create Qobj now accepted a dtype parameter that allows the data
type of the returned Qobj to specified.
• The new & operator may be used to obtain the tensor product.
• The new @ operator may be used to obtain the matrix / operator product. bar @ ket returns a scalar.
• The new .contract() method will collapse 1D subspaces of the dimensions of the Qobj.
• The new .logm() method returns the matrix logarithm of an operator.
• The methods .set_data, .get_data, .extract_state, .eliminate_states, .evaluate and .
check_isunitary have been removed.
The QobjEvo type for storing time-dependent quantum objects has been significantly expanded, standardized and
extended. The time-dependent coefficients are now represented using a new Coefficient type that may be inde-
pendently created and manipulated if required.
Some highlights:
• The .compile() method has been removed. Coefficients specified as strings are automatically compiled if
possible and the compilation is cached across different Python runs and instances.
• Mixing coefficient types within a single Qobj is now supported.
• Many new attributes were added to QobjEvo for convenience. Examples include .dims, .shape, .
superrep and .isconstant.
• Many old attributes such as .cte, .use_cython, .type, .const, and .coeff_file were removed.
• A new Spline coefficient supports spline interpolations of different orders. The old Cubic_Spline coef-
ficient has been removed.
• The new .arguments(...) method allows additional arguments to the underlying coefficient functions to
be updated.
• The _step_func_coeff argument has been replaced by the order parameter. _step_func_coeff=False
is equivalent to order=3. _step_func_coeff=True is equivalent to order=0. Higher values of order
gives spline interpolations of higher orders.
The solvers in QuTiP have been heavily reworked and standardized. Under the hood solvers now make use of
swappable ODE Integrators. Many Integrators are included (see the list below) and custom implementations
are possible. Solvers now consistently accept a QobjEvo instance at the Hamiltonian or Liouvillian, or any object
which can be passed to the QobjEvo constructor.
A breakdown of highlights follows.
All solvers:
• Solver options are now supplied in an ordinary Python dict. qutip.Options is deprecated and returns a
dict for backwards compatibility.
• A specific ODE integrator may be selected by supplying a method option.
• Each solver provides a class interface. Creating an instance of the class allows a solver to be run multiple
times for the same system without having to repeatedly reconstruct the right-hand side of the ODE to be
integrated.
• A QobjEvo instance is accepted for most operators, e.g., H, c_ops, e_ops, a_ops.
• The progress bar is now selected using the progress_bar option. A new progess bar using the tqdm Python
library is provided.
• Dynamic arguments, where the value of an operator depends on the current state of the evolution, have been
removed. They may be re-implemented later if there is demand for them.
Integrators:
• The SciPy zvode integrator is available with the BDF and Adams methods as bdf and adams.
• The SciPy dop853 integrator (an eighth order Runge-Kutta method by Dormand & Prince) is available as
dop853.
• The SciPy lsoda integrator is available as lsoda.
• QuTiP’s own implementation of Verner’s “most efficient” Runge-Kutta methods of order 7 and 9 are available
as vern7 and vern9. See http://people.math.sfu.ca/~jverner/ for a description of the methods.
• QuTiP’s own implementation of a solver that directly diagonalizes the the system to be integrated is available
as diag. It only works on time-independent systems and is slow to setup, but once the diagonalization is
complete, it generates solutions very quickly.
• QuTiP’s own implementatoin of an approximate Krylov subspace integrator is available as krylov. This
integrator is only usable with sesolve.
Result class:
• A new .e_data attribute provides expectation values as a dictionary. Unlike .expect, the values are pro-
vided in a Python list rather than a numpy array, which better supports non-numeric types.
• The contents of the .stats attribute changed significantly and is now more consistent across solvers.
Monte-Carlo Solver (mcsolve):
• The system, H, may now be a super-operator.
• The seed parameter now supports supplying numpy SeedSequence or Generator types.
• The new timeout and target_tol parameters allow the solver to exit early if a timeout or target tolerance
is reached.
• The ntraj option no longer supports a list of numbers of trajectories. Instead, just run the solver multiple
times and use the class MCSolver if setting up the solver uses a significant amount of time.
• The map_func parameter has been replaced by the map option. In addition to the existing serial and
parallel values, the value loky may be supplied to use the loky package to parallelize trajectories.
• The result returned by mcsolve now supports calculating photocurrents and calculating the steady state over
N trajectories.
• The old parfor parallel execution function has been removed from qutip.parallel. Use parallel_map
or loky_map instead.
Bloch-Redfield Master Equation Solver (brmesolve):
• The a_ops and spectra support implementaitons been heavily reworked to reuse the techniques from the
new Coefficient and QobjEvo classes.
• The use_secular parameter has been removed. Use sec_cutoff=-1 instead.
• The required tolerance is now read from qutip.settings.
Krylov Subspace Solver (krylovsolve):
• The Krylov solver is now implemented using SESolver and the krylov ODE integrator. The function
krylovsolve is maintained for convenience and now supports many more options.
• The sparse parameter has been removed. Supply a sparse Qobj for the Hamiltonian instead.
Floquet Solver (fsesolve and fmmesolve):
• The Floquet solver has been rewritten to use a new FloquetBasis class which manages the transformations
from lab to Floquet basis and back.
• Many of the internal methods used by the old Floquet solvers have been removed. The Floquet tensor may
still be retried using the function floquet_tensor.
• The Floquet Markov Master Equation solver has had many changes and new options added. The environment
temperature may be specified using w_th, and the result states are stored in the lab basis and optionally in
the Floquet basis using store_floquet_state.
• The spectra functions supplied to fmmesolve must now be vectorized (i.e. accept and return numpy arrays
for frequencies and densities) and must accept negative frequence (i.e. usually include a w > 0 factor so that
the returned densities are zero for negative frequencies).
• The number of sidebands to keep, kmax may only be supplied when using the FMESolver
• The Tsteps parameter has been removed from both fsesolve and fmmesolve. The precompute option
to FloquetBasis may be used instead.
Evolution of State Solver (essovle):
• The function essolve has been removed. Use the diag integration method with sesolve or mesolve
instead.
Steady-state solvers (steadystate module):
• The method parameter and solver parameters have been separated. Previously they were mixed together
in the method parameter.
• The previous options are now passed as parameters to the steady state solver and mostly passed through to
the underlying SciPy functions.
• The logging and statistics have been removed.
Correlation functions (correlation module):
• A new correlation_3op function has been added. It supports MESolver or BRMESolver.
• The correlation, correlation_4op, and correlation_ss functions have been removed.
• Support for calculating correlation with mcsolve has been removed.
There have been numerous other small changes to core QuTiP features:
• qft(...) the function that returns the quantum Fourier transform operator was moved from qutip.qip.
algorithm into qutip.
• The Bloch-Redfield solver tensor, brtensor, has been moved into qutip.core. See the section above on
the Bloch-Redfield solver for details.
• The functions mat2vec and vec2mat for transforming states to and from super-operator states have been
renamed to stack_columns and unstack_columns.
• The function liouvillian_ref has been removed. Used liouvillian instead.
• The superoperator transforms super_to_choi, choi_to_super, choi_to_kraus, choi_to_chi and
chi_to_choi have been removed. Used to_choi, to_super, to_kraus and to_chi instead.
• All of the random object creation functions now accepted a numpy Generator as a seed.
• The dims parameter of all random object creation functions has been removed. Supply the dimensions as
the first parameter if explicit dimensions are required.
• The function rand_unitary_haar has been removed. Use rand_unitary(distribution="haar") in-
stead.
• The functions rand_dm_hs and rand_dm_ginibre have been removed. Use
rand_dm(distribution="hs") and rand_dm(distribution="ginibre") instead.
• The function rand_ket_haar has been removed. Use rand_ket(distribution="haar") instead.
• The measurement functions have had the target parameter for expanding the measurement operator re-
moved. Used expand_operator to expand the operator instead.
• qutip.Bloch now supports applying colours per-point, state or vector in add_point, add_states, and
add_vectors.
Previously qutip.settings was an ordinary module. Now qutip.settings is an instance of a settings class.
All the runtime modifiable settings for core operations are in qutip.settings.core. The other settings are not
modifiable at runtime.
• Removed load. reset and save functions.
• Removed .debug, .fortran, .openmp_thresh.
• New .compile stores the compilation options for compiled coefficients.
• New .core["rtol"] core option gives the default relative tolerance used by QuTiP.
• The absolute tolerance setting .atol has been moved to .core["atol"].
• qutip.qip has been moved into its own package, qutip-qip. Once installed, qutip-qip is available as either
qutip.qip or qutip_qip. Some widely useful gates have been retained in qutip.gates.
• qutip.lattice has been moved into its own package, qutip-lattice. It is available from
<https://github.com/qutip/qutip-lattice>.
• qutip.sparse has been removed. It contained the old sparse matrix representation and is replaced by the
new implementation in qutip.data.
• qutip.piqs functions are no longer available from the qutip namespace. They are accessible from qutip.
piqs instead.
6.7.13 Miscellaneous
• Support has been added for 64-bit integer sparse matrix indices, allowing sparse matrices with up to 2**63
rows and columns. This support needs to be enabled at compilation time by calling setup.py and passing
--with-idxint-64.
• Support for OpenMP has been removed. If there is enough demand and a good plan for how to organize it,
OpenMP support may return in a future QuTiP release.
• The qutip.parfor function has been removed. Use qutip.parallel_map instead.
• qutip.graph has been removed and replaced by SciPy’s graph functions.
• qutip.topology has been removed. It contained only one function berry_curvature.
• The ~/.qutip/qutiprc config file is no longer supported. It contained settings for the OpenMP support.
Patch release for QuTiP 4.7. It adds support for SciPy 1.12.
• Remove use of scipy.<numpy-func> in parallel.py, incompatible with scipy==1.12 (#2305 by Evan McKin-
ney)
6.9.2 Miscellaneous
• Rework choi_to_kraus, making it rely on an eigenstates solver that can choose eigh if the Choi matrix is
Hermitian, as it is more numerically stable. (#2276, by Bogdan Reznychenko)
• Rework kraus_to_choi, making it faster (#2283, by Bogdan Reznychenko and Rafael Haenel)
6.10.2 Miscellaneous
This is a bugfix release for QuTiP 4.7.X. It adds support for numpy 1.25 and scipy 1.11.
• Fix setting of sso.m_ops in heterodyne smesolver and passing through of sc_ops to photocurrent solver.
(#2081 by Bogdan Reznychenko and Simon Cross)
• Update calls to SciPy eigvalsh and eigsh to pass the range of eigenvalues to return using subset_by_index=.
(#2081 by Simon Cross)
• Fixed bug where some matrices were wrongly found to be hermitian. (#2082 by AGaliciaMartinez)
6.11.2 Miscellaneous
This is a bugfix release for QuTiP 4.7.X. In addition to the minor fixes listed below, the release adds builds for
Python 3.11 and support for packaging 22.0.
6.11.3 Features
• Change floquet_master_equation_rates(. . . ) to use an adaptive number of time steps scaled by the number
of sidebands, kmax. (#1961)
• Change fidelity(A, B) to use the reduced fidelity formula for pure states which is more numerically efficient
and accurate. (#1964)
• Change brmesolve to raise an exception when ode integration is not successful. (#1965)
• Backport fix for IPython helper Bloch._repr_svg_ from dev.major. Previously the print_figure function re-
turned bytes, but since ipython/ipython#5452 (in 2014) it returns a Unicode string. This fix updates QuTiP’s
helper to match. (#1970)
• Fix correlation for case where only the collapse operators are time dependent. (#1979)
• Fix the hinton visualization method to plot the matrix instead of its transpose. (#2011)
• Fix the hinton visualization method to take into account all the matrix coefficients to set the squares scale,
instead of only the diagonal coefficients. (#2012)
• Fix parsing of package versions in setup.py to support packaging 22.0. (#2037)
• Add back .qu suffix to objects saved with qsave and loaded with qload. The suffix was accidentally removed
in QuTiP 4.7.0. (#2038)
• Add a default max_step to processors. (#2040)
6.11.5 Documentation
6.11.6 Miscellaneous
• Return TypeError instead of Exception for type error in sesolve argument. (#1924)
• Add towncrier draft build of changelog to CI tests. (#1946)
• Add Python 3.11 to builds. (#2041)
• Simplify version parsing by using packaging.version.Version. (#2043)
• Update builds to use cibuildwheel 2.11, and to build with manylinux2014 on Python 3.8 and 3.9, since numpy
and SciPy no longer support manylinux2010 on those versions of Python. (#2047)
This release sees the addition of two new solvers – qutip.krylovsolve based on the Krylov subspace approxi-
mation and qutip.nonmarkov.heom that reimplements the BoFiN HEOM solver.
Bloch sphere rendering gained support for drawing arcs and lines on the sphere, and for setting the transparency
of rendered points and vectors, Hinton plots gained support for specifying a coloring style, and matrix histograms
gained better default colors and more flexible styling options.
Other significant improvements include better scaling of the Floquet solver, support for passing Path objects when
saving and loading files, support for passing callable functions as e_ops to mesolve and sesolve, and faster state
number enumeration and Husimi Q functions.
Import bugfixes include some bugs affecting plotting with matplotlib 3.5 and fixing support for qutrits (and other
non-qubit) quantum circuits.
The many other small improvements, bug fixes, documentation enhancements, and behind the scenese development
changes are included in the list below.
QuTiP 4.7.X will be the last series of releases for QuTiP 4. Patch releases will continue for the 4.7.X series but the
main development effort will move to QuTiP 5.
The many, many contributors who filed issues, submitted or reviewed pull requests, and improved the documenta-
tion for this release are listed next to their contributions below. Thank you to all of you.
6.11.7 Improvements
• MAJOR Added krylovsolve as a new solver based on krylov subspace approximation. (#1739 by Emiliano
Fortes)
• MAJOR Imported BoFiN HEOM (https://github.com/tehruhn/bofin/) into QuTiP and replaced the HEOM
solver with a compatibility wrapper around BoFiN bosonic solver. (#1601, #1726, and #1724 by Simon
Cross, Tarun Raheja and Neill Lambert)
• MAJOR Added support for plotting lines and arcs on the Bloch sphere. (#1690 by Gaurav Saxena, Asier
Galicia and Simon Cross)
• Added transparency parameter to the add_point, add_vector and add_states methods in the Bloch and
Bloch3d classes. (#1837 by Xavier Spronken)
• Support Path objects in qutip.fileio. (#1813 by Adrià Labay)
• Improved the weighting in steadystate solver, so that the default weight matches the documented behaviour
and the dense solver applies the weights in the same manner as the sparse solver. (#1275 and #1802 by NS2
Group at LPS and Simon Cross)
• Added a color_style option to the hinton plotting function. (#1595 by Cassandra Granade)
• Improved the scaling of floquet_master_equation_rates and floquet_master_equation_tensor
and fixed transposition and basis change errors in floquet_master_equation_tensor and
floquet_markov_mesolve. (#1248 by Camille Le Calonnec, Jake Lishman and Eric Giguère)
• Removed linspace_with and view_methods from qutip.utilities. For the former it is far better
to use numpy.linspace and for the later Python’s in-built help function or other tools. (#1680 by Eric
Giguère)
• Added support for passing callable functions as e_ops to mesolve and sesolve. (#1655 by Marek Naroż-
niak)
• Added the function steadystate_floquet, which returns the “effective” steadystate of a periodic driven
system. (#1660 by Alberto Mercurio)
• Improved mcsolve memory efficiency by not storing final states when they are not needed. (#1669 by Eric
Giguère)
• Improved the default colors and styling of matrix_histogram and provided additional styling options. (#1573
and #1628 by Mahdi Aslani)
• Sped up state_number_enumerate, state_number_index, state_index_number, and added some
error checking. enr_state_dictionaries now returns a list for idx2state. (#1604 by Johannes Feist)
• Added new Husimi Q algorithms, improving the speed for density matrices, and giving a near order-of-
magnitude improvement when calculating the Q function for many different states, using the new qutip.
QFunc class, instead of the qutip.qfunc function. (#934 and #1583 by Daniel Weigand and Jake Lishman)
• Updated licence holders with regards to new governance model, and remove extraneous licensing information
from source files. (#1579 by Jake Lishman)
• Removed the vendored copy of LaTeX’s qcircuit package which is GPL licensed. We now rely on the package
being installed by user. It is installed by default with TexLive. (#1580 by Jake Lishman)
• The signatures of rand_ket and rand_ket_haar were changed to allow N (the size of the random ket) to be
determined automatically when dims are specified. (#1509 by Purva Thakre)
• Fix circuit index used when plotting circuits with non-reversed states. (#1847 by Christian Staufenbiel)
• Changed implementation of qutip.orbital to use scipy.special.spy_harm to remove bugs in angle
interpretation. (#1844 by Christian Staufenbiel)
• Fixed QobjEvo.tidyup to use settings.auto_tidyup_atol when removing small elements in sparse
matrices. (#1832 by Eric Giguère)
• Ensured that tidyup’s default tolerance is read from settings at each call. (#1830 by Eric Giguère)
• Fixed scipy.sparse deprecation warnings raised by qutip.fast_csr_matrix. (#1827 by Simon Cross)
• Fixed rendering of vectors on the Bloch sphere when using matplotlib 3.5 and above. (#1818 by Simon
Cross)
• Fixed the displaying of Lattice1d instances and their unit cells. Previously calling them raised exceptions
in simple cases. (#1819, #1697 and #1702 by Simon Cross and Saumya Biswas)
• Fixed the displaying of the title for hinton and matrix_histogram plots when a title is given. Previously
the supplied title was not displayed. (#1707 by Vladimir Vargas-Calderón)
• Removed an incorrect check on the initial state dimensions in the QubitCircuit constructor. This allows,
for example, the construction of qutrit circuits. (#1807 by Boxi Li)
• Fixed the checking of method and offset parameters in coherent and coherent_dm. (#1469 and #1741
by Joseph Fox-Rabinovitz and Simon Cross)
• Removed the Hamiltonian saved in the sesolve solver results. (#1689 by Eric Giguère)
• Fixed a bug in rand_herm with pos_def=True and density>0.5 where the diagonal was incorrectly filled.
(#1562 by Eric Giguère)
• Add GitHub actions test run on windows-latest. (#1853 and #1855 by Simon Cross)
• Bumped the version of pillow used to build documentation from 9.0.0 to 9.0.1. (#1835 by dependabot)
• Migrated the qutip.superop_reps tests to pytest. (#1825 by Felipe Bivort Haiek)
• Migrated the qutip.steadystates tests to pytest. (#1679 by Eric Giguère)
• Changed the README.md CI badge to the GitHub Actions badge. (#1581 by Jake Lishman)
• Updated CodeClimate configuration to treat our Python source files as Python 3. (#1577 by Jake Lishman)
• Reduced cyclomatic complexity in qutip._mkl. (#1576 by Jake Lishman)
• Fixed PEP8 warnings in qutip.control, qutip.mcsolve, qutip.random_objects, and qutip.
stochastic. (#1575 by Jake Lishman)
• Bumped the version of urllib3 used to build documentation from 1.26.4 to 1.26.5. (#1563 by dependabot)
• Moved tests to GitHub Actions. (#1551 by Jake Lishman)
• The GitHub contributing guidelines were re-added and updated to point to the more complete guidelines in
the documentation. (#1549 by Jake Lishman)
• The release documentation was reworked after the initial 4.6.1 to match the actual release process. (#1544
by Jake Lishman)
This minor release adds support for numpy 1.22 and Python 3.10 and removes some blockers for running QuTiP
on the Apple M1.
The performance of the enr_destroy, state_number_enumerate and hadamard_transform functions was
drastically improved (up to 70x or 200x faster in some common cases), and support for the drift Hamiltonian was
added to the qutip.qip Processor.
The qutip.hardware_info module was removed as part of adding support for the Apple M1. We hope the
removal of this little-used module does not adversely affect many users – it was largely unrelated to QuTiP’s core
functionality and its presence was a continual source of blockers to importing qutip on new or changed platforms.
A new check on the dimensions of Qobj’s were added to prevent segmentation faults when invalid shape and
dimension combinations were passed to Cython code.
In addition, there were many small bugfixes, documentation improvements, and improvements to our building and
testing processes.
6.11.11 Improvements
• The enr_destroy function was made ~200x faster in many simple cases. (#1593 by Johannes Feist)
• The state_number_enumerate function was made significantly faster. (#1594 by Johannes Feist)
• Added the missing drift Hamiltonian to the method run_analytically of Processor. (#1603 Boxi Li)
• The hadamard_transform was made much faster, e.g., ~70x faster for N=10. (#1688 by Asier Galicia)
• Added support for computing the power of a scalar-like Qobj. (#1692 by Asier Galicia)
• Removed the hardware_info module. This module wasn’t used inside QuTiP and regularly broke when
new operating systems were released, and in particular prevented importing QuTiP on the Apple M1. (#1754,
#1758 by Eric Giguère)
• Fixed support for calculating the propagator of a density matrix with collapse operators. QuTiP 4.6.2 intro-
duced extra sanity checks on the dimensions of inputs to mesolve (Fix mesolve segfault with bad initial state
#1459), but the propagator function’s calls to mesolve violated these checks by supplying initial states with
the dimensions incorrectly set. propagator now calls mesolve with the correct dimensions set on the initial
state. (#1588 by Simon Cross)
• Fixed support for calculating the propagator for a superoperator without collapse operators. This function-
ality was not tested by the test suite and appears to have broken sometime during 2019. Tests have now been
added and the code breakages fixed. (#1588 by Simon Cross)
• Fixed the ignoring of the random number seed passed to rand_dm in the case where pure was set to true.
(#1600 Pontus Wikståhl)
• Fixed qutip.control.optimize_pulse support for sparse eigenvector decomposition with the Qobj oper_dtype
(the Qobj oper_dtype is the default for large systems). (#1621 by Simon Cross)
• Removed qutip.control.optimize_pulse support for scipy.sparse.csr_matrix and generic ndarray-like matri-
ces. Support for these was non-functional. (#1621 by Simon Cross)
• Fixed errors in the calculation of the Husimi spin_q_function and spin_wigner functions and added tests for
them. (#1632 by Mark Johnson)
• Fixed setting of OpenMP compilation flag on Linux. Previously when compiling the OpenMP functions
were compiled without parallelization. (#1693 by Eric Giguère)
• Fixed tracking the state of the Bloch sphere figure and axes to prevent exceptions during rendering. (#1619
by Simon Cross)
• Fixed compatibility with numpy configuration in numpy’s 1.22.0 release. (#1752 by Matthew Treinish)
• Added dims checks for e_ops passed to solvers to prevent hanging the calling process when e_ops of the
wrong dimensions were passed. (#1778 by Eric Giguère)
• Added a check in Qobj constructor that the respective members of data.shape cannot be larger than what the
corresponding dims could contain to prevent a segmentation fault caused by inconsistencies between dims
and shapes. (#1783, #1785, #1784 by Lajos Palanki & Eric Giguère)
• Added docs for the num_cbits parameter of the QubitCircuit class. (#1652 by Jon Crall)
• Fixed the parameters in the call to fsesolve in the Floquet guide. (#1675 by Simon Cross)
• Fixed the description of random number usage in the Monte Carlo solver guide. (#1677 by Ian Thorvaldson)
• Fixed the rendering of equation numbers in the documentation (they now appear on the right as expected,
not above the equation). (#1678 by Simon Cross)
• Updated the installation requirements in the documentation to match what is specified in setup.py. (#1715
by Asier Galicia)
• Fixed a typo in the chi_to_choi documentation. Previously the documentation mixed up chi and choi.
(#1731 by Pontus Wikståhl)
• Improved the documentation for the stochastic equation solvers. Added links to notebooks with examples,
API doumentation and external references. (#1743 by Leonardo Assis)
• Fixed a typo in qutip.settings in the settings guide. (#1786 by Mahdi Aslani)
• Made numerous small improvements to the text of the QuTiP basics guide. (#1768 by Anna Naden)
• Made a small phrasing improvement to the README. (#1790 by Rita Abani)
• Improved test coverage of states and operators functions. (#1578 by Eric Giguère)
• Fixed test_interpolate mcsolve use (#1645 by Eric Giguère)
• Ensured figure plots are explicitly closed during tests so that the test suite passes when run headless under
Xvfb. (#1648 by Simon Cross)
• Bumped the version of pillow used to build documentation from 8.2.0 to 9.0.0. (#1654, #1760 by dependabot)
• Bumped the version of babel used to build documentation from 2.9.0 to 2.9.1. (#1695 by dependabot)
• Bumped the version of numpy used to build documentation from 1.19.5 to 1.21.0. (#1767 by dependabot)
• Bumped the version of ipython used to build documentation from 7.22.0 to 7.31.1. (#1780 by dependabot)
• Rename qutip.bib to CITATION.bib to enable GitHub’s citation support. (#1662 by Ashish Panigrahi)
• Added tests for simdiags. (#1681 by Eric Giguère)
• Added support for specifying the numpy version in the CI test matrix. (#1696 by Simon Cross)
• Fixed the skipping of the dnorm metric tests if cvxpy is not installed. Previously all metrics tests were
skipped by accident. (#1704 by Florian Hopfmueller)
• Added bug report, feature request and other options to the GitHub issue reporting template. (#1728 by
Aryaman Kolhe)
• Updated the build process to support building on Python 3.10 by removing the build requirement for numpy
< 1.20 and replacing it with a requirement on oldest-supported-numpy. (#1747 by Simon Cross)
• Updated the version of cibuildwheel used to build wheels to 2.3.0. (#1747, #1751 by Simon Cross)
• Added project urls to linking to the source repository, issue tracker and documentation to setup.cfg. (#1779
by Simon Cross)
• Added a numpy 1.22 and Python 3.10 build to the CI test matrix. (#1777 by Simon Cross)
• Ignore deprecation warnings from SciPy 1.8.0 scipy.sparse.X imports in CI tests. (#1797 by Simon Cross)
• Add building of wheels for Python 3.10 to the cibuildwheel job. (#1796 by Simon Cross)
This minor release adds a function to calculate the quantum relative entropy, fixes a corner case in handling time-
dependent Hamiltonians in mesolve and adds back support for a wider range of matplotlib versions when plotting
or animating Bloch spheres.
It also adds a section in the README listing the papers which should be referenced while citing QuTiP.
6.11.15 Improvements
• Added a “Citing QuTiP” section to the README, containing a link to the QuTiP papers. (#1554)
• Added entropy_relative which returns the quantum relative entropy between two density matrices.
(#1553)
• Fixed Bloch sphere distortion when using Matplotlib >= 3.3.0. (#1496)
• Removed use of integer-like floats in math.factorial since it is deprecated as of Python 3.9. (#1550)
• Simplified call to ffmpeg used in the the Bloch sphere animation tutorial to work with recent versions of
ffmpeg. (#1557)
• Removed blitting in Bloch sphere FuncAnimation example. (#1558)
• Added a version checking condition to handle specific functionalities depending on the matplotlib version.
(#1556)
• Fixed mesolve handling of time-dependent Hamiltonian with a custom tlist and c_ops. (#1561)
This minor release fixes bugs in QIP gate definitions, fixes building from the source tarball when git is not installed
and works around an MKL bug in versions of SciPy <= 1.4.
It also adds the [full] pip install target so that pip install qutip[full] installs qutip and all of its optional
and developer dependencies.
6.11.18 Improvements
• Work around pointer MKL eigh bug in SciPy <= 1.4 (by Felipe Bivort Haiek)
• Fix berkeley, swapalpha and cz gate operations (by Boxi Li)
• Expose the CPHASE control gate (by Boxi Li)
• Fix building from the sdist when git is not installed (by Jake Lishman)
• Move the qutip-doc documentation into the qutip repository (by Jake Lishman)
• Fix warnings in documentation build (by Jake Lishman)
• Fix warnings in pytest runs and make pytest treat warnings as errors (by Jake Lishman)
• Add Simon Cross as author (by Simon Cross)
This release brings improvements for qubit circuits, including a pulse scheduler, measurement statistics, read-
ing/writing OpenQASM and optimisations in the circuit simulations.
This is the first release to have full binary wheel releases on pip; you can now do pip install qutip on almost
any machine to get a correct version of the package without needing any compilers set up. The support for Numpy
1.20 that was first added in QuTiP 4.5.3 is present in this version as well, and the same build considerations
mentioned there apply here too. If building using the now-supported PEP 517 mechanisms (e.g. python -mbuild
/path/to/qutip), all build dependencies will be correctly satisfied.
6.11.21 Improvements
• MAJOR Add saving, loading and resetting functionality to qutip.settings for easy re-configuration. (by
Eric Giguère)
• MAJOR Add a quantum gate scheduler in qutip.qip.scheduler, to help parallelise the operations of
quantum gates. This supports two scheduling modes: as late as possible, and as soon as possible. (by Boxi
Li)
• MAJOR Improved qubit circuit simulators, including OpenQASM support and performance optimisations.
(by Sidhant Saraogi)
• MAJOR Add tools for quantum measurements and their statistics. (by Simon Cross and Sidhant Saraogi)
• Add support for Numpy 1.20. QuTiP should be compiled against a version of Numpy >= 1.16.6 and <
1.20 (note: does _not_ include 1.20 itself), but such an installation is compatible with any modern version
of Numpy. Source installations from pip understand this constraint.
• Improve the error message when circuit plotting fails. (by Boxi Li)
• Add support for parsing M1 Mac hardware information. (by Xiaoliang Wu)
• Add more single-qubit gates and controlled gates. (by Mateo Laguna and Martín Sande Costa)
• Support decomposition of X, Y and Z gates in circuits. (by Boxi Li)
• Refactor QubitCircuit.resolve_gate() (by Martín Sande Costa)
• Fix dims in the returns from Qobj.eigenstates on superoperators. (by Jake Lishman)
• Calling Numpy ufuncs on Qobj will now correctly raise a TypeError rather than returning a nonsense
ndarray. (by Jake Lishman)
• Convert segfault into Python exception when creating too-large tensor products. (by Jake Lishman)
• Correctly set num_collapse in the output of mesolve. (by Jake Lishman)
• Fix ptrace when all subspaces are being kept, or the subspaces are passed in order. (by Jake Lishman)
• Fix sorting bug in Bloch3d.add_points(). (by pschindler)
• Fix invalid string literals in docstrings and some unclosed files. (by Élie Gouzien)
• Fix Hermicity tests for matrices with values that are within the tolerance of 0. (by Jake Lishman)
• Fix the trace norm being incorrectly reported as 0 for small matrices. (by Jake Lishman)
• Fix issues with dnorm when using CVXPy 1.1 with sparse matrices. (by Felipe Bivort Haiek)
• Fix segfaults in mesolve when passed a bad initial Qobj as the state. (by Jake Lishman)
• Fix sparse matrix construction in PIQS when using Scipy 1.6.1. (by Drew Parsons)
• Fix zspmv_openmp.cpp missing from the pip sdist. (by Christoph Gohlke)
• Fix correlation functions throwing away imaginary components. (by Asier Galicia Martinez)
• Fix QubitCircuit.add_circuit() for SWAP gate. (by Canoming)
• Fix the broken LaTeX image conversion. (by Jake Lishman)
• Fix gate resolution of the FREDKIN gate. (by Bo Yang)
• Fix broken formatting in docstrings. (by Jake Lishman)
6.11.23 Deprecations
• eseries, essolve and ode2es are all deprecated, pending removal in QuTiP 5.0. These are legacy func-
tions and classes that have been left unmaintained for a long time, and their functionality is now better
achieved with QobjEvo or mesolve.
• MAJOR Overhaul of setup and packaging code to make it satisfy PEP 517, and move the build to a matrix
on GitHub Actions in order to release binary wheels on pip for all major platforms and supported Python
versions. (by Jake Lishman)
• Default arguments in Qobj are now None rather than mutable types. (by Jake Lishman)
• Fixed comsumable iterators being used to parametrise some tests, preventing the testing suite from being
re-run within the same session. (by Jake Lishman)
• Remove unused imports, simplify some floats and remove unnecessary list conversions. (by jakobjakob-
son13)
• Improve Travis jobs matrix for specifying the testing containers. (by Jake Lishman)
• Fix coverage reporting on Travis. (by Jake Lishman)
• Added a pyproject.toml file. (by Simon Humpohl and Eric Giguère)
• Add doctests to documentation. (by Sidhant Saraogi)
• Fix all warnings in the documentation build. (by Jake Lishman)
This patch release adds support for Numpy 1.20, made necessary by changes to how array-like objects are handled.
There are no other changes relative to version 4.5.2.
Users building from source should ensure that they build against Numpy versions >= 1.16.6 and < 1.20 (not in-
cluding 1.20 itself), but after that or for those installing from conda, an installation will support any current Numpy
version >= 1.16.6.
6.11.25 Improvements
• Add support for Numpy 1.20. QuTiP should be compiled against a version of Numpy >= 1.16.6 and <
1.20 (note: does _not_ include 1.20 itself), but such an installation is compatible with any modern version
of Numpy. Source installations from pip understand this constraint.
This is predominantly a hot-fix release to add support for Scipy 1.5, due to changes in private sparse matrix functions
that QuTiP also used.
6.11.26 Improvements
• Fix zcsr_proj acting on matrices with unsorted indices. (by Jake Lishman)
• Fix errors in Milstein’s heterodyne. (by Eric Giguère)
• Fix datatype bug in qutip.lattice module. (by Boxi Li)
• Fix issues with eigh on Mac when using OpenBLAS. (by Eric Giguère)
6.11.29 Improvements
6.11.31 Deprecations
6.11.33 Improvements
• MAJOR FEATURE: Added qip.noise, a module with pulse level description of quantum circuits allowing
to model various types of noise and devices (by Boxi Li).
• MAJOR FEATURE: Added qip.lattice, a module for the study of lattice dynamics in 1D (by Saumya
Biswas).
• Migrated testing from Nose to PyTest (by Tarun Raheja).
• Optimized testing for PyTest and removed duplicated test runners (by Jake Lishman).
• Deprecated importing qip functions to the qutip namespace (by Boxi Li).
• Added the possibility to define non-square superoperators relevant for quantum circuits (by Arne Grimsmo
and Josh Combes).
• Implicit tensor product for qeye, qzero and basis (by Jake Lishman).
• QObjEvo no longer requires Cython for string coefficient (by Eric Giguère).
• Added marked tests for faster tests in testing.run() and made faster OpenMP benchmarking in CI (by Eric
Giguère).
• Added entropy and purity for Dicke density matrices, refactored into more general dicke_trace (by Nathan
Shammah).
• Added option for specifying resolution in Bloch.save function (by Tarun Raheja).
• Added information related to the value of hbar in wigner and continuous_variables (by Nicolas Quesada).
• Updated requirements for scipy 1.4 (by Eric Giguère).
• Added previous lead developers to the qutip.about() message (by Nathan Shammah).
• Added improvements to Qobj introducing the inv method and making the partial trace, ptrace, faster, keeping
both sparse and dense methods (by Eric Giguère).
• Allowed general callable objects to define a time-dependent Hamiltonian (by Eric Giguère).
• Added feature so that QobjEvo no longer requires Cython for string coefficients (by Eric Giguère).
• Updated authors list on Github and added my binder link (by Nathan Shammah).
6.11.35 Improvements
• Fixed the pickling but that made solver unable to run in parallel on Windows (Thank lrunze for reporting)
• Removed warning when mesolve fall back on sesolve (by Michael Goerz).
• Fixed dimension check and confusing documentation in random ket (by Yariv Yanay).
• Fixed Qobj isherm not working after using Qobj.permute (Thank llorz1207 for reporting).
• Correlation functions call now properly handle multiple time dependant functions (Thank taw181 for report-
ing).
• Removed mutable default values in mesolve/sesolve (by Michael Goerz).
• Fixed simdiag bug (Thank Croydon-Brixton for reporting).
• Better support of constant QobjEvo (by Boxi Li).
• Fixed potential cyclic import in the control module (by Alexander Pitchford).
6.11.37 Improvements
• MAJOR FEATURE: Added methods and techniques to the stochastic solvers (by Eric Giguère) which
allows to use a much broader set of solvers and much more efficiently.
• MAJOR FEATURE: Optimization of the montecarlo solver (by Eric Giguère). Computation are faster in
many cases. Collapse information available to time dependant information.
• Added the QObjEvo class and methods (by Eric Giguère), which is used behind the scenes by the dynamical
solvers, making the code more efficient and tidier. More built-in function available to string coefficients.
• The coefficients can be made from interpolated array with variable timesteps and can obtain state information
more easily. Time-dependant collapse operator can have multiple terms.
• New wigner_transform and plot_wigner_sphere function. (by Nithin Ramu).
• ptrace is faster and work on bigger systems, from 15 Qbits to 30 Qbits.
• QIP module: added the possibility for user-defined gates, added the possibility to remove or add gates in any
point of an already built circuit, added the molmer_sorensen gate, and fixed some bugs (by Boxi Li).
• Added the quantum Hellinger distance to qutip.metrics (by Wojciech Rzadkowski).
• Implemented possibility of choosing a random seed (by Marek Marekyggdrasil).
• Added a code of conduct to Github.
6.11.39 Improvements
• MAJOR FEATURE: Added the Permutational Invariant Quantum Solver (PIQS) module (by Nathan
Shammah and Shahnawaz Ahmed) which allows the simluation of large TLSs ensembles including col-
lective and local Lindblad dissipation. Applications range from superradiance to spin squeezing.
• MAJOR FEATURE: Added a photon scattering module (by Ben Bartlett) which can be used to study
scattering in arbitrary driven systems coupled to some configuration of output waveguides.
• Cubic_Spline functions as time-dependent arguments for the collapse operators in mesolve are now allowed.
• Added a faster version of bloch_redfield_tensor, using components from the time-dependent version. About
3x+ faster for secular tensors, and 10x+ faster for non-secular tensors.
• Computing Q.overlap() [inner product] is now ~30x faster.
• Added projector method to Qobj class.
• Added fast projector method, Q.proj().
• Computing matrix elements, Q.matrix_element is now ~10x faster.
• Computing expectation values for ket vectors using expect is now ~10x faster.
• Q.tr() is now faster for small Hilbert space dimensions.
• Unitary operator evolution added to sesolve
• Use OPENMP for tidyup if installed.
6.11.41 Improvements
6.11.43 Improvements
Core libraries
• MAJOR FEATURE: QuTiP now works for Python 3.5+ on Windows using Visual Studio 2015.
• MAJOR FEATURE: Cython and other low level code switched to C++ for MS Windows compatibility.
• MAJOR FEATURE: Can now use interpolating cubic splines as time-dependent coefficients.
• MAJOR FEATURE: Sparse matrix - vector multiplication now parallel using OPENMP.
• Automatic tuning of OPENMP threading threshold.
• Partial trace function is now up to 100x+ faster.
• Hermitian verification now up to 100x+ faster.
• Internal Qobj objects now created up to 60x faster.
• Inplace conversion from COO -> CSR sparse formats (e.g. Memory efficiency improvement.)
• Faster reverse Cuthill-Mckee and sparse one and inf norms.
• Cleanup of temp. Cython files now more robust and working under Windows.
6.11.46 Improvements
Core libraries
• MAJOR FEATURE: Fast sparse: New subclass of csr_matrix added that overrides commonly used methods
to avoid certain checks that incurr execution cost. All Qobj.data now fast_csr_matrix
• HEOM performance enhancements
• spmv now faster
• mcsolve codegen further optimised
Control modules
• Time dependent drift (through list of pwc dynamics generators)
• memory optimisation options provided for control.dynamics
Core libraries
• MAJOR FEATURE: Non-Markovian solvers: Hierarchy (Added by Neill Lambert), Memory-Cascade,
and Transfer-Tensor methods.
• MAJOR FEATURE: Default steady state solver now up to 100x faster using the Intel Pardiso library under
the Anaconda and Intel Python distributions.
• The default Wigner function now uses a Clenshaw summation algorithm to evaluate a polynomial series that
is applicable for any number of exciations (previous limitation was ~50 quanta), and is ~3x faster than before.
(Added by Denis Vasilyev)
• Can now define a given eigen spectrum for random Hermitian and density operators.
• The Qobj expm method now uses the equivilent SciPy routine, and performs a much faster exp operation if
the matrix is diagonal.
• One can now build zero operators using the qzero function.
Control modules
• MAJOR FEATURE: CRAB algorithm added This is an alternative to the GRAPE algorithm, which allows
for analytical control functions, which means that experimental constraints can more easily be added into
optimisation. See tutorial notebook for full information.
6.11.49 Improvements
Core libraries
• Two-time correlation functions can now be calculated for fully time-dependent Hamiltonians and collapse
operators. (Added by Kevin Fischer)
• The code for the inverse-power method for the steady state solver has been simplified.
• Bloch-Redfield tensor creation is now up to an order of magnitude faster. (Added by Johannes Feist)
• Q.transform now works properly for arrays directly from sp_eigs (or eig).
• Q.groundstate now checks for degeneracy.
• Added sinm and cosm methods to the Qobj class.
• Added charge and tunneling operators.
• Time-dependent Cython code is now easier to read and debug.
Control modules
• The internal state / quantum operator data type can now be either Qobj or ndarray Previous only ndarray was
possible. This now opens up possibility of using Qobj methods in fidelity calculations The attributes and
functions that return these operators are now preceded by an underscore, to indicate that the data type could
change depending on the configuration options. In most cases these functions were for internal processing
only anyway, and should have been ‘private’. Accessors to the properties that could be useful outside of the
library have been added. These always return Qobj. If the internal operator data type is not Qobj, then there
could be signicant overhead in the conversion, and so this should be avoided during pulse optimisation. If cus-
tom sub-classes are developed that use Qobj properties and methods (e.g. partial trace), then it is very likely
that it will be more efficient to set the internal data type to Qobj. The internal operator data will be chosen
automatically based on the size and sparsity of the dynamics generator. It can be forced by setting dynamics.
oper_dtype = <type> Note this can be done by passing dyn_params={'oper_dtype':<type>} in any
of the pulseoptim functions.
Some other properties and methods were renamed at the same time. A full list is given here.
– All modules - function: set_log_level -> property: log_level
– dynamics functions
∗ _init_lists now _init_evo
∗ get_num_ctrls now property: num_ctrls
∗ get_owd_evo_target now property: onto_evo_target
∗ combine_dyn_gen now _combine_dyn_gen (no longer returns a value)
∗ get_dyn_gen now _get_phased_dyn_gen
∗ get_ctrl_den_gen now _get_phased_ctrl_dyn_gen
∗ ensure_decomp_curr now _ensure_decomp_curr
∗ spectral_decomp now _spectral_decomp
– dynamics properties
∗ evo_init2t now _fwd_evo (fwd_evo as Qobj)
∗ evo_t2end now _onwd_evo (onwd_evo as Qobj)
∗ evo_t2targ now _onto_evo (onto_evo as Qobj)
– fidcomp properties
∗ uses_evo_t2end now uses_onwd_evo
∗ uses_evo_t2targ now uses_onto_evo
∗ set_phase_option function now property phase_option
– propcomp properties
∗ grad_exact (now read only)
– propcomp functions
∗ compute_propagator now _compute_propagator
∗ compute_diff_prop now _compute_diff_prop
∗ compute_prop_grad now _compute_prop_grad
– tslotcomp functions
∗ get_timeslot_for_fidelity_calc now _get_timeslot_for_fidelity_calc
Miscellaneous
• QuTiP Travis CI tests now use the Anaconda distribution.
• The about box and ipynb version_table now display addition system information.
• Updated Cython cleanup to remove depreciation warning in sysconfig.
• Updated ipynb_parallel to look for ipyparallel module in V4 of the notebooks.
• Cython build files for time-dependent string format now removed automatically.
• Fixed incorrect solution time from inverse-power method steady state solver.
• mcsolve now supports Options(store_states=True)
• Fixed bug in hadamard gate function.
• Fixed compatibility issues with NumPy 1.9.0.
• Progressbar in mcsolve can now be suppressed.
• Fixed bug in gate_expand_3toN.
• Fixed bug for time-dependent problem (list string format) with multiple terms in coefficient to an operator.
• Fix bug in create(), which returned a Qobj with CSC data instead of CSR.
• Fix several bugs in mcsolve: Incorrect storing of collapse times and collapse operator records. Incorrect
averaging of expectation values for different trajectories when using only 1 CPU.
• Fix bug in parsing of time-dependent Hamiltonian/collapse operator arguments that occurred when the args
argument is not a dictionary.
• Fix bug in internal _version2int function that cause a failure when parsingthe version number of the Cython
package.
•
• New module qutip.stochastic with stochastic master equation and stochastic Schrödinger equation solvers.
• Expanded steady state solvers. The function steady has been deprecated in favor of steadystate. The
steadystate solver no longer use umfpack by default. New pre-processing methods for reordering and bal-
ancing the linear equation system used in direct solution of the steady state.
• New module qutip.qip with utilities for quantum information processing, including pre-defined quantum
gates along with functions for expanding arbitrary 1, 2, and 3 qubit gates to N qubit registers, circuit repre-
sentations, library of quantum algorithms, and basic physical models for some common QIP architectures.
• New module qutip.distributions with unified API for working with distribution functions.
• New format for defining time-dependent Hamiltonians and collapse operators, using a pre-calculated numpy
array that specifies the values of the Qobj-coefficients for each time step.
• New functions for working with different superoperator representations, including Kraus and Chi represen-
tation.
• New functions for visualizing quantum states using Qubism and Schimdt plots: plot_qubism and
plot_schmidt.
• Dynamics solver now support taking argument e_ops (expectation value operators) in dictionary form.
• Public plotting functions from the qutip.visualization module are now prefixed with plot_ (e.g.,
plot_fock_distribution). The plot_wigner and plot_wigner_fock_distribution now supports
3D views in addition to contour views.
• New API and new functions for working with spin operators and states, including for example spin_Jx,
spin_Jy, spin_Jz and spin_state, spin_coherent.
• The expect function now supports a list of operators, in addition to the previously supported list of states.
• Simplified creation of qubit states using ket function.
• The module qutip.cyQ has been renamed to qutip.cy and the sparse matrix-vector functions spmv and
spmv1d has been combined into one function spmv. New functions for operating directly on the underlaying
sparse CSR data have been added (e.g., spmv_csr). Performance improvements. New and improved Cython
functions for calculating expectation values for state vectors, density matrices in matrix and vector form.
• The concurrence function now supports both pure and mixed states. Added function for calculating the
entangling power of a two-qubit gate.
• Added function for generating (generalized) Lindblad dissipator superoperators.
• New functions for generating Bell states, and singlet and triplet states.
• QuTiP no longer contains the demos GUI. The examples are now available on the QuTiP web site. The
qutip.gui module has been renamed to qutip.ui and does no longer contain graphical UI elements. New
text-based and HTML-based progressbar classes.
• Support for harmonic oscillator operators/states in a Fock state basis that does not start from zero (e.g., in
the range [M,N+1]). Support for eliminating and extracting states from Qobj instances (e.g., removing one
state from a two-qubit system to obtain a three-level system).
• Support for time-dependent Hamiltonian and Liouvillian callback functions that depend on the instantaneous
state, which for example can be used for solving master equations with mean field terms.
6.11.55 Improvements
• Restructured and optimized implementation of Qobj, which now has significantly lower memory footprint
due to avoiding excessive copying of internal matrix data.
• The classes OdeData, Odeoptions, Odeconfig are now called Result, Options, and Config, respec-
tively, and are available in the module qutip.solver.
• The squeez function has been renamed to squeeze.
• Better support for sparse matrices when calculating propagators using the propagator function.
• Improved Bloch sphere.
• Restructured and improved the module qutip.sparse, which now only operates directly on sparse matrices
(not on Qobj instances).
• Improved and simplified implement of the tensor function.
• Improved performance, major code cleanup (including namespace changes), and numerous bug fixes.
• Benchmark scripts improved and restructured.
• QuTiP is now using continuous integration tests (TravisCI).
The second version of QuTiP has seen many improvements in the performance of the original code base, as well as
the addition of several new routines supporting a wide range of functionality. Some of the highlights of this release
include:
• QuTiP now includes solvers for both Floquet and Bloch-Redfield master equations.
• The Lindblad master equation and Monte Carlo solvers allow for time-dependent collapse operators.
• It is possible to automatically compile time-dependent problems into c-code using Cython (if installed).
• Python functions can be used to create arbitrary time-dependent Hamiltonians and collapse operators.
• Solvers now return Odedata objects containing all simulation results and parameters, simplifying the saving
of simulation results.
• mesolve and mcsolve can reuse Hamiltonian data when only the initial state, or time-dependent arguments,
need to be changed.
• QuTiP includes functions for creating random quantum states and operators.
• The generation and manipulation of quantum objects is now more efficient.
• Quantum objects have basis transformation and matrix element calculations as built-in methods.
• The quantum object eigensolver can use sparse solvers.
• The partial-trace (ptrace) function is up to 20x faster.
• The Bloch sphere can now be used with the Matplotlib animation function, and embedded as a subplot in a
figure.
• QuTiP has built-in functions for saving quantum objects and data arrays.
• The steady-state solver has been further optimized for sparse matrices, and can handle much larger system
Hamiltonians.
• The steady-state solver can use the iterative bi-conjugate gradient method instead of a direct solver.
• There are three new entropy functions for concurrence, mutual information, and conditional entropy.
• Correlation functions have been combined under a single function.
• The operator norm can now be set to trace, Frobius, one, or max norm.
• Global QuTiP settings can now be modified.
• Fixed issue where Monte Carlo states were not output properly.
• Initial release.
Developers
435
QuTiP: Quantum Toolbox in Python, Release 5.0.4
• Alex Pitchford
• Nathan Shammah
• Shahnawaz Ahmed
• Neill Lambert
• Eric Giguère
• Boxi Li
• Simon Cross
• Asier Galicia
7.3 Contributors
Note: Anyone is welcome to contribute to QuTiP. If you are interested in helping, please let us know!
• Abhisek Upadhyaya
• Adriaan
• Alexander Pitchford
• Alexios-xi
• Amit
• Anubhav Vardhan
• Arie van Deursen
• Arne Grimsmo
• Arne Hamann
• Asier Galicia Martinez
• Ben Bartlett
• Ben Criger
• Ben Jones
• Bo Yang
• Boxi Li
• Canoming
• Christoph Gohlke
• Christopher Granade
• Craig Gidney
• Denis Vasilyev
• Dominic Meiser
• Drew Parsons
• Eric Giguère
• Eric Hontz
• Felipe Bivort Haiek
• Florestan Ziem
• Gilbert Shih
• Harry Adams
• Ivan Carvalho
• Jake Lishman
• Jevon Longdell
• Johannes Feist
• Jonas Hoersch
• Jonas Neergaard-Nielsen
• Jonathan A. Gross
• Julian Iacoponi
• Kevin Fischer
• Laurence Stant
• Louis Tessler
• Lucas Verney
• Marco David
• Marek Narozniak
• Markus Baden
• Martín Sande
• Mateo Laguna
• Matthew O’Brien
• Michael Goerz
• Michael V. DePalatis
• Moritz Oberhauser
• Nathan Shammah
• Neill Lambert
• Nicolas Quesada
• Nikolas Tezak
• Nithin Ramu
• Paul Nation
• Peter Kirton
• Philipp Schindler
• Piotr Migdal
• Rajiv-B
• Ray Ganardi
• Reinier Heeres
• Richard Brierley
• Robert Johansson
• Sam Griffiths
• Samesh Lakhotia
• Sebastian Krämer
• Shahnawaz Ahmed
• Sidhant Saraogi
• Simon Cross
• Simon Humpohl
• Simon Whalen
• Stefan Krastanov
• Tarun Raheja
• Thomas Walker
• Viacheslav Ostroukh
• Vlad Negnevitsky
• Wojciech Rzadkowski
• Xiaodong Qi
• Xiaoliang Wu
• Yariv Yanay
• YouWei Zhao
• alex
• eliegenois
• essence-of-waqf
• fhenneke
• gecrooks
• jakobjakobson13
• maij
• sbisw002
• yuri@FreeBSD
• Élie Gouzien
Development Documentation
This chapter covers the development of QuTiP and its subpackages, including a roadmap for upcoming releases
and ideas for future improvements.
QuTiP is developed through wide collaboration using the git version-control system, with the main repositories
hosted in the qutip organisation on GitHub. You will need to be familiar with git as a tool, and the GitHub Flow
workflow for branching and making pull requests. The exact details of environment set-up, build process and
testing vary by repository and are discussed below, however in overview, the steps to contribute are:
1. Consider creating an issue on the GitHub page of the relevant repository, describing the change you think
should be made and why, so we can discuss details with you and make sure it is appropriate.
2. (If this is your first contribution.) Make a fork of the relevant repository on GitHub and clone it to your
local computer. Also add our copy as a remote (git remote add qutip https://github.com/qutip/
<repo>)
3. Begin on the master branch (git checkout master), and pull in changes from the main QuTiP repository
to make sure you have an up-to-date copy (git pull qutip master).
4. Switch to a new git branch (git checkout -b <branch-name>).
5. Make the changes you want to make, then create some commits with short, descriptive names (git add
<files> then git commit).
6. Follow the build process for this repository to build the final result so you can check your changes work
sensibly.
7. Run the tests for the repository (if it has them).
8. Push the changes to your fork (git push -u origin <branch-name>). You won’t be able to push to the
main QuTiP repositories directly.
9. Go to the GitHub website for the repository you are contributing to, click on the “Pull Requests” tab, click
the “New Pull Request” button, and follow the instructions there.
Once the pull request is created, some members of the QuTiP admin team will review the code to make sure it is
suitable for inclusion in the library, to check the programming, and to ensure everything meets our standards. For
some repositories, several automated tests will run whenever you create or modify a pull request; in general these
will be the same tests you can run locally, and all tests are required to pass online before your changes are merged.
There may be some feedback and possibly some requested changes. You can add more commits to address these,
and push them to the relevant branch of your fork to update the pull request.
439
QuTiP: Quantum Toolbox in Python, Release 5.0.4
The rest of this document covers programming standards, and particular considerations for some of the more
complicated repositories.
Building
Building the core library from source is typically a bit more difficult than simply installing the package for regular
use. You will most likely want to do this in a clean Python environment so that you do not compromise a working
installation of a release version, for example by starting from
Complete instructions for the build are elsewhere in this guide, however beware that you will need to follow the
installation from source using setuptools section, not the general installation. You will need all the build and tests
“optional” requirements for the package. The build requirements can be found in the pyproject.toml file, and
the testing requirements are in the tests key of the options.extras_require section of setup.cfg. You will
also need the requirements for any optional features you want to test as well.
Refer to the main instructions for the most up-to-date version, however as of version 4.6 the requirements can be
installed into a conda environment with
conda install setuptools wheel numpy scipy cython packaging pytest pytest-
˓→rerunfailures
Note: If you prefer, you can also use pip to install all the dependencies. We typically recommend conda when do-
ing main-library development because it is easier to switch low-level packages around like BLAS implementations,
but if this doesn’t mean anything to you, feel free to use pip.
You will need to make sure you have a functioning C++ compiler to build QuTiP. If you are on Linux or Mac,
this is likely already done for you, however if you are on Windows, refer to the Windows installation section of the
installation guide.
The command to build QuTiP in editable mode is
from the repository directory. If you now load up a Python interpreter, you should be able to import qutip from
anywhere as long as the correct Python environment is active. Any changes you make to the Python files in the git
repository should be immediately present if you restart your Python interpreter and re-import qutip.
On the first run, the setup command will compile many C++ extension modules built from Cython sources (files
ending .pxd and .pyx). Generally the low-level linear algebra routines that QuTiP uses are written in these files,
not in pure Python. Unlike Python files, changes you make to Cython files will not appear until you run python
setup.py develop again; you will only need to re-run this if you are changing Cython files. Cython will detect
and compile only the files that have been changed, so this command will be faster on subsequent runs.
Note: When undertaking Cython development, the reason we use python setup.py develop instead of pip
install -e . is because Cython’s changed-file detection does not reliably work in the latter. pip tends to build in
temporary virtual environments, which often makes Cython think its core library files have been updated, triggering
a complete, slow rebuild of everything.
Note: QuTiP follows NEP29 when selecting the supported version of its dependencies. To see which versions
are planned to be supported in the next release, please refer to the QuTiP major release roadmap. These coincide
with the versions employed for testing in continuous integration.
In the event of a feature requiring a version upgrade of python or a dependency, it will be considered appropriately
in the pull request. In any case, python and dependency upgrades will only happen in mayor or minor versions of
QuTiP, not in a patch.
Code Style
The biggest concern you should always have is to make it easy for your code to be read and understood by the
person who comes next.
All new contributions must follow PEP 8 style; all pull requests will be passed through a linter that will complain
if you violate it. You should use the pycodestyle package locally (available on pip) to test you satisfy the
requirements before you push your commits, since this is rather faster than pushing 10 different commits trying to
fix minor niggles. Keep in mind that there is quite a lot of freedom in this style, especially when it comes to line
breaks. If a line is too long, consider the best way to split it up with the aim of making the code readable, not just
the first thing that doesn’t generate a warning.
Try to stay consistent with the style of the surrounding code. This includes using the same variable names, espe-
cially if they are function arguments, even if these “break” PEP 8 guidelines. Do not change existing parameter,
attribute or method names to “match” PEP 8; these are breaking user-facing changes, and cannot be made except
in a new major release of QuTiP.
Other than this, general “good-practice” Python standards apply: try not to duplicate code; try to keep functions
short, descriptively-named and side-effect free; provide a docstring for every new function; and so on.
Documenting
When you make changes in the core library, you should update the relevant documentation if needed. If you are
making a bug fix, or other relatively minor changes, you will probably only need to make sure that the docstrings
of the modified functions and classes are up-to-date; changes here will propagate through to the documentation
the next time it is built. Be sure to follow the Numpy documentation standards (numpydoc) when writing doc-
strings. All docstrings will be parsed as reStructuredText, and will form the API documentation section of the
documentation.
Testing
We use pytest as our test runner. The base way to run every test is
pytest /path/to/repo/qutip/tests
This will take around 10 to 30 minutes, depending on your computer and how many of the optional requirements
you have installed. It is normal for some tests to be marked as “skip” or “xfail” in yellow; these are not problems.
True failures will appear in red and be called “fail” or “error”.
While prototyping and making changes, you might want to use some of the filtering features of pytest. Instead
of passing the whole tests directory to the pytest command, you can also pass a list of files. You can also use
the -k selector to only run tests whose names include a particular pattern, for example
Changelog Generation
We use towncrier for tracking changes and generating a changelog. When making a pull request, we require
that you add a towncrier entry along with the code changes. You should create a file named <PR number>.
<change type> in the doc/changes directory, where the PR number should be substituted for <PR number>,
and <change type> is either feature, bugfix, doc, removal, misc, or deprecation, depending on the type
of change included in the PR.
You can also create this file by installing towncrier and running
towncrier create <PR number>.<change type>
Running this will create a file in the doc/changes directory with a filename corresponding to the argument you
passed to towncrier create. In this file, you should add a short description of the changes that the PR introduces.
The core library is in the qutip/qutip repository on GitHub, inside the doc directory.
Building
The documentation is built using sphinx, matplotlib and numpydoc, with several additional extensions includ-
ing sphinx-gallery and sphinx-rtd-theme. The most up-to-date instructions and dependencies will be in the
README.md file of the documentation directory. You can see the rendered version of this file simply by going to
the documentation GitHub page and scrolling down.
Building the documentation can be a little finnicky on occasion. You likely will want to keep a separate Python
environment to build the documentation in, because some of the dependencies can have tight requirements that may
conflict with your favourite tools for Python development. We recommend creating an empty conda environment
containing only Python with
and install all further dependencies with pip. There is a requirements.txt file in the repository root that fixes
all package versions exactly into a known-good configuration for a completely empty environment, using
This known-good configuration was intended for Python 3.8, though in principle it is possible that other Python
versions will work.
Note: We recommend you use pip to install dependencies for the documentation rather than conda because
several necessary packages can be slower to update their conda recipes, so suitable versions may not be available.
The documentation build includes running many components of the main QuTiP library to generate figures and to
test the output, and to generate all the API documentation. You therefore need to have a version of QuTiP available
in the same Python environment. If you are only interested in updating the users’ guide, you can use a release
version of QuTiP, for example by running pip install qutip. If you are also modifying the main library, you
need to make your development version accessible in this environment. See the above section on building QuTiP
for more details, though the requirements.txt file will have already installed all the build requirements, so you
should be able to simply run
a full pdflatex installation), and clean to remove all built files. The most important command you will want to
run is
make html
You should re-run this any time you make changes, and it should only update files that have been changed.
Important: The documentation build includes running almost all the optional features of QuTiP. If you get failure
messages in red, make sure you have installed all of the optional dependencies for the main library.
The HTML files will be placed in the _build/html directory. You can open the file _build/html/index.html
in your web browser to check the output.
Code Style
All user guide pages and docstrings are parsed by Sphinx using reStructuredText. There is a general Sphinx usage
guide, which has a lot of information that can sometimes be a little tricky to follow. It may be easier just to look at
other .rst files already in the documentation to copy the different styles.
Note: reStructuredText is a very different language to the Markdown that you might be familiar with. It’s always
worth checking your work in a web browser to make sure it’s appeared the way you intended.
Testing
There are unfortunately no automated tests for the documentation. You should ensure that no errors appeared in
red when you ran make html. Try not to introduce any new warnings during the build process. The main test is to
open the HTML pages you have built (open _build/html/index.html in your web browser), and click through
to the relevant pages to make sure everything has rendered the way you expected it to.
8.2.1 Preamble
This document outlines plan and ideas for the current and future development of QuTiP. The document is main-
tained by the QuTiP Admim team. Contributuions from the QuTiP Community are very welcome.
In particular this document outlines plans for the next major release of qutip, which will be version 5. And also
plans and dreams beyond the next major version.
There is lots of development going on in QuTiP that is not recorded in here. This a just an attempt at coordinated
stragetgy and ideas for the future.
What is QuTiP?
The name QuTiP refers to a few things. Most famously, qutip is a Python library for simulating quantum dynamics.
To support this, the library also contains various software tools (functions and classes) that have more generic ap-
plications, such as linear algebra components and visualisation utilities, and also tools that are specifically quantum
related, but have applications beyond just solving dynamics (for instance partial trace computation).
QuTiP is also an organisation, in the Github sense, and in the sense of a group of people working collaboratively
towards common objectives, and also a web presence qutip.org. The QuTiP Community includes all the people
who have supported the project since in conception in 2010, including manager, funders, developers, maintainers
and users.
These related, and overlapping, uses of the QuTiP name are of little consequence until one starts to consider how to
organise all the software packages that are somehow related to QuTiP, and specifically those that are maintained by
the QuTiP Admim Team. Herin QuTiP will refer to the project / organisation and qutip to the library for simulating
quantum dyanmics.
Should we be starting again from scratch, then we would probably chose another name for the main qutip library,
such as qutip-quantdyn. However, qutip is famous, and the name will stay.
With a name as general as Quantum Toolkit in Python, the scope for new code modules to be added to qutip is very
wide. The library was becoming increasingly difficult to maintain, and in c. 2020 the QuTiP Admim Team decided
to limit the scope of the ‘main’ (for want of a better name) qutip package. This scope is restricted to components for
the simulation (solving) of the dynamics of quantum systems. The scope includes utilities to support this, including
analysis and visualisation of output.
At the same time, again with the intention of easing maintence, a decision to limit dependences was agreed upon.
Main qutip runtime code components should depend only upon Numpy and Scipy. Installation (from source)
requires Cython, and some optional components also require Cython at runtime. Unit testing requires Pytest.
Visualisation (optional) components require Matplotlib.
Due to the all encompassing nature of the plan to abstract the linear algebra data layer, this enhancement (developed
as part of a GSoC project) was allowed the freedom (potential for non-backward compatibility) of requiring a
major release. The timing of such allows for a restructuring of the qutip compoments, such that some that could be
deemed out of scope could be packaged in a different way – that is, not installed as part of the main qutip package.
Hence the proposal for different types of package described next. With reference to the discussion above on the
name QuTiP/qutip, the planned restructuring suffers from confusing naming, which seems unavoidable without
remaining either the organisation or the main package (neither of which are desirable).
QuTiP family packages
The main qutip package already has sub-packages, which are maintained in the main qutip repo. Any pack-
ages maitained by the QuTiP organisation will be called QuTiP ‘family’ packages. Sub-packages within
qutip main will be called ‘integrated’ sub-packages. Some packages will be maintained in their own repos
and installed separately within the main qutip folder structure to provide backwards compatibility, these are
(will be) called qutip optional sub-packages. Others will be installed in their own folders, but (most likely)
have qutip as a dependency – these will just be called ‘family’ packages.
QuTiP affilliated packages
Other packages have been developed by others outside of the QuTiP organisation that work with, and are
complementary to, qutip. The plan is to give some recognition to those that we deem worthy of such [this
needs clarification]. These packages will not be maintained by the QuTiP Team.
Family packages
qutip main
Qtrl
QIP
qutip-symbolic
Affilliated packages
qucontrol-krotov
tag
solve-dl
status
development ongoing
admin lead
Eric
main dev
Eric
The new data layer gives opportunity for significantly improving performance of the qutip solvers. Eric has been
revamping the solvers by deploying QobjEvo (the time-dependent quantum object) that he developed. QobjEvo
will exploit the data layer, and the solvers in turn exploit QobjEvo.
Qtrl migration
tag
qtrl-mig
status
conceptualised
admin lead
Alex
main dev
TBA
The components currently packaged as an integrated subpackage of qutip main will be moved to separate package
called Qtrl. This is the original codename of the package before it was integrated into qutip. Also changes to exploit
the new data layer will be implemented.
tag
ctrl-fw
status
conceptualised
admin lead
Alex
main dev
TBA
Create new package qutip-ctrlfw “QuTiP Control Framework”. The aim is provide a common framework that can
be adopted by control optimisation packages, such that different packages (algorithms) can be applied to the same
problem.
Classes for defining a controlled system:
• named control parameters. Scalar and n-dim. Continuous and discrete variables
• mapping of control parameters to dynamics generator args
• masking for control parameters to be optimised
Classes for time-dependent variable parameterisation
• piecewise constant
• piecewise linear
• Fourier basis
• more
Classes for defining an optimisation problem:
• single and multiple objectives
QuTiP optimisation
tag
qutip-optim
status
conceptualised
admin lead
Alex
main dev
TBA
A wrapper for multi-variable optimisation functions. For instance those in scipy.optimize (Nelder-Mead, BFGS),
but also others, such as Bayesian optimisation and other machine learning based approaches. Initially just providing
a common interface for quantum control optimisation, but applicable more generally.
Sympsi migration
tag
sympsi-mig
status
conceptualised
admin lead
Alex
main dev
TBA
Create a new family package qutip-symbolic from ajgpitch fork of Sympy. Must gain permission from Robert
Johansson and Eunjong Kim. Extended Sympy simplify to respect non-commuting operators. Produce user doc-
umentation.
tag
status-msg
status
conceptualised
admin lead
Alex
main dev
TBA
QuTiP has various ways of recording and reporting status and progress.
• ProgressBar used by some solvers
qutip Interactive
status
conceptualised
tag
qutip-gui
admin lead
Alex
main dev
TBA
QuTiP is pretty simple to use at an entry level for anyone with basic Python skills. However, some Python skills
are necessary. A graphical user interface (GUI) for some parts of qutip could help make qutip more accessible.
This could be particularly helpful in education, for teachers and learners.
This would make an good GSoC project. It is independent and the scope is flexible.
The scope for this is broad and flexible. Ideas including, but not limited to:
Matplotlib has some interactive features (sliders, radio buttons, cmd buttons) that can be used to control parameters.
They are a bit clunky to use, but they are there. Could maybe avoid these and develop our own GUI. An interactive
Bloch sphere could have sliders for qubit state angles. Buttons to add states, toggle state evolution path.
Interactive solvers
Options to configure dynamics generators (Lindbladian / Hamiltonian args etc) and expectation operators. Then
run solver and view state evolution.
Animated circuits
QIP circuits could be animated. Status lights showing evolution of states during the processing. Animated Bloch
spheres for qubits.
tag
dl-abs
status
completed
admin lead
Eric
main dev
Jake Lishman
Development completed as a GSoC project. Fully implemented in the dev.major branch. Currently being used by
some research groups.
Abstraction of the linear algebra data from code qutip components, allowing for alternatives, such as sparse, dense
etc. Difficult to summarize. Almost every file in qutip affected in some way. A major milestone for qutip. Signifi-
cant performance improvements throughout qutip.
Some developments tasks remain, including providing full control over how the data-layer dispatchers choose the
most appropriate output type.
tag
qmain-reorg
status
completed
admin lead
Eric
main dev
Jake Lishman
Reorganise qutip main components to the structure described above.
tag
qmain-docs
status
completed
admin lead
Jake Lishman
main dev
Jake Lishman
The qutip user documentation build files are to be moved to the qutip/qutip repo. This is more typical for an OSS
package.
As part of the move, the plan is to reconstruct the Sphinx structure from scratch. Historically, there have been many
issues with building the docs. Sphinx has come a long way since qutip docs first developed. The main source (rst)
files will remain [pretty much] as they are, although there is a lot of scope to improve them.
The qutip-doc repo will afterwards just be used for documents, such as this one, pertaining to the QuTiP project.
QIP migration
tag
qip-mig
status
completed
admin lead
Boxi
main dev
Sidhant Saraogi
A separate package for qutip-qip was created during Sidhant’s GSoC project. There is some fine tuning required,
especially after qutip.control is migrated.
HEOM revamp
tag
heom-revamp
status
completed
admin lead
Neill
main dev
Simon Cross, Tarun Raheja
An overhaul of the HEOM solver, to incorporate the improvements pioneered in BoFiN.
QuTiP v.5
Ideas for significant new features are listed here. For the general roadmap, see QuTiP Development Roadmap.
Contents
QuTiP is pretty simple to use at an entry level for anyone with basic Python skills. However, some Python skills
are necessary. A graphical user interface (GUI) for some parts of qutip could help make qutip more accessible.
This could be particularly helpful in education, for teachers and learners.
Ideally, interactive components could be embedded in web pages. Including, but not limited to, Jupyter notebooks.
The scope for this is broad and flexible. Ideas including, but not limited to:
QuTiP has a Bloch sphere virtualisation for qubit states. This could be made interactive through sliders, radio
buttons, cmd buttons etc. An interactive Bloch sphere could have sliders for qubit state angles. Buttons to add
states, toggle state evolution path. Potential for recording animations. Matplotlib has some interactive features
(sliders, radio buttons, cmd buttons) that can be used to control parameters. that could potentially be used.
Interactive solvers
Options to configure dynamics generators (Lindbladian / Hamiltonian args etc) and expectation operators. Then
run solver and view state evolution.
Animated circuits
QIP circuits could be animated. Status lights showing evolution of states during the processing. Animated Bloch
spheres for qubits.
Expected outcomes
Skills
• Git, Python and familiarity with the Python scientific computing stack
• elementary understanding of quantum dynamics
Difficulty
• Variable
Mentors
Contents
• Expected outcomes
• Skills
• Difficulty
• Mentors
• References
The aim of this proposal is to enhance QuTiP quantum-circuit compilation features with regard to quantum infor-
mation processing. While QuTiP core modules deal with dynamics simulation, there is also a module for quantum
circuits simulation. The two subsequent Google Summer of Code projects, in 2019 and 2020, enhanced them in
capabilities and features, allowing the simulation both at the level of gates and at the level of time evolution. To
connect them, a compiler is implemented to compile quantum gates into the Hamiltonian model. We would like to
further enhance this feature in QuTiP and the connection with other libraries.
Expected outcomes
• APIs to import and export pulses to other libraries. Quantum compiler is a current research topic in quantum
engineering. Although QuTiP has a simple compiler, many may want to try their own compiler which is more
compatible with their quantum device. Allowing importation and exportation of control pulses will make this
much easier. This will include a study of existing libraries, such as qiskit.pulse and OpenPulse1 , comparing
them with qutip.qip.pulse module and building a more general and comprehensive description of the pulse.
• More examples of quantum system in the qutip.qip.device module. The circuit simulation and compilation
depend strongly on the physical system. At the moment, we have two models: spin chain and cavity QED.
We would like to include some other commonly used planform such as Superconducting system2 , Ion trap
system3 or silicon system. Each model will need a new set of control Hamiltonian and a compiler that finds
the control pulse of a quantum gate. More involved noise models can also be added based on the physical
system. This part is going to involve some physics and study of commonly used hardware platforms. The
related code can be found in qutip.qip.device and qutip.qip.compiler.
Skills
• Git, Python and familiarity with the Python scientific computing stack
• quantum information processing and quantum computing (quantum circuit formalism)
Difficulty
• Medium
Mentors
arXiv:1809.03452, 2018.
2 Häffner H, Roos C F, Blatt R, Quantum computing with trapped ions, Physics reports, 2008, 469(4): 155-203.
3 Krantz P, Kjaergaard M, Yan F, et al. A quantum engineer’s guide to superconducting qubits, Applied Physics Reviews, 2019, 6(2):
021318.
References
Contents
• Expected outcomes
• Skills
• Difficulty
• Mentors
• References
From the QuTiP 4.5 release, the qutip.qip module now contains the noisy quantum circuit simulator (which was
a GSoC project) providing enhanced features for a pulse-level description of quantum circuits and noise models.
A new class Processor and several subclasses are added to represent different platforms for quantum computing.
They can transfer a quantum circuit into the corresponding control sequence and simulate the dynamics with QuTiP
solvers. Different noise models can be added to qutip.qip.noise to simulate noise in a quantum device.
This module is still young and many features can be improved, including new device models, new noise models and
integration with the existing general framework for quantum circuits (qutip.qip.circuit). There are also possible
applications such as error mitigation techniques (1 ,2 ,3 ).
The tutorial notebooks can be found in the Quantum information processing section of https://qutip.org/
qutip-tutorials/index-v5.html. A recent presentation on the FOSDEM conference may help you get an overview
(https://fosdem.org/2020/schedule/event/quantum_qutip/). See also the Github Project page for a collection of
related issues and ongoing Pull Requests.
Expected outcomes
• Make an overview of existing libraries and features in error mitigation, similarly to a literature survey for
a research article, but for a code project (starting from Refs.4 ,5 ). This is done in order to best integrate the
features in QuTiP with existing libraries and avoid reinventing the wheel.
• Features to perform error mitigation techniques in QuTiP, such as zero-noise extrapolation by pulse stretch-
ing.
• Tutorials implementing basic quantum error mitigation protocols
• Possible integration with Mitiq6
1 Kristan Temme, Sergey Bravyi, Jay M. Gambetta, Error mitigation for short-depth quantum circuits, Phys. Rev. Lett. 119, 180509
(2017)
2 Abhinav Kandala, Kristan Temme, Antonio D. Corcoles, Antonio Mezzacapo, Jerry M. Chow, Jay M. Gambetta, Extending the compu-
tational reach of a noisy superconducting quantum processor, Nature 567, 491 (2019)
3
S. Endo, S.C. Benjamin, Y. Li, Practical quantum error mitigation for near-future applications, Physical Review X 8, 031027 (2018)
4 Boxi Li’s blog on the GSoC 2019 project on pulse-level control, https://gsoc2019-boxili.blogspot.com/
5 Video of a recent talk on the GSoC 2019 project, https://fosdem.org/2020/schedule/event/quantum_qutip/
6 Mitiq
Skills
Difficulty
• Medium
Mentors
References
Contents
• Expected outcomes
• Skills
• Difficulty
• Mentors
• References
The Hierarchical Equations of Motion (HEOM) method is a non-perturbative approach to simulate the evolution
of the density matrix of dissipative quantum systems. The underlying equations are a system of coupled ODEs
which can be run on a GPU. This will allow the study of larger systems as discussed in1 . The goal of this project
would be to extend QuTiP’s HEOM method2 and implement it on a GPU.
Since the method is related to simulating large, coupled ODEs, it can also be quite general and extended to other
solvers.
1 https://pubs.acs.org/doi/abs/10.1021/ct200126d?src=recsys&journalCode=jctcce
2 https://arxiv.org/abs/2010.10806
Expected outcomes
Skills
• Git, python and familiarity with the Python scientific computing stack
• CUDA and OpenCL knowledge
Difficulty
• Hard
Mentors
References
Many possible extensions and improvements to QuTiP have been documented as part of Google Summer of Code:
• GSoC 2021
• GSoC 2022
Contents
QuTiP’s data layer provides the mathematical operations needed to work with quantum states and operators, i.e.
Qobj, inside QuTiP. As part of Google Summer of Code 2020, the data layer was rewritten to allow new backends to
be added more easily and for different backends to interoperate with each other. Backends using in-memory spares
and dense matrices already exist, and we would like to add a backend that implements the necessary operations
using TensorFlow1 .
TensorFlow supports distributing matrix operations across multiple GPUs and multiple machines, and abstracts
away some of the complexities of doing so efficiently. We hope that by using TensorFlow we might enable QuTiP
to scale to bigger quantum systems (e.g. more qubits) and decrease the time taken to simulate them.
There is particular interest in trying the new backend with the BoFiN HEOM (Hierarchical Equations of Motion)
solver2 .
Challenges
TensorFlow is a very different kind of computational framework to the existing dense and sparse matrix backends.
It uses flow graphs to describe operations, and to work efficiently. Ideally large graphs of operations need to be
executed together in order to efficiently compute results.
The QuTiP data layer might need to be adjusted to accommodate these differences, and it is possible that this will
prove challenging or even that we will not find a reasonable way to achieve the desired performance.
Expected outcomes
Skills
• Git, Python and familiarity with the Python scientific computing stack
• Familiarity with TensorFlow (beneficial, but not required)
• Familiarity with Cython (beneficial, but not required)
3 https://github.com/qutip/qutip-tensorflow/
1 https://www.tensorflow.org/
2 https://github.com/tehruhn/bofin
Difficulty
• Medium
Mentors
References
The user guide provides an overview of QuTiP’s functionality. The guide is composed of individual reStructured-
Text (.rst) files which each get rendered as a webpage. Each page typically tackles one area of functionality. To
learn more about how to write .rst files, it is useful to follow the sphinx guide.
The documentation build also utilizes a number of Sphinx Extensions including but not limited to doctest, autodoc,
sphinx gallery and plot. Additional extensions can be configured in the conf.py file.
8.4.1 Directives
There are two Sphinx directives that can be used to write code examples in the user guide:
• Doctest
• Plot
For a more comprehensive account of the usage of each directive, please refer to their individual pages. Here we
outline some general guidelines on how to these directives while making a user guide.
Doctest
The doctest directive enables tests on interactive code examples. The simplest way to do this is by specifying a
prompt along with its respective output:
.. doctest::
>>> a = 2
>>> a
2
>>> a = 2
>>> a
2
While specifying code examples under the .. doctest:: directive, either all statements must be specified by the
>>> prompt or without it. For every prompt, any potential corresponding output must be specified immediately after
it. This directive is ideally used when there are a number of examples that need to be checked in quick succession.
A different way to specify code examples (and test them) is using the associated .. testcode:: directive which
is effectively a code block:
.. testcode::
a = 2
print(a)
followed by its results. The result can be specified with the .. testoutput:: block:
.. testoutput::
The advantage of the testcode directive is that it is a lot simpler to specify and amenable to copying the code
to clipboard. Usually, tests are more easily specified with this directive as the input and output are specified in
different blocks. The rendering is neater too.
Note: The doctest and testcode directives should not be assumed to have the same namespace.
Output:
a = 2
print(a)
.. doctest:: [group_name]
>>> a = 2
can be followed by some explanation followed by another code block sharing the same namespace
.. doctest:: [group_name]
>>> print(a)
2
• To only print the code blocks (or the output), use the option +SKIP to specify the block without the code
being tested when running make doctest.
• To check the result of a Qobj output, it is useful to make sure that spacing irregularities between the expected
and actual output are ignored. For that, we can use the option +NORMALIZE_WHITESPACE.
Plot
Since the doctest directive cannot render matplotlib figures, we use Matplotlib’s Plot directive when rendering to
LaTeX or HTML.
The plot directive can also be used in the doctest format. In this case, when running doctests (which is enabled by
specifying all statements with the >>> prompts), tests also include those specified under the plot directive.
Example:
.. plot::
.. plot::
:context:
Note the use of the NORMALIZE_WHITESPACE option to ensure that the multiline output matches.
Render:
1.00
0.75
0.50
0.25
0.00
0.25
0.50
0.75
1.00
0 1 2 3 4 5 6
8.5.1 Preamble
This document covers the process for managing updates to the current minor release and making new releases.
Within this document, the git remote upstream refers to the main QuTiP organsiation repository, and origin
refers to your personal fork.
In short, the steps you need to take are:
1. Prepare the release branch (see git).
2. Run the “Build wheels, optionally deploy to PyPI” GitHub action to build binary and source packages and
upload them to PyPI (see deploy).
3. Create a GitHub release and uploaded the built files to it (see github).
4. Update qutip.org with the new links and documentation (web).
5. Update the conda feedstock, deploying the package to conda (cforge).
In this step you will prepare a git branch on the main QuTiP repository that has the state of the code that is going
to be released. This procedure is quite different if you are releasing a new minor or major version compared to if
you are making a bugfix patch release. For a new minor or major version, do update-changelog and then jump to
release. For a bug fix to an existing release, do update-changelog and then jump to bugfix.
Changes that are not backwards-compatible may only be made in a major release. New features that do not affect
backwards-compatibility can be made in a minor release. Bug fix releases should be small, only fix bugs, and not
introduce any new features.
There are a few steps that should have been kept up-to-date during day-to-day development, but might not be quite
accurate. For every change that is going to be part of your release, make sure that:
• The user guide in the documentation is updated with any new features, or changes to existing features.
• Any new API classes or functions have entries in a suitable RST file in doc/apidoc.
• Any new or changed docstrings are up-to-date and render correctly in the API documentation.
Please make a normal PR to master correcting anything missing from these points and have it merged before you
begin the release, if necessary.
Ensure that QuTiP’s tests pass on the oldest version supported in the requirements. On major and minor version,
requirements can be adjusted upwards, but patch release must not change minimum requirements. We follow
NEP29 for minimum supported versions
- All minor versions of Python released 42 months prior to the project, and at␣
˓→minimum the two latest minor versions.
- All minor versions of numpy and scipy released in the 24 months prior to the␣
˓→project, and at minimum the last three minor versions.
If dependency versions need to be updated, update them in the master branch. The following files may need to
be updated: .github/workflows/tests.yml, setup.cfg and roadmap.rst. Finally, ensure that PyPI wheels and conda
builds cover at least these versions.
Now jump to release if you are making a major or minor release, or bugfix if you are only fixing bugs in a previous
release.
This involves making a new branch to hold the release and adding some commits to set the code into “release”
mode. This release should be done by branching directly off the master branch at its current head.
1. On your machine, make sure your copy of master is up-to-date (git checkout master; git pull
upstream master). This should at least involve fetching the changelog PR that you just made. Now create
a new branch off a commit in master that has the state of the code you want to release. The command is
git checkout -b qutip-<major>.<minor>.X, for example qutip-4.7.X. This branch name will be
public, and must follow this format.
2. Push the new branch (with no commits in it relative to master) to the main qutip/qutip repository (git
push upstream qutip-4.7.X). Creating a branch is one of the only situations in which it is ok to push to
qutip/qutip without making a pull request.
3. Create a second new branch, which will be pushed to your fork and used to make a pull request against the
qutip-<major>.<minor>.X branch on qutip/qutip you just created. You can call this branch whatever
you like because it is not going to the main repository, for example git checkout -b prepare-qutip-4.
7.0.
4. • Change the VERSION file to contain the new version number exactly, removing the .dev suffix. For
example, if you are releasing the first release of the minor 4.7 track, set VERSION to contain the string
4.7.0. (Special circumstances: if you are making an alpha, beta or release candidate release, append
a .a<n>, .b<n> or .rc<n> to the version string, where <n> is an integer starting from 0 that counts
how many of that pre-release track there have been.)
• Edit setup.cfg by changing the “Development Status” line in the classifiers section to
Commit both changes (git add VERSION setup.cfg; git commit -m "Set release mode for
4.7.0"), and then push them to your fork (git push -u origin prepare-qutip-4.7.0)
5. Using GitHub, make a pull request to the release branch (e.g. qutip-4.7.X) using this branch that you just
created. You will need to change the “base branch” in the pull request, because GitHub will always try to
make the PR against master at first. When the tests have passed, merge this in.
6. Finally, back on master, make a new pull request that changes the VERSION file to be
<next-expected-version>.dev, for example 4.8.0.dev. The “Development Status” in setup.
cfg on master should not have changed, and should be
In this you will modify an already-released branch by “cherry-picking” one or more pull requests that have been
merged to master (including your new changelog), and bump the “patch” part of the version number.
1. On your machine, make sure your copy of master is up-to-date (git checkout master; git pull
upstream master). In particular, make sure the changelog you wrote in the first step is visible.
2. Find the branch of the release that you will be modifying. This should already exist on the qutip/
qutip repository, and be called qutip-<major>.<minor>.X (e.g. qutip-4.6.X). If you cannot see
it, run git fetch upstream to update all the branch references from the main repository. Checkout a
new private branch, starting from the head of the release branch (git checkout -b prepare-qutip-4.
6.1 upstream/qutip-4.6.X). You can call this branch whatever you like (in the example it is
prepare-qutip-4.6.1), because it will only be used to make a pull request.
3. Cherry-pick all the commits that will be added to this release in order, including your PR that wrote the
new changelog entries (this will be the last one you cherry-pick). You will want to use git log to find
the relevant commits, going from oldest to newest (their “age” is when they were merged into master, not
when the PR was first opened). The command is slightly different depending on which merge strategy was
used for a particular PR:
• “merge”: you only need to find one commit though the log will have included several; there will be an
entry in git log with a title such as “Merge pull request #1000 from <. . . >”. Note the first 7 characters
of its hash. Cherry-pick this by git cherry-pick --mainline 1 <hash>.
• “squash and merge”: there will only be a single commit for the entire PR. Its name will be “<Name of the
pull request> (#1000)”. Note the first 7 characters of its hash. Cherry-pick this by git cherry-pick
<hash>.
• “rebase and merge”: this is the most difficult, because there will be many commits that you will have to
find manually, and cherry-pick all of them. Go to the GitHub page for this PR, and go to the “Commits”
tab. Using your local git log (you may find git log --oneline useful), find the hash for every
single commit that is listed on the GitHub page, in order from oldest to newest (top-to-bottom in the
GitHub view, which is bottom-to-top in git log). You will need to use the commit message to do this;
the hashes that GitHub reports will probably not be the same as how they appear locally. Find the first
7 characters of each of the hashes. Cherry-pick these all in one go by git cherry-pick <hash1>
<hash2> ... <hash10>, where <hash1> is the oldest.
If any of the cherry-picks have merge conflicts, first verify that you are cherry-picking in order from oldest
to newest. If you still have merge conflicts, you will either need to manually fix them (if it is a very simple
fix), or else you will need to find which additional PR this patch depends on, and restart the bug fix process
including this additional patch. This generally should not happen if you are sticking to very small bug fixes;
if the fixes had far-reaching changes, a new minor release may be more appropriate.
4. Change the VERSION file by bumping the last number up by one (double-digit numbers are fine, so 4.6.10
comes after 4.6.9), and commit the change.
5. Push this branch to your fork, and make a pull request against the release branch. On GitHub in the PR
screen, you will need to change the “Base” branch to qutip-4.6.X (or whatever version), because GitHub
will default to making it against master. It should be quite clear if you have forgotten to do this, because
there will probably be many merge conflicts. Once the tests have passed and you have another admin’s
approval, merge the PR.
You should now see that the qutip-4.6.X (or whatever) branch on GitHub has been updated, and now includes
all the changes you have just made. If you have made a mistake, feel free to make additonal PRs to rectify the
situation.
You are now ready to actually perform the release. Go to deploy.
This step builds the source (sdist) and binary (wheel) distributions, and uploads them to PyPI (pip). You will also
be able to download the built files yourself in order to upload them to the QuTiP website.
This is handled entirely by a GitHub Action. Go to the “Actions” tab at the top of the QuTiP code repository.
Click on the “Build wheels, optionally deploy to PyPI” action in the left-hand sidebar. Click the “Run workflow”
dropdown in the header notification; it should look like the image below.
• Use the drop-down menu to choose the branch or tag you want to release from. This should be called
qutip-4.5.X or similar, depending on what you made earlier. This must never be master.
• To make the release to PyPI, type the branch name (e.g. qutip-4.5.X) into the “Confirm chosen branch
name [. . . ]” field. You may leave this field blank to skip the deployment and only build the package.
• (Special circumstances) If for some reason you need to override the version number (for example if the
previous deployment to PyPI only partially succeeded), you can type a valid Python version identifier into
the “Override version number” field. You probably do not need to do this. The mechanism is designed
to make alpha-testing major upgrades with nightly releases easier. For even a bugfix release, you should
commit the change to the VERSION file.
• Click the lower “Run workflow” to perform the build and deployment.
At this point, the deployment will take care of itself. It should take between 30 minutes and an hour, after which
the new version will be available for install by pip install qutip. You should see the new version appear on
QuTiP’s PyPI page.
When the build is complete, click into its summary screen. This is the main screen used to both monitor the build
and see its output, and should look like the below image on a success.
The built binary wheels and the source distribution are the “build artifacts” at the bottom. You need to download
both the wheels and the source distribution. Save them on your computer, and unzip both files; you should have
many wheel qutip-*.whl files, and two sdist files: qutip-*.tar.gz and qutip-*.zip. These are the same
files that have just been uploaded to PyPI.
While the build is in progress, you can monitor its progress by clicking on its entry in the list below the “Run work-
flow” button. You should see several subjobs, like the completed screen, except they might not yet be completed.
The “Verify PyPI deployment confirmation” should get ticked, no matter what. If it fails, you have forgotten to
choose the correct branch in the drop-down menu or you made a typo when confirming the correct branch, and you
will need to restart this step. You can check that the deployment instruction has been understood by clicking the
“Verify PyPI deployment confirmation” job, and opening the “Compare confirmation to current reference” subjob.
You will see a message saying “Built wheels will be deployed” if you typed in the confirmation, or “Only building
wheels” if you did not. If you see “Only building wheels” but you meant to deploy the release to PyPI, you can
cancel the workflow and re-run it after typing the confirmation.
This is all done through the “Releases” section of the qutip/qutip repository on GitHub.
• Click the “Draft a new release” button.
• Choose the correct branch for your release (e.g. qutip-4.5.X) in the drop-down.
• For the tag name, use v<your-version>, where the version matches the contents of the VERSION file. In
other words, if you are releasing a micro version 4.5.3, use v4.5.3 as the tag, or if you are releasing major
version 5.0.0, use v5.0.0.
• The title is “QuTiP <your-version>”, e.g. “QuTiP 4.6.0”.
• For the description, write a short (~two-line for a patch release) summary of the reason for this release, and
note down any particular user-facing changes that need special attention. Underneath, put the changelog you
wrote when you did the documentation release. Note that there may be some syntax differences between the
.rst file of the changelog and the Markdown of this description field (for example, GitHub’s markdown
typically maintains hard-wrap linebreaks, which is probably not what you wanted).
• Drag-and-drop all the qutip-*.whl, qutip-*.tar.gz and qutip-*.zip files you got after the build step
into the assets box. You may need to unzip the files wheels.zip and sdist.zip to find them if you haven’t
already; don’t upload those two zip files.
Click on the “Publish release” button to finalise.
8.5.5 Website
This assumes that qutip.github.io has already been forked and familiarity with the website updating workflow. The
documentation need not be updated for every patch release.
• Edit download.html
– The ‘Latest release’ version and date should be updated.
– The tar.gz and zip links need to have their micro release numbers updated in their filenames, labels
and trackEvent javascript. These links should point to the “Source code” links that appeared when
you made in the GitHub Releases section. They should look something like https://github.com/
qutip/qutip/archive/refs/tags/v4.6.0.tar.gz.
– For a minor or major release links to the last micro release of the previous version will need to be moved
(copied) to the ‘Previous releases’ section.
• Edit _includes/sidebar.html
– Add the new version and release date. Only actively developed version should be listed. Micro replace
the previous entry but the last major can be kept.
– Link to the installation instruction, documentation, source code and changelog should be updated.
• Edit documentation.html
– For major and minor release, the previous release tags should be moved (copied) to the ‘Previous
releases’ section and the links to the readthedocs of the new version added the to ‘Latest releases’
section.
Find the sha256 checksum for the tarball that the GitHub web interface generated when you produced the release
called “Source code”. This is not the sdist that you downloaded earlier, it’s a new file that GitHub labels “Source
code”. When you download it, though, it will have a name that looks like it’s the sdist
Edit the recipe/meta.yaml file. Change the version at the top of the file, and update the sha256 checksum.
Check that the recipe package version requirements at least match those in setup.cfg, and that any changes to
the build process are reflected in meta.yml. Also ensure that the build number is reset
build:
number: 0
Make a Pull Request. This will trigger tests of the package build process.
If (when) the tests pass, the PR can be merged, which will trigger the upload of the packages to the conda-forge
channel. To test the packages, add the conda-forge channel with lowest priority
This should mean that the prerequistes come from the default channel, but the qutip packages are found in conda-
forge.
Bibliography
469
QuTiP: Quantum Toolbox in Python, Release 5.0.4
The text of this documentation is licensed under the Creative Commons Attribution 3.0 Unported License. Un-
less specifically indicated otherwise, all code samples, the source code of QuTiP, and its reproductions in this
documentation, are licensed under the terms of the 3-clause BSD license, reproduced below.
471
QuTiP: Quantum Toolbox in Python, Release 5.0.4
e. “Original Author” means, in the case of a literary or artistic work, the individual, individuals, entity
or entities who created the Work or if no individual or entity can be identified, the publisher; and in
addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons
who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or
expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity
who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the
organization that transmits the broadcast.
f. “Work” means the literary and/or artistic work offered under the terms of this License including without
limitation any production in the literary, scientific and artistic domain, whatever may be the mode or
form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, ad-
dress, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic
work or entertainment in dumb show; a musical composition with or without words; a cinematographic
work to which are assimilated works expressed by a process analogous to cinematography; a work of
drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are
assimilated works expressed by a process analogous to photography; a work of applied art; an illus-
tration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or
science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected
as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not
otherwise considered a literary or artistic work.
g. “You” means an individual or entity exercising rights under this License who has not previously violated
the terms of this License with respect to the Work, or who has received express permission from the
Licensor to exercise rights under this License despite a previous violation.
h. “Publicly Perform” means to perform public recitations of the Work and to communicate to the public
those public recitations, by any means or process, including by wire or wireless means or public digital
performances; to make available to the public Works in such a way that members of the public may
access these Works from a place and at a place individually chosen by them; to perform the Work to
the public by any means or process and the communication to the public of the performances of the
Work, including by public digital performance; to broadcast and rebroadcast the Work by any means
including signs, sounds or images.
i. “Reproduce” means to make copies of the Work by any means including without limitation by sound
or visual recordings and the right of fixation and reproducing fixations of the Work, including storage
of a protected performance or phonogram in digital form or other electronic medium.
2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copy-
right or rights arising from limitations or exceptions that are provided for in connection with the copyright
protection under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide,
royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the
rights in the Work as stated below:
a. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Repro-
duce the Work as incorporated in the Collections;
b. to create and Reproduce Adaptations provided that any such Adaptation, including any trans-
lation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify
that changes were made to the original Work. For example, a translation could be marked
“The original work was translated from English to Spanish,” or a modification could indicate
“The original work has been modified.”;
c. to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
d. to Distribute and Publicly Perform Adaptations.
For the avoidance of doubt:
i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to
collect royalties through any statutory or compulsory licensing scheme cannot be waived,
the Licensor reserves the exclusive right to collect such royalties for any exercise by You of
the rights granted under this License;
ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect
royalties through any statutory or compulsory licensing scheme can be waived, the Licen-
sor waives the exclusive right to collect such royalties for any exercise by You of the rights
granted under this License; and,
iii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether indi-
vidually or, in the event that the Licensor is a member of a collecting society that administers
voluntary licensing schemes, via that society, from any exercise by You of the rights granted
under this License.
The above rights may be exercised in all media and formats whether now known or hereafter devised. The
above rights include the right to make such modifications as are technically necessary to exercise the rights
in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby
reserved.
4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following
restrictions:
a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must
include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the
Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that
restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted
to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact
all notices that refer to this License and to the disclaimer of warranties with every copy of the Work
You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may
not impose any effective technological measures on the Work that restrict the ability of a recipient of
the Work from You to exercise the rights granted to that recipient under the terms of the License. This
Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection
apart from the Work itself to be made subject to the terms of this License. If You create a Collection,
upon notice from any Licensor You must, to the extent practicable, remove from the Collection any
credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any
Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by
Section 4(b), as requested.
b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless
a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and
provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or
pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another
party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution (“Attribution Par-
ties”) in Licensor’s copyright notice, terms of service or by other reasonable means, the name of such
party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI,
if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the
copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the
case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., “French trans-
lation of the Work by Original Author,” or “Screenplay based on original Work by Original Author”).
The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided,
however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit
for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in
a manner at least as prominent as the credits for the other contributing authors. For the avoidance of
doubt, You may only use the credit required by this Section for the purpose of attribution in the manner
set out above and, by exercising Your rights under this License, You may not implicitly or explicitly as-
sert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or
Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior
written permission of the Original Author, Licensor and/or Attribution Parties.
c. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable
law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adap-
tations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation
to the Work which would be prejudicial to the Original Author’s honor or reputation. Licensor agrees
that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this
License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification
or other derogatory action prejudicial to the Original Author’s honor and reputation, the Licensor will
waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable na-
tional law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to
make Adaptations) but not otherwise.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OF-
FERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND
CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING,
WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTIC-
ULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVER-
ABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES,
SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT
WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCI-
DENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LI-
CENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSI-
BILITY OF SUCH DAMAGES.
7. Termination
a. This License and the rights granted hereunder will terminate automatically upon any breach by You of
the terms of this License. Individuals or entities who have received Adaptations or Collections from
You under this License, however, will not have their licenses terminated provided such individuals or
entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any
termination of this License.
b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the
applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release
the Work under different license terms or to stop distributing the Work at any time; provided, however
that any such election will not serve to withdraw this License (or any other license that has been, or is
required to be, granted under the terms of this License), and this License will continue in full force and
effect unless terminated as stated above.
8. Miscellaneous
a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the
recipient a license to the Work on the same terms and conditions as the license granted to You under
this License.
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license
to the original Work on the same terms and conditions as the license granted to You under this License.
c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the
validity or enforceability of the remainder of the terms of this License, and without further action by
the parties to this agreement, such provision shall be reformed to the minimum extent necessary to
make such provision valid and enforceable.
d. No term or provision of this License shall be deemed waived and no breach consented to unless such
waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
e. This License constitutes the entire agreement between the parties with respect to the Work licensed
here. There are no understandings, agreements or representations with respect to the Work not specified
here. Licensor shall not be bound by any additional provisions that may appear in any communication
from You. This License may not be modified without the mutual written agreement of the Licensor
and You.
f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the
terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended
on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the
WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as
revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in
which the License terms are sought to be enforced according to the corresponding provisions of the
implementation of those treaty provisions in the applicable national law. If the standard suite of rights
granted under applicable copyright law includes additional rights not granted under this License, such
additional rights are deemed to be included in the License; this License is not intended to restrict the
license of any rights under applicable law.
10.2 License Terms for Source Code of QuTiP and Code Samples
Copyright (c) 2011 to 2022 inclusive, QuTiP developers and contributors. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DI-
RECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUD-
ING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
10.2. License Terms for Source Code of QuTiP and Code Samples 475
QuTiP: Quantum Toolbox in Python, Release 5.0.4
• genindex
• modindex
• search
477
QuTiP: Quantum Toolbox in Python, Release 5.0.4
[LACN19] Neill Lambert, Shahnawaz Ahmed, Mauro Cirio, and Franco Nori. Virtual excitations in the
ultra-strongly-coupled spin-boson model: physical results from unphysical modes. arXiv preprint
arXiv:1903.05892, 2019.
[Tan20] Yoshitaka Tanimura. Numerically “exact” approach to open quantum dynamics: the hierarchical
equations of motion (heom). The Journal of Chemical Physics, 153(2):020901, 2020. URL: https:
//doi.org/10.1063/5.0011599, doi:10.1063/5.0011599.
[TK89] Yoshitaka Tanimura and Ryogo Kubo. Time evolution of a quantum system in contact with a nearly
gaussian-markoffian noise bath. J. Phys. Soc. Jpn., 58(1):101–114, 1989. doi:10.1143/jpsj.58.101.
[1] https://en.wikipedia.org/wiki/Concurrence_(quantum_computing)
[1] J. Rodriguez-Laguna, P. Migdal, M. Ibanez Berganza, M. Lewenstein and G. Sierra, Qubism: self-
similar visualization of many-body wavefunctions, New J. Phys. 14 053028, arXiv:1112.3560 (2012),
open access.
[1] J. Rodriguez-Laguna, P. Migdal, M. Ibanez Berganza, M. Lewenstein and G. Sierra, Qubism: self-
similar visualization of many-body wavefunctions, New J. Phys. 14 053028, arXiv:1112.3560 (2012),
open access.
[1] Javier Cerrillo and Jianshu Cao, Phys. Rev. Lett 112, 110401 (2014) ..
[BCSZ08] W. Bruzda, V. Cappellini, H.-J. Sommers, K. Życzkowski, Random Quantum Operations, Phys. Lett.
A 373, 320-324 (2009). doi:10.1016/j.physleta.2008.11.043.
[Hav03] Havel, T. Robust procedures for converting among Lindblad, Kraus and matrix representa-
tions of quantum dynamical semigroups. Journal of Mathematical Physics 44 2, 534 (2003).
doi:10.1063/1.1518555.
[Wat13] Watrous, J. Theory of Quantum Information, lecture notes.
[Mez07] F. Mezzadri, How to generate random matrices from the classical compact groups, Notices of the
AMS 54 592-604 (2007). arXiv:math-ph/0609050.
[Moh08] M. Mohseni, A. T. Rezakhani, D. A. Lidar, Quantum-process tomography: Resource analysis of
different strategies, Phys. Rev. A 77, 032322 (2008). doi:10.1103/PhysRevA.77.032322.
[Gri98] M. Grifoni, P. Hänggi, Driven quantum tunneling, Physics Reports 304, 299 (1998).
doi:10.1016/S0370-1573(98)00022-2.
[Gar03] Gardineer and Zoller, Quantum Noise (Springer, 2004).
[Bre02] H.-P. Breuer and F. Petruccione, The Theory of Open Quantum Systems (Oxford, 2002).
[Coh92] C. Cohen-Tannoudji, J. Dupont-Roc, G. Grynberg, Atom-Photon Interactions: Basic Processes and
Applications, (Wiley, 1992).
[WBC11] C. Wood, J. Biamonte, D. G. Cory, Tensor networks and graphical calculus for open quantum systems.
arXiv:1111.6950
[dAless08] D. d’Alessandro, Introduction to Quantum Control and Dynamics, (Chapman & Hall/CRC, 2008).
[Byrd95] R. H. Byrd, P. Lu, J. Nocedal, and C. Zhu, A Limited Memory Algorithm for Bound Constrained
Optimization, SIAM J. Sci. Comput. 16, 1190 (1995). doi:10.1137/0916069
479
QuTiP: Quantum Toolbox in Python, Release 5.0.4
[Flo12] F. F. Floether, P. de Fouquieres, and S. G. Schirmer, Robust quantum gates for open systems
via optimal control: Markovian versus non-Markovian dynamics, New J. Phys. 14, 073023
(2012). doi:10.1088/1367-2630/14/7/073023
[Lloyd14] S. Lloyd and S. Montangero, Information theoretical analysis of quantum optimal control, Phys.
Rev. Lett. 113, 010502 (2014). doi:10.1103/PhysRevLett.113.010502
[Doria11] P. Doria, T. Calarco & S. Montangero, Optimal Control Technique for Many-Body Quantum Dy-
namics, Phys. Rev. Lett. 106, 190501 (2011). doi:10.1103/PhysRevLett.106.190501
[Caneva11] T. Caneva, T. Calarco, & S. Montangero, Chopped random-basis quantum optimization, Phys. Rev.
A 84, 022326 (2011). doi:10.1103/PhysRevA.84.022326
[Rach15] N. Rach, M. M. Müller, T. Calarco, and S. Montangero, Dressing the chopped-random-basis op-
timization: A bandwidth-limited access to the trap-free landscape, Phys. Rev. A. 92, 062343
(2015). doi:10.1103/PhysRevA.92.062343
[Wis09] Wiseman, H. M. & Milburn, G. J. Quantum Measurement and Control, (Cambridge University Press,
2009).
[NKanej] N Khaneja et. al. Optimal control of coupled spin dynamics: Design of NMR pulse sequences by
gradient ascent algorithms. J. Magn. Reson. 172, 296–305 (2005). doi:10.1016/j.jmr.2004.11.004
[Donvil22] B. Donvil, P. Muratore-Ginanneschi, Quantum trajectory framework for general time-local master
equations, Nat Commun 13, 4140 (2022). doi:10.1038/s41467-022-31533-8.
[Abd19] M. Abdelhafez, D. I. Schuster, J. Koch, Gradient-based optimal control of open quantum sys-
tems using quantumtrajectories and automatic differentiation, Phys. Rev. A 99, 052327 (2019).
doi:10.1103/PhysRevA.99.052327.
480 Bibliography
Python Module Index
q
qutip, 390
qutip.animation, 374
qutip.continuous_variables, 320
qutip.core.coefficient, 341
qutip.core.dimensions, 310
qutip.core.energy_restricted, 299
qutip.core.expect, 311
qutip.core.gates, 292
qutip.core.metrics, 315
qutip.core.operators, 280
qutip.core.qobj, 301
qutip.core.states, 266
qutip.core.superop_reps, 308
qutip.core.superoperator, 306
qutip.core.tensor, 311
qutip.entropy, 313
qutip.fileio, 386
qutip.ipynbtools, 390
qutip.matplotlib_utilities, 382
qutip.measurement, 322
qutip.partial_transpose, 312
qutip.piqs.piqs, 356
qutip.random_objects, 301
qutip.solver.brmesolve, 334
qutip.solver.correlation, 345
qutip.solver.floquet, 335
qutip.solver.heom, 343
qutip.solver.krylovsolve, 332
qutip.solver.mcsolve, 328
qutip.solver.mesolve, 327
qutip.solver.nm_mcsolve, 330
qutip.solver.nonmarkov.transfertensor, 384
qutip.solver.parallel, 387
qutip.solver.propagator, 354
qutip.solver.scattering, 355
qutip.solver.sesolve, 325
qutip.solver.spectrum, 350
qutip.solver.steadystate, 351
qutip.solver.stochastic, 338
qutip.tomography, 383
qutip.utilities, 385
qutip.visualization, 366
qutip.wigner, 364
481
QuTiP: Quantum Toolbox in Python, Release 5.0.4
A C
about() (in module qutip), 390 c_ops() (Dicke method), 262
add_annotation() (Bloch method), 205 calculate_j_m() (Pim method), 264
add_arc() (Bloch method), 205 calculate_k() (Pim method), 264
add_line() (Bloch method), 205 charge() (in module qutip.core.operators), 280
add_points() (Bloch method), 206 check_herm() (Qobj method), 189
add_states() (Bloch method), 206 clear() (Bloch method), 207
add_vectors() (Bloch method), 206 clebsch() (in module qutip.utilities), 385
am() (in module qutip.piqs.piqs), 356 cnot() (in module qutip.core.gates), 293
anim_fock_distribution() (in module coefficient() (in module qutip.core.coefficient), 341
qutip.animation), 374 coefficient_matrix() (Dicke method), 262
anim_hinton() (in module qutip.animation), 375 coefficient_matrix() (Pim method), 264
anim_matrix_histogram() (in module coherence_function_g1() (in module
qutip.animation), 376 qutip.solver.correlation), 345
anim_qubism() (in module qutip.animation), 378 coherence_function_g2() (in module
anim_schmidt() (in module qutip.animation), 379 qutip.solver.correlation), 345
anim_sphereplot() (in module qutip.animation), 379 coherent() (in module qutip.core.states), 269
anim_spin_distribution() (in module coherent_dm() (in module qutip.core.states), 270
qutip.animation), 380 col_times (McResult property), 259
anim_wigner() (in module qutip.animation), 380 col_times (NmmcResult property), 260
anim_wigner_sphere() (in module qutip.animation), col_which (McResult property), 259
381 col_which (NmmcResult property), 260
ap() (in module qutip.piqs.piqs), 357 collapse_uncoupled() (in module qutip.piqs.piqs),
arguments() (QobjEvo method), 201 357
average_final_state (McResult property), 259 CollapseFeedback() (MCSolver class method), 221
average_final_state (MultiTrajResult property), CollapseFeedback() (NonMarkovianMCSolver class
258 method), 224
average_final_state (NmmcResult property), 260 combine() (BosonicBath class method), 234
average_gate_fidelity() (in module commutator() (in module qutip.core.operators), 280
qutip.core.metrics), 315 complex_phase_cmap() (in module
average_states (McResult property), 259 qutip.matplotlib_utilities), 382
average_states (MultiTrajResult property), 258 composite() (in module qutip.core.tensor), 311
average_states (NmmcResult property), 260 compress() (QobjEvo method), 201
concurrence() (in module qutip.entropy), 313
B conj() (Qobj method), 189
basis() (in module qutip.core.states), 266 conj() (QobjEvo method), 201
Bath (class in qutip.solver.heom), 233 contract() (Qobj method), 189
BathExponent (class in qutip.solver.heom), 232 convert_unit() (in module qutip.utilities), 385
bell_state() (in module qutip.core.states), 267 copy() (Qobj method), 189
berkeley() (in module qutip.core.gates), 292 copy() (QobjEvo method), 201
Bloch (class in qutip.bloch), 204 correlation_2op_1t() (in module
block_matrix() (in module qutip.piqs.piqs), 357 qutip.solver.correlation), 346
BosonicBath (class in qutip.solver.heom), 233 correlation_2op_2t() (in module
bra() (in module qutip.core.states), 268 qutip.solver.correlation), 347
483
QuTiP: Quantum Toolbox in Python, Release 5.0.4
484 Index
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Index 485
QuTiP: Quantum Toolbox in Python, Release 5.0.4
486 Index
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Index 487
QuTiP: Quantum Toolbox in Python, Release 5.0.4
488 Index
QuTiP: Quantum Toolbox in Python, Release 5.0.4
Index 489
QuTiP: Quantum Toolbox in Python, Release 5.0.4
U
UnderDampedBath (class in qutip.solver.heom), 236
unit() (Qobj method), 198
unitarity() (in module qutip.core.metrics), 319
V
variance() (in module qutip.core.expect), 311
vector_to_operator() (in module
qutip.core.superoperator), 307
version_table() (in module qutip.ipynbtools), 390
visualize() (Distribution method), 266
W
w_state() (in module qutip.core.states), 279
WienerFeedback() (SMESolver class method), 243
WienerFeedback() (SSESolver class method), 246
wigner() (in module qutip.wigner), 365
wigner_cmap() (in module qutip.matplotlib_utilities),
382
wigner_covariance_matrix() (in module
qutip.continuous_variables), 321
Z
zero_ket() (in module qutip.core.states), 280
490 Index