Qutip Readthedocs Io en Qutip 5.0.x

Download as pdf or txt
Download as pdf or txt
You are on page 1of 498

QuTiP: Quantum Toolbox in Python

Release 5.0.4

P.D. Nation, J.R. Johansson, A.J.G. Pitchford, C. Granade, A.L. G

Sep 03, 2024


Contents

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

5 API documentation 187


5.1 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
5.1.1 Qobj . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
5.1.2 QobjEvo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
5.1.3 Bloch sphere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
5.1.4 Distributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
5.1.5 Solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
5.1.6 Monte Carlo Solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
5.1.7 Non-Markovian HEOM Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
5.1.8 Stochastic Solver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
5.1.9 Integrator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
5.1.10 Stochastic Integrator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
5.1.11 Solver Options and Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
5.1.12 Permutational Invariance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
5.1.13 Distribution functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
5.2 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
5.2.1 Manipulation and Creation of States and Operators . . . . . . . . . . . . . . . . . . . . 266
5.2.2 Functions acting on states and operators . . . . . . . . . . . . . . . . . . . . . . . . . . 311
5.2.3 Measurement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
5.2.4 Dynamics and Time-Evolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
5.2.5 Visualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
5.2.6 Non-Markovian Solvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
5.2.7 Utility Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385

6 Change Log 391


6.1 QuTiP 5.0.4 (2024-08-30) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6.1.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6.2 QuTiP 5.0.3 (2024-06-20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6.2.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6.2.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6.2.3 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
6.3 QuTiP 5.0.2 (2024-05-16) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
6.3.1 Bug Fixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
6.3.2 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
6.3.3 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
6.4 QuTiP 5.0.1 (2024-04-03) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
6.5 QuTiP 5.0.0 (2024-03-26) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392
6.5.1 Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
6.5.2 Qobj changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
6.5.3 QobjEvo changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
6.5.4 Solver changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396
6.5.5 QuTiP core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
6.5.6 QuTiP settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
6.5.7 Visualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
6.5.8 Package reorganization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
6.5.9 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
6.5.10 Feature removals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
6.5.11 Changes from QuTiP 5.0.0b1: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
6.5.12 Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401

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

8 Development Documentation 439


8.1 Contributing to QuTiP Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
8.1.1 Quick Start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
8.1.2 Core Library: qutip/qutip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
8.1.3 Documentation: qutip/qutip (doc directory) . . . . . . . . . . . . . . . . . . . . . . . . 442
8.2 QuTiP Development Roadmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
8.2.1 Preamble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
8.2.2 Library package structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
8.2.3 Development Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446
8.2.4 Completed Development Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449
8.2.5 QuTiP major release roadmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
8.3 Ideas for future QuTiP development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
8.3.1 QuTiP Interactive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451

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

10 Copyright and Licensing 471


10.1 License Terms for Documentation Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471
10.2 License Terms for Source Code of QuTiP and Code Samples . . . . . . . . . . . . . . . . . . . . 475

11 Indices and tables 477

Bibliography 479

Python Module Index 481

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

1.1 About This Documentation

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.2 Citing This Project

If you find this project useful, then please cite:


J. R. Johansson, P.D. Nation, and F. Nori, “QuTiP 2: A Python framework for the dynamics of open quantum
systems”, Comp. Phys. Comm. 184, 1234 (2013).
or
J. R. Johansson, P.D. Nation, and F. Nori, “QuTiP: An open-source Python framework for the dynamics of open
quantum systems”, Comp. Phys. Comm. 183, 1760 (2012).
which may also be downloaded from https://arxiv.org/abs/1211.6518 or https://arxiv.org/abs/1110.0573, respec-
tively.

1.3 Funding

QuTiP is developed under the auspice of the non-profit organizations:

QuTiP was partially supported by

4 Chapter 1. Frontmatter
QuTiP: Quantum Toolbox in Python, Release 5.0.4

1.4 About QuTiP

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.

1.4. About QuTiP 5


QuTiP: Quantum Toolbox in Python, Release 5.0.4

1.5 QuTiP Plugins

Several libraries depend on QuTiP heavily making QuTiP a super-library


Matsubara
Matsubara is a plugin to study the ultrastrong coupling regime with structured baths
QNET
QNET is a computer algebra package for quantum mechanics and photonic quantum networks

1.6 Libraries Using QuTiP

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

1.7 Contributing to QuTiP

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.

1.7. Contributing to QuTiP 7


QuTiP: Quantum Toolbox in Python, Release 5.0.4

8 Chapter 1. Frontmatter
Chapter 2

Installation

2.1 Quick Start

From QuTiP version 4.6 onwards, you should be able to get a working version of QuTiP with the standard

pip install qutip

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.

2.2 General Requirements

QuTiP depends on several open-source libraries for scientific computing in the Python programming language.
The following packages are currently required:

Package Version Details


Python 3.9+ 3.6+ for version 4.7
NumPy 1.22+ <2.0 1.16+ for version 4.7
SciPy 1.8+ 1.0+ for version 4.7

In addition, there are several optional packages that provide additional functionality:

Package Version Details


matplotlib 1.2.1+ Needed for all visualisation tasks.
cython setuptools 0.29.20+ Needed for compiling some time-dependent Hamiltonians. Cython
filelock needs a working C++ compiler.
cvxpy 1.0+ Needed to calculate diamond norms.
pytest, 5.3+ For running the test suite.
pytest-rerunfailures
LaTeX TeXLive Needed if using LaTeX in matplotlib figures, or for nice circuit draw-
2009+ ings in IPython.
loky, mpi4py Extra parallel map back-ends.
tqdm Extra progress bars back-end.

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.

2.3 Installing with conda

If you already have your conda environment set up, and have the conda-forge channel available, then you can
install QuTiP using:

conda install qutip

This will install the minimum set of dependences, but none of the optional packages.

2.3.1 Adding the conda-forge channel

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:

conda config --append channels conda-forge

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.

2.3.2 New conda environments

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:

conda create -n qutip-env python qutip

This will automatically install all the necessary packages, and none of the optional packages. You activate the new
environment by running

conda activate qutip-env

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

2.4 Installing from Source

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.

2.4.1 PEP 517 Source Builds

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)

pip install build


python -m build <path to qutip>
pip install <path to qutip>/dist/qutip-<version>.whl

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.

2.4.2 Direct Setuptools Source Builds

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

pip install setuptools wheel packaging cython 'numpy<2.0.0' scipy

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:

python setup.py develop

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.

2.4. Installing from Source 11


QuTiP: Quantum Toolbox in Python, Release 5.0.4

2.5 Installation on Windows

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.

2.6 Verifying the Installation

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.

2.7 Checking Version Information

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

3.1 Guide Overview

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.

3.2 Basic Operations on Quantum Objects

3.2.1 First things first

Warning: Do not run QuTiP from the installation directory.

To load the qutip modules, first call the import statement:

from qutip import *

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

import matplotlib.pyplot as plt

14 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

3.2.2 The quantum object class

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))

3.2. Basic Operations on Quantum Objects 15


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

States and operators

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:

States Command (# Inputs


means optional)
Fock state ket vector basis(N, N = number of levels in Hilbert space, m = level con-
#m)/fock(N,#m) taining excitation (0 if no m given)
Empty ket vector zero_ket(N) N = number of levels in Hilbert space,
Fock density matrix (outer fock_dm(N,#p) same as basis(N,m) / fock(N,m)
product of basis)
Coherent state coherent(N, alpha = complex number (eigenvalue) for requested co-
alpha) herent state
Coherent density matrix coherent_dm(N, same as coherent(N,alpha)
(outer product) alpha)
Thermal density matrix (for thermal_dm(N,n) n = particle number expectation value
n particles)
Maximally mixed density N = number of levels in Hilbert space
maximally_mixed_dm(N)
matrix

16 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Operators Command (# means Inputs


optional)
Charge operator charge(N,M=-N) Diagonal operator with entries from M..0..N.
Commutator commutator(A, B, Kind = ‘normal’ or ‘anti’.
kind)
Diagonals operator qdiags(N) Quantum object created from arrays of diagonals at given
offsets.
Displacement operator displace(N,alpha) N=number of levels in Hilbert space, alpha = complex
(Single-mode) displacement amplitude.
Higher spin operators jmat(j,#s) j = integer or half-integer representing spin, s = ‘x’, ‘y’,
‘z’, ‘+’, or ‘-’
Identity qeye(N) N = number of levels in Hilbert space.
Identity-like qeye_like(qobj) qobj = Object to copy dimensions from.
Lowering (destruction) destroy(N) same as above
operator
Momentum operator momentum(N) same as above
Number operator num(N) same as above
Phase operator (Single- phase(N, phi0) Single-mode Pegg-Barnett phase operator with ref phase
mode) phi0.
Position operator position(N) same as above
Raising (creation) opera- create(N) same as above
tor
Squeezing operator squeeze(N, sp) N=number of levels in Hilbert space, sp = squeezing pa-
(Single-mode) rameter.
Squeezing operator (Gen- squeezing(q1, q2, q1,q2 = Quantum operators (Qobj) sp = squeezing pa-
eralized) sp) rameter.
Sigma-X sigmax()
Sigma-Y sigmay()
Sigma-Z sigmaz()
Sigma plus sigmap()
Sigma minus sigmam()
Tunneling operator tunneling(N,m) Tunneling operator with elements of the form |𝑁 ><
𝑁 + 𝑚| + |𝑁 + 𝑚 >< 𝑁 |.

As an example, we give the output for a few of these functions:

>>> 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)

3.2. Basic Operations on Quantum Objects 17


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


Qobj data =
[[0. 1. 0. 0. ]
[0. 0. 1.41421356 0. ]
[0. 0. 0. 1.73205081]
[0. 0. 0. 0. ]]

>>> 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:

Property At- Description


tribute
Data Q. Matrix representing state or operator
data
Dimen- Q. List keeping track of shapes for individual components of a multipartite system (for
sions dims tensor products and partial traces).
Shape Q. Dimensions of underlying data matrix.
shape
is Hermi- Q. Is the operator Hermitian or not?
tian? isherm
Type Q. Is object of type ‘ket, ‘bra’, ‘oper’, or ‘super’?
type

18 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Fig. 2: The Qobj Class viewed as a container for the properties needed to characterize a quantum operator or state
vector.

For the destruction operator above:

>>> 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>

Conversion between storage type is done using the Qobj.to method.

>>> 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>

Note that Qobj.data_as does not do the conversion.


QuTiP will do conversion when needed to keep everything working in any format. However these conversions
could slow down computation and it is recommended to keep to one format family where possible. For example,
core QuTiP Dense and CSR work well together and binary operations between these formats is efficient. However
binary operations between Dense and Jax should be avoided since it is not always clear whether the operation will
be executed by Jax (possibly on a GPU if present) or numpy.

3.2. Basic Operations on Quantum Objects 19


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

~/Documents/qutip_dev/qutip/qutip/qobj.py in __mul__(self, other)


553
554 else:
--> 555 raise TypeError("Incompatible Qobj shapes")
556
557 elif isinstance(other, np.ndarray):

TypeError: Incompatible Qobj shapes

In addition, the logic operators “is equal” == and “is not equal” != are also supported.

20 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.2.3 Functions operating on Qobj class

Like attributes, the quantum object class has defined functions (methods) that operate on Qobj class instances. For
a general quantum object Q:

Function Command Description


Check Her- Q.check_herm() Check if quantum object is Hermitian
micity
Conjugate Q.conj() Conjugate of quantum object.
Cosine Q.cosm() Cosine of quantum object.
Dagger (ad- Q.dag() Returns adjoint (dagger) of object.
joint)
Diagonal Q.diag() Returns the diagonal elements.
Diamond Q.dnorm() Returns the diamond norm.
Norm
Eigenenergies Q.eigenenergies() Eigenenergies (values) of operator.
Eigenstates Q.eigenstates() Returns eigenvalues and eigenvectors.
Exponential Q.expm() Matrix exponential of operator.
Full Q.full() Returns full (not sparse) array of Q’s data.
Groundstate Q.groundstate() Eigenval & eigket of Qobj groundstate.
Matrix inverse Q.inv() Matrix inverse of the Qobj.
Matrix Ele- Q.matrix_element(bra, Matrix element <bra|Q|ket>
ment ket)
Norm Q.norm() Returns L2 norm for states, trace norm for operators.
Overlap Q.overlap(state) Overlap between current Qobj and a given state.
Partial Trace Q.ptrace(sel) Partial trace returning components selected using ‘sel’ param-
eter.
Permute Q.permute(order) Permutes the tensor structure of a composite object in the
given order.
Projector Q.proj() Form projector operator from given ket or bra vector.
Sine Q.sinm() Sine of quantum operator.
Sqrt Q.sqrtm() Matrix sqrt of operator.
Tidyup Q.tidyup() Removes small elements from Qobj.
Trace Q.tr() Returns trace of quantum object.
Conversion Q.to(dtype) Convert the matrix format CSR / Dense.
Transform Q.transform(inpt) A basis transformation defined by matrix or list of kets ‘inpt’
.
Transpose Q.trans() Transpose of quantum object.
Truncate Neg Q.trunc_neg() Truncates negative eigenvalues
Unit Q.unit() Returns normalized (unit) vector Q/Q.norm().

>>> basis(5, 3)
Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[1.]
[0.]]

>>> basis(5, 3).dag()


Quantum object: dims = [[1], [5]], shape = (1, 5), type = bra
Qobj data =
[[0. 0. 0. 1. 0.]]

>>> coherent_dm(5, 1)
(continues on next page)

3.2. Basic Operations on Quantum Objects 21


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[0.36791117 0.36774407 0.26105441 0.14620658 0.08826704]
[0.36774407 0.36757705 0.26093584 0.14614018 0.08822695]
[0.26105441 0.26093584 0.18523331 0.10374209 0.06263061]
[0.14620658 0.14614018 0.10374209 0.05810197 0.035077 ]
[0.08826704 0.08822695 0.06263061 0.035077 0.0211765 ]]

>>> coherent_dm(5, 1).diag()


array([0.36791117, 0.36757705, 0.18523331, 0.05810197, 0.0211765 ])

>>> coherent_dm(5, 1).full()


array([[0.36791117+0.j, 0.36774407+0.j, 0.26105441+0.j, 0.14620658+0.j,
0.08826704+0.j],
[0.36774407+0.j, 0.36757705+0.j, 0.26093584+0.j, 0.14614018+0.j,
0.08822695+0.j],
[0.26105441+0.j, 0.26093584+0.j, 0.18523331+0.j, 0.10374209+0.j,
0.06263061+0.j],
[0.14620658+0.j, 0.14614018+0.j, 0.10374209+0.j, 0.05810197+0.j,
0.035077 +0.j],
[0.08826704+0.j, 0.08822695+0.j, 0.06263061+0.j, 0.035077 +0.j,
0.0211765 +0.j]])

>>> coherent_dm(5, 1).norm()


1.0000000175063126

>>> coherent_dm(5, 1).sqrtm()


Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = False
Qobj data =
[[0.36791117+3.66778589e-09j 0.36774407-2.13388761e-09j
0.26105441-1.51480558e-09j 0.14620658-8.48384618e-10j
0.08826704-5.12182118e-10j]
[0.36774407-2.13388761e-09j 0.36757705+2.41479965e-09j
0.26093584-1.11446422e-09j 0.14614018+8.98971115e-10j
0.08822695+6.40705133e-10j]
[0.26105441-1.51480558e-09j 0.26093584-1.11446422e-09j
0.18523331+4.02032413e-09j 0.10374209-3.39161017e-10j
0.06263061-3.71421368e-10j]
[0.14620658-8.48384618e-10j 0.14614018+8.98971115e-10j
0.10374209-3.39161017e-10j 0.05810197+3.36300708e-10j
0.035077 +2.36883273e-10j]
[0.08826704-5.12182118e-10j 0.08822695+6.40705133e-10j
0.06263061-3.71421368e-10j 0.035077 +2.36883273e-10j
0.0211765 +1.71630348e-10j]]

>>> coherent_dm(5, 1).tr()


1.0

>>> (basis(4, 2) + basis(4, 1)).unit()


Quantum object: dims = [[4], [1]], shape = (4, 1), type = ket
Qobj data =
[[0. ]
[0.70710678]
[0.70710678]
[0. ]]

22 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.3 Manipulating States and Operators

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.

3.3.2 State Vectors (kets or bras)

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.]]

and then create a lowering operator (ˆ


𝑎) corresponding to 5 number states using the destroy function:

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.]]

3.3. Manipulating States and Operators 23


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

24 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[1.41421356]
[0. ]
[0. ]]

Applying the raising operator twice gives the expected 𝑛 + 1 dependence. We can use the product of 𝑐 * 𝑎 to
also apply the number operator to the state vector vac:

print(c * a * vac)

Output:

Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[0.]
[0.]
[0.]]

or on the |1⟩ state:

print(c * a * (c * vac))

Output:

Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]
[0.]]

or the |2⟩ state:

print(c * a * (c**2 * vac))

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:

print(c * a * (c**2 * vac).unit())

Output:

Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
(continues on next page)

3.3. Manipulating States and Operators 25


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[[0.]
[0.]
[2.]
[0.]
[0.]]

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.]]

Therefore, instead of c * a * (c ** 2 * vac).unit() we have:

print(n * ket)

Output:

Quantum object: dims = [[5], [1]], shape = (5, 1), type = ket
Qobj data =
[[0.]
[0.]
[2.]
[0.]
[0.]]

We can also create superpositions of states:

26 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

ket = (basis(5, 0) + basis(5, 1)).unit()

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)

s = squeeze(5, np.complex(0.25, 0.25))

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)

3.3. Manipulating States and Operators 27


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[ 0.10779462+0.51579735j]
[-0.37567217-0.01326853j]
[-0.02688063-0.23828775j]
[ 0.26352814+0.11512178j]]

Of course, displacing the vacuum gives a coherent state, which can also be generated using the built in coherent
function.

3.3.3 Density matrices

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.]]

28 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

print(0.5 * ket2dm(basis(5, 4)) + 0.5 * ket2dm(basis(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. 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)

y = coherent_dm(5, np.complex(0, 1.25)) # <-- note the 'j'

z = thermal_dm(5, 0.125)

np.testing.assert_almost_equal(fidelity(x, x), 1)

np.testing.assert_almost_equal(hellinger_dist(x, y), 1.3819080728932833)



We also know that for two pure states, the trace distance (T) and the fidelity (F) are related by 𝑇 = 1 − 𝐹 2 , while

3.3. Manipulating States and Operators 29


QuTiP: Quantum Toolbox in Python, Release 5.0.4

√︁
2
the quantum Hellinger distance (QHE) between two pure states |𝜓⟩ and |𝜑⟩ is given by 𝑄𝐻𝐸 = 2 − 2 |⟨𝜓|𝜑⟩| .

np.testing.assert_almost_equal(tracedist(y, x), np.sqrt(1 - fidelity(y, x) ** 2))

For a pure state and a mixed state, 1 − 𝐹 2 ≤ 𝑇 which can also be verified:

assert 1 - fidelity(x, z) ** 2 < tracedist(x, z)

3.3.4 Qubit (two-level) systems

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.]]

30 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

3.3. Manipulating States and Operators 31


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

The pre-defined gates are shown in the table below:

Gate function Description


rx Rotation around x axis
ry Rotation around y axis
rz Rotation around z axis
sqrtnot Square root of not gate
sqrtnot Square root of not gate
snot Hardmard gate
phasegate Phase shift gate
qrot A qubit rotation under a Rabi pulse
cy_gate Controlled y gate
cz_gate Controlled z gate
s_gate Single-qubit rotation
t_gate Square root of s gate
cs_gate Controlled s gate
ct_gate Controlled t gate
cphase Controlled phase gate
cnot Controlled not gate
csign Same as cphase
berkeley Berkeley gate
swapalpha Swapalpha gate
swap Swap the states of two qubits
iswap Swap gate with additional phase for 01 and 10 states
sqrtswap Square root of the swap gate
sqrtiswap Square root of the iswap gate
fredkin Fredkin gate
molmer_sorensen Molmer Sorensen gate
toffoli Toffoli gate
hadamard_transform Hadamard gate
qubit_clifford_group Generates the Clifford group on a single qubit
globalphase Global phase gate

To load this qutip module, first you have to import gates:

from qutip import gates

For example to use the Hadamard Gate:

32 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

H = gates.hadamard_transform()
print(H)

Output:

Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', dtype=Dense, isherm=True


Qobj data =
[[ 0.70710678 0.70710678]
[0.70710678 -0.70710678]]

3.3.6 Expectation values

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)

coh = coherent_dm(5, 1.0j)

np.testing.assert_almost_equal(expect(N, coh), 0.9970555745806597)

cat = (basis(5, 4) + 1.0j * basis(5, 3)).unit()

np.testing.assert_almost_equal(expect(c, cat), 0.9999999999999998j)

The expect function also accepts lists or arrays of state vectors or density matrices for the second input:

states = [(c**k * vac).unit() for k in range(5)] # must normalize

print(expect(N, states))

Output:

[0. 1. 2. 3. 4.]

cat_list = [(basis(5, 4) + x * basis(5, 3)).unit() for x in [0, 1.0j, -1.0, -1.0j]]

print(expect(c, cat_list))

Output:

[ 0.+0.j 0.+1.j -1.+0.j 0.-1.j]

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

3.3. Manipulating States and Operators 33


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

np.testing.assert_almost_equal(expect(sigmaz(), down), -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)

two_spins = tensor(spin1, spin2)

sz1 = tensor(sigmaz(), qeye(2))

sz2 = tensor(qeye(2), sigmaz())

np.testing.assert_almost_equal(expect(sz1, two_spins), 1)

np.testing.assert_almost_equal(expect(sz2, two_spins), -1)

3.3.7 Superoperators and Vectorized Operators

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:

34 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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()

S = spre(X) * spost(X.dag()) # Represents conjugation by X.

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)

Quantum objects representing superoperators are denoted by type='super':

print(S)

Output:

3.3. Manipulating States and Operators 35


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

print(S.iscp, S.istp, S.iscptp)

Output:

True True True

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:

from qutip import *


settings.colorblind_safe = True

import matplotlib.pyplot as plt


plt.rcParams['savefig.transparent'] = True

X = sigmax()
S = spre(X) * spost(X.dag())
(continues on next page)

36 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

hinton(S)

I X Y Z

I 1.0

0.5
X
0.0
Y 0.5

1.0
Z

3.3.8 Choi, Kraus, Stinespring and 𝜒 Representations

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

(continues on next page)

3.3. Manipulating States and Operators 37


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


Qobj data =
[[0. 0. 0. 0.]
[0. 1. 1. 0.]
[0. 1. 1. 0.]
[0. 0. 0. 0.]]

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)

38 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[0. 1. 0. 0.]
[1. 0. 0. 0.]]

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.

del sum # np.sum overwrote sum and caused a bug.

I, X, Y, Z = qeye(2), sigmax(), sigmay(), sigmaz()

S = sum([sprepost(P, P) for P in (I, X, Y, Z)]) / 4


print(S)

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)

3.3. Manipulating States and Operators 39


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[0.]
[0.]]
Quantum object: dims = [[[2], [2]], [1, 1]], shape = (4, 1), type = operator-ket
Qobj data =
[[0.]
[1.]
[0.]
[0.]]
Quantum object: dims = [[[2], [2]], [1, 1]], shape = (4, 1), type = operator-ket
Qobj data =
[[0.]
[0.]
[1.]
[0.]]
Quantum object: dims = [[[2], [2]], [1, 1]], shape = (4, 1), type = operator-ket
Qobj data =
[[0.]
[0.]
[0.]
[1.]]]

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

(continues on next page)

40 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


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]]]

for A, AJ in zip(K, KJ):


print(A - AJ)

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 ℋ,

Λ(𝑋) = Tr2 (𝐴𝑋𝐵 † ),

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()

S_ad = sprepost(a * a.dag(), a * a.dag()) + sprepost(a, a.dag())


S = 0.9 * sprepost(I, I) + 0.1 * S_ad

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)

3.3. Manipulating States and Operators 41


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[0. 0. 0.9 0. ]
[0. 0. 0. 0.9]]

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:

[0. 0.04861218 0.1 1.85138782]

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)

42 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[[3.7+0.j 0. +0.j 0. +0.j 0.1+0.j ]
[0. +0.j 0.1+0.j 0. +0.1j 0. +0.j ]
[0. +0.j 0. -0.1j 0.1+0.j 0. +0.j ]
[0.1+0.j 0. +0.j 0. +0.j 0.1+0.j ]]

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.

3.3.9 Properties of Quantum Maps

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:

[-0.5 0.5 0.5 0.5]

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

3.3. Manipulating States and Operators 43


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

3.4 Using Tensor Products and Partial Traces

3.4.1 Tensor products

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:

>>> tensor(op1, op2, op3)

or a list:

>>> tensor([op1, op2, op3])

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:

print(tensor(basis(2, 0), basis(2, 0)))

Output:

44 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Quantum object: dims = [[2, 2], [1, 1]], shape = (4, 1), type = ket
Qobj data =
[[1.]
[0.]
[0.]
[0.]]

or equivalently using the list format:

print(tensor([basis(2, 0), basis(2, 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:

print(tensor((basis(2, 0) + basis(2, 1)).unit(), (basis(2, 0) + basis(2, 1)).unit(),␣


˓→basis(2, 0)))

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

3.4. Using Tensor Products and Partial Traces 45


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.]]

3.4.2 Example: Constructing composite Hamiltonians

The tensor function is extensively used when constructing Hamiltonians for composite systems. Here we’ll look
at some simple examples.

Two coupled qubits

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:

H = tensor(sigmaz(), identity(2)) + tensor(identity(2), sigmaz()) + 0.05 *␣


˓→tensor(sigmax(), sigmax())

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. ]]

Three coupled qubits

The two-qubit example is easily generalized to three coupled qubits:

H = (tensor(sigmaz(), identity(2), identity(2)) + tensor(identity(2), sigmaz(),␣


˓→identity(2)) + tensor(identity(2), identity(2), sigmaz()) + 0.5 * tensor(sigmax(),␣

˓→sigmax(), identity(2)) + 0.25 * tensor(identity(2), sigmax(), sigmax()))

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)

46 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[ 0. 1. 0.25 0. 0. 0. 0. 0.5 ]
[ 0. 0.25 1. 0. 0.5 0. 0. 0. ]
[ 0.25 0. 0. -1. 0. 0.5 0. 0. ]
[ 0. 0. 0.5 0. 1. 0. 0. 0.25]
[ 0. 0. 0. 0.5 0. -1. 0.25 0. ]
[ 0.5 0. 0. 0. 0. 0.25 -1. 0. ]
[ 0. 0.5 0. 0. 0.25 0. 0. -3. ]]

A two-level system coupled to a cavity: The Jaynes-Cummings model

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))

H = 0.5 * omega_a * sz + omega_c * a.dag() * a + g * (a.dag() * sm + a * sm.dag())

hinton(H, fig=plt.figure(figsize=(12, 12)))

3.4. Using Tensor Products and Partial Traces 47


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Here N is the number of Fock states included in the cavity mode.

3.4.3 Partial trace

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 = tensor(basis(2, 0), basis(2, 1))

>>> psi.ptrace(0)
Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper, isherm = True
(continues on next page)

48 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


Qobj data =
[[1. 0.]
[0. 0.]]

>>> 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 = tensor((basis(2, 0) + basis(2, 1)).unit(), basis(2, 0))

>>> 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 = tensor(ket2dm((basis(2, 0) + basis(2, 1)).unit()), fock_dm(2, 0))

>>> 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]]

3.4.4 Superoperators and Tensor Manipulations

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:

3.4. Using Tensor Products and Partial Traces 49


QuTiP: Quantum Toolbox in Python, Release 5.0.4

>>> A = qeye([2])

>>> B = qeye([3])

>>> to_super(tensor(A, B)).dims


[[[2, 3], [2, 3]], [[2, 3], [2, 3]]]

>>> tensor(to_super(A), to_super(B)).dims


[[[2], [2], [3], [3]], [[2], [2], [3], [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:

>>> super_tensor(to_super(A), to_super(B)).dims


[[[2, 3], [2, 3]], [[2, 3], [2, 3]]]

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.

>>> composite(A, B).dims


[[2, 3], [2, 3]]

>>> composite(to_super(A), to_super(B)).dims


[[[2, 3], [2, 3]], [[2, 3], [2, 3]]]

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:

>>> tensor_contract(composite(to_super(A), to_super(B)), (1, 3), (4, 6)).dims


[[[2], [2]], [[3], [3]]]

3.5 Superoperators, Pauli Basis and Channel Contraction

written by Christopher Granade <http://www.cgranade.com>, Institute for Quantum Computing


In this guide, we will demonstrate the tensor_contract function, which contracts one or more pairs of indices
of a Qobj. This functionality can be used to find rectangular superoperators that implement the partial trace chan-
nel :math:S(rho) = Tr_2(rho)`, for instance. Using this functionality, we can quickly turn a system-environment
representation of an open quantum process into a superoperator representation.

50 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.5.1 Superoperator Representations and Plotting

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

3.5. Superoperators, Pauli Basis and Channel Contraction 51


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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()))

52 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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())))

3.5. Superoperators, Pauli Basis and Channel Contraction 53


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

54 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.5.2 Reduced Channels

As an example of tensor contraction, we now consider the map

𝑆(𝜌) = Tr2 (CNOT(𝜌⊗|0⟩⟨0|)CNOT† )

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).

tensor_contract(to_super(identity([2, 2])), (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()))

3.5. Superoperators, Pauli Basis and Channel Contraction 55


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

hinton(tensor_contract(to_super(cnot()), (1, 3)) * s_prep)

56 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

I X Y Z

I 1.0

0.5
X
0.0
Y 0.5

1.0
Z

3.6 Time Evolution and Quantum System Dynamics

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:

3.6. Time Evolution and Quantum System Dynamics 57


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Table 1: QuTiP Solvers


Equation Function Class Returns
Unitary evolution, Schrödinger equation. sesolve SESolver Result
Periodic Schrödinger equation. fsesolve None Result
Schrödinger equation using Krylov method krylovsolve None Result
Lindblad master eqn. or Von Neuman eqn. mesolve MESolver Result
Monte Carlo evolution mcsolve MCSolver McResult
Non-Markovian Monte Carlo nm_mcsolve NonMarkovianMCSolver
NmmcResult
Bloch-Redfield master equation brmesolve BRSolver Result
Floquet-Markov master equation fmmesolve FMESolver FloquetResult
Stochastic Schrödinger equation ssesolve SSESolver MultiTrajResult
Stochastic master equation smesolve SMESolver MultiTrajResult
Transfer Tensor Method time-evolution ttmsolve None Result
Hierarchical Equations of Motion evolu- heomsolve HEOMSolver HEOMResult
tion

3.6.2 Dynamics Simulation Results

The solver.Result Class

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.

Accessing Result Data

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)

58 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


Number of e_ops: 1
State not saved.
>

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:

e_ops = {"sx": sigmax(), "sy": sigmay(), "sz": sigmaz()}


...
expt_sx = result.e_data["sx"]

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

we can plot the resulting expectation values:

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.

Multiple Trajectories Solver Results

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:

>>> mcsolve(H, psi, np.linspace(0, 1, 11), c_ops, e_ops=[num(N)], ntraj=25, options={


˓→"keep_runs_results": False})

>>> np.shape(result.expect)
(1, 11)

>>> mcsolve(H, psi, np.linspace(0, 1, 11), c_ops, e_ops=[num(N)], ntraj=25, options={


˓→"keep_runs_results": True})

>>> 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:

3.6. Time Evolution and Quantum System Dynamics 59


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Reduced result Trajectories re- Description


sults
average_states State vectors or density matrices calculated at each times of
runs_states
tlist
average_final_state runs_final_state State vectors or density matrices calculated at the last time of
tlist
average_expect runs_expect List/array of expectation values, if requested.
std_expect List/array of standard derivation of the expectation values.
average_e_data runs_e_data Dictionary of expectation values, if requested.
std_e_data Dictionary of standard derivation of the expectation values.

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.

>>> run1 = smesolve(H, psi, np.linspace(0, 1, 11), c_ops, e_ops=[num(N)], ntraj=25)


>>> print(run1.num_trajectories)
25
>>> run2 = smesolve(H, psi, np.linspace(0, 1, 11), c_ops, e_ops=[num(N)], ntraj=25)
>>> print(run2.num_trajectories)
25
>>> merged = run1 + run2
>>> print(merged.num_trajectories)
50

This allows one to improve statistics while keeping previous computations.

3.6.3 Lindblad Master Equation Solver

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.

60 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

>>> H = 2*np.pi * 0.1 * sigmax()


>>> psi0 = basis(2, 0)
>>> times = np.linspace(0.0, 10.0, 20)
>>> solver = SESolver(H)
>>> result = solver.run(psi0, times, e_ops=[sigmaz()])
>>> result.expect
[array([ 1. , 0.78914057, 0.24548543, -0.40169579, -0.87947417,
-0.98636112, -0.67728018, -0.08257665, 0.54695111, 0.94581862,
0.94581574, 0.54694361, -0.08258559, -0.67728679, -0.9863626 ,
-0.87946979, -0.40168705, 0.24549517, 0.78914703, 1. ])]

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.

>>> solver.run(psi0, times, e_ops={"s_z": sigmaz(), "s_y": sigmay()}).e_data


{'s_z': [1.0, 0.7891405656865187, 0.24548542861367784, -0.40169578982499127,
..., 0.24549516882108563, 0.7891470300925004, 0.9999999999361128],
's_y': [0.0, -0.6142126403681064, -0.9694002807604085, -0.9157731664756708,
..., 0.9693978141534602, 0.6142043348073879, -1.1303742482923297e-05]}

The resulting expectation values can easily be visualized using matplotlib’s plotting functions:

>>> H = 2*np.pi * 0.1 * sigmax()


>>> psi0 = basis(2, 0)
>>> times = np.linspace(0.0, 10.0, 100)
>>> result = sesolve(H, psi0, times, [sigmaz(), sigmay()])
>>> fig, ax = plt.subplots()
>>> ax.plot(result.times, result.expect[0])
>>> ax.plot(result.times, result.expect[1])
>>> ax.set_xlabel('Time')
>>> ax.set_ylabel('Expectation values')
>>> ax.legend(("Sigma-Z", "Sigma-Y"))
>>> plt.show()

3.6. Time Evolution and Quantum System Dynamics 61


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

>>> times = [0.0, 1.0]


>>> result = sesolve(H, psi0, times, [])
>>> result.states
[Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[1.]
[0.]], Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.80901699+0.j ]
[0. -0.58778526j]]]

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.

62 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

The Lindblad Master equation

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

𝐻tot = 𝐻sys + 𝐻env + 𝐻int ,

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

3.6. Time Evolution and Quantum System Dynamics 63


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

>>> times = np.linspace(0.0, 10.0, 100)


>>> result = mesolve(H, psi0, times, [np.sqrt(0.05) * sigmax()], e_ops=[sigmaz(),␣
˓→sigmay()])

>>> fig, ax = plt.subplots()


>>> ax.plot(times, result.expect[0])
>>> ax.plot(times, result.expect[1])
>>> ax.set_xlabel('Time')
>>> ax.set_ylabel('Expectation values')
>>> ax.legend(("Sigma-Z", "Sigma-Y"))
>>> plt.show()

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

64 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

>>> times = np.linspace(0.0, 10.0, 200)


>>> psi0 = tensor(fock(2,0), fock(10, 5))
>>> a = tensor(qeye(2), destroy(10))
>>> sm = tensor(destroy(2), qeye(10))
>>> H = 2 * np.pi * a.dag() * a + 2 * np.pi * sm.dag() * sm + 2 * np.pi * 0.25 * (sm␣
˓→* a.dag() + sm.dag() * a)
>>> result = mesolve(H, psi0, times, [np.sqrt(0.1)*a], e_ops=[a.dag()*a, sm.dag()*sm])
>>> plt.figure()
>>> plt.plot(times, result.expect[0])
>>> plt.plot(times, result.expect[1])
>>> plt.xlabel('Time')
>>> plt.ylabel('Expectation values')
>>> plt.legend(("cavity photon number", "atom excitation probability"))
>>> plt.show()

5 cavity photon number


atom excitation probability

4
Expectation values

0
0 2 4 6 8 10
Time

3.6.4 Monte Carlo Solver

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

3.6. Time Evolution and Quantum System Dynamics 65


QuTiP: Quantum Toolbox in Python, Release 5.0.4

equation with a non-Hermitian effective Hamiltonian

𝑖ℏ ∑︁ +
𝐻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

𝑃𝑖 (𝑡) = 𝜓(𝑡)|𝐶𝑖+ 𝐶𝑖 |𝜓(𝑡) /𝛿𝑝. (3.7)


⟨︀ ⟩︀

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.

Monte Carlo in QuTiP

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

66 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

times = np.linspace(0.0, 10.0, 200)


psi0 = tensor(fock(2, 0), fock(10, 8))
a = tensor(qeye(2), destroy(10))
sm = tensor(destroy(2), qeye(10))
H = 2*np.pi*a.dag()*a + 2*np.pi*sm.dag()*sm + 2*np.pi*0.25*(sm*a.dag() + sm.dag()*a)
data = mcsolve(H, psi0, times, [np.sqrt(0.1) * a], e_ops=[a.dag() * a, sm.dag() * sm])

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()

Monte Carlo time evolution


8 cavity photon number
atom excitation probability
7
6
Expectation values

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.

3.6. Time Evolution and Quantum System Dynamics 67


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Monte Carlo Solver Result

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.

Changing the Number of Trajectories

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:

data = mcsolve(H, psi0, times, c_ops e_ops=e_ops, ntraj=1000)

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:

data = mcsolve(H, psi0, times, [np.sqrt(0.1) * a], e_ops=e_ops, ntraj=1000,␣


˓→timeout=60)

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:

data = mcsolve(H, psi0, times, [np.sqrt(0.1) * a], e_ops=e_ops,


ntraj=1000, target_tol=0.01, timeout=600)

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:

data = mcsolve(H, psi0, times, c_ops, e_ops=e_ops, target_tol=[


(1e-5, 0.1),
(0, 0),
])

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:

68 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

>>> run1 = mcsolve(H, psi, times, c_ops, e_ops=e_ops, ntraj=25)


>>> print(run1.num_trajectories)
25
>>> run2 = mcsolve(H, psi, times, c_ops, e_ops=e_ops, ntraj=25)
>>> print(run2.num_trajectories)
25
>>> merged = run1 + run2
>>> print(merged.num_trajectories)
50

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:

solver = MCSolver(H, c_ops=[np.sqrt(0.1) * a])


c_ops=[np.sqrt(0.1) * a]
e_ops = [a.dag() * a, sm.dag() * sm]

data1 = mcsolve(H, psi0, times, c_ops, e_ops=e_ops, ntraj=1)


data10 = data1 + mcsolve(H, psi0, times, c_ops, e_ops=e_ops, ntraj=9)
data100 = data10 + mcsolve(H, psi0, times, c_ops, e_ops=e_ops, ntraj=90)

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()

3.6. Time Evolution and Quantum System Dynamics 69


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Monte Carlo time evolution


8 ntraj=1
ntraj=10
ntraj=100
7
Expectation values

0 2 4 6 8 10
Time

Using the Improved Sampling Algorithm

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:

data = mcsolve(H, psi0, times, [np.sqrt(0.1) * a], options={"improved_sampling": True}


˓→)

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)

times = np.linspace(0.0, 300.0, 100)


psi0 = fock(2, 1)
sm = fock(2, 0) * fock(2, 1).dag()
omega = 2.0 * np.pi * 1.0
H0 = -0.5 * omega * sigmaz()
gamma = 1/10000
data = mcsolve(
(continues on next page)

70 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[H0], psi0, times, [np.sqrt(gamma) * sm], [sm.dag() * sm], ntraj=100
)
data_imp = mcsolve(
[H0], psi0, times, [np.sqrt(gamma) * sm], [sm.dag() * sm], ntraj=100,
options={"improved_sampling": True}
)

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()

Monte Carlo: improved sampling algorithm


1.000 original
improved sampling
0.995 exp( t)

0.990

0.985
p1

0.980

0.975

0.970

0 50 100 150 200 250 300


time [ns]

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.

3.6. Time Evolution and Quantum System Dynamics 71


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Reproducibility

For reproducibility of Monte-Carlo computations it is possible to set the seed of the random number generator:

>>> res1 = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, seeds=1, ntraj=1)


>>> res2 = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, seeds=1, ntraj=1)
>>> res3 = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, seeds=2, ntraj=1)
>>> np.allclose(res1, res2)
True
>>> np.allclose(res1, res3)
False

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:

>>> res1 = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, ntraj=10)


>>> res2 = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, seeds=res1.seeds, ntraj=10)
>>> np.allclose(res1, res2)
True

Running trajectories in parallel

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.

>>> res_par = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, options={"map": "parallel"},


˓→ seeds=1)

>>> res_ser = mcsolve(H, psi0, tlist, c_ops, e_ops=e_ops, options={"map": "serial"},␣


˓→seeds=1)

>>> np.allclose(res_par.average_expect, res_ser.average_expect)


True

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,),)]

72 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

times = np.linspace(0.0, 10.0, 200)


psi0 = tensor(fock(2, 0), fock(10, 8))
a = tensor(qeye(2), destroy(10))
sm = tensor(destroy(2), qeye(10))
e_ops = [a.dag() * a, sm.dag() * sm]
H = 2*np.pi*a.dag()*a + 2*np.pi*sm.dag()*sm + 2*np.pi*0.25*(sm*a.dag() + sm.dag()*a)
data = mcsolve(H, psi0, times, [np.sqrt(0.1) * a], e_ops=e_ops)

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()

Monte Carlo Photocurrent

1.2

1.0
Photon detections

0.8

0.6

0.4

0.2

0 2 4 6 8 10
Time

3.6. Time Evolution and Quantum System Dynamics 73


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 𝑖

With the collapse probability becoming:


∑︁
tr 𝜌(𝑡)𝐶𝑛+ 𝐶𝑛 ,
(︀ )︀
𝛿𝑝 = 𝛿𝑡 (3.10)
𝑛

And a jump with the collapse operator n changing the state as:

𝜌(𝑡 + 𝛿𝑡) = 𝐶𝑛 𝜌(𝑡)𝐶𝑛+ /tr 𝐶𝑛 𝜌(𝑡)𝐶𝑛+ , (3.11)


(︀ )︀

We can redo the previous example for a situation where only half the emitted photons are detected.

times = np.linspace(0.0, 10.0, 200)


psi0 = tensor(fock(2, 0), fock(10, 8))
a = tensor(qeye(2), destroy(10))
sm = tensor(destroy(2), qeye(10))
H = 2*np.pi*a.dag()*a + 2*np.pi*sm.dag()*sm + 2*np.pi*0.25*(sm*a.dag() + sm.dag()*a)
L = liouvillian(H, [np.sqrt(0.05) * a])
data = mcsolve(L, psi0, times, [np.sqrt(0.05) * a], e_ops=[a.dag() * a, sm.dag() *␣
˓→sm])

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()

74 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Monte Carlo Photocurrent


0.7

0.6

0.5
Photon detections

0.4

0.3

0.2

0.1

0.0
0 2 4 6 8 10
Time

3.6.5 Krylov Solver

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

𝒦𝑁 = span |𝜓⟩, 𝐻|𝜓⟩, . . . , 𝐻 𝑁 −1 |𝜓⟩ , (3.12)


{︀ }︀

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

3.6. Time Evolution and Quantum System Dynamics 75


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Krylov Solver in QuTiP

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.

>>> dim = 100


>>> jx = jmat((dim - 1) / 2.0, "x")
>>> jy = jmat((dim - 1) / 2.0, "y")
>>> jz = jmat((dim - 1) / 2.0, "z")
>>> e_ops = [jx, jy, jz]
>>> H = (jz + jx) / 2
>>> psi0 = rand_ket(dim, seed=1)
>>> tlist = np.linspace(0.0, 10.0, 200)
>>> results = krylovsolve(H, psi0, tlist, krylov_dim=20, e_ops=e_ops)
>>> plt.figure()
>>> for expect in results.expect:
>>> plt.plot(tlist, expect)
>>> plt.legend(('jmat x', 'jmat y', 'jmat z'))
>>> plt.xlabel('Time')
>>> plt.ylabel('Expectation values')
>>> plt.show()

76 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

4 jmat x
jmat y
3 jmat z
2
Expectation values

1
0
1
2
3
4
0 2 4 6 8 10
Time

3.6.6 Stochastic Solver

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 ] = 𝑑𝑡.

Stochastic Schrodinger Equation

The stochastic Schrodinger equation is given by (see section 4.4, [Wis09])


∑︁ (︂ 𝑆 † 𝑆𝑛 𝑒𝑛 𝑒2
)︂ ∑︁ (︁ 𝑒𝑛 )︁
𝑛
𝑑𝜓(𝑡) = −𝑖𝐻𝜓(𝑡)𝑑𝑡 − − 𝑆𝑛 + 𝑛 𝜓(𝑡)𝑑𝑡 + 𝑆𝑛 − 𝜓(𝑡)𝑑𝑊𝑛 , (3.15)
𝑛
2 2 8 𝑛
2

where 𝐻 is the Hamiltonian, 𝑆𝑛 are the stochastic collapse operators, and 𝑒𝑛 is

𝑒𝑛 = 𝜓(𝑡)|𝑆𝑛 + 𝑆𝑛† |𝜓(𝑡) (3.16)


⟨︀ ⟩︀

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

3.6. Time Evolution and Quantum System Dynamics 77


QuTiP: Quantum Toolbox in Python, Release 5.0.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.

Stochastic Master Equation

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])

𝑑𝜌(𝑡) = −𝑖[𝐻, 𝜌(𝑡)]𝑑𝑡 + 𝐷[𝐴]𝜌(𝑡)𝑑𝑡 + ℋ[𝐴]𝜌𝑑𝑊 (𝑡) (3.19)

where
1 [︀
2𝐴𝜌𝐴† − 𝜌𝐴† 𝐴 − 𝐴† 𝐴𝜌 , (3.20)
]︀
𝐷[𝐴]𝜌 =
2
and

ℋ[𝐴]𝜌 = 𝐴𝜌(𝑡) + 𝜌(𝑡)𝐴† − tr[𝐴𝜌(𝑡) + 𝜌(𝑡)𝐴† ]. (3.21)

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)
𝑖 𝑛

The stochastic part, 𝑑2,𝑛 , is given solely by the operators 𝑆𝑛

𝑑2,𝑛 = 𝑆𝑛 𝜌(𝑡) + 𝜌(𝑡)𝑆𝑛† − tr 𝑆𝑛 𝜌(𝑡) + 𝜌(𝑡)𝑆𝑛† 𝜌(𝑡). (3.23)


(︀ )︀

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

𝐽𝑥 = ⟨𝑥⟩ + 𝑑𝑊/𝑑𝑡, (3.24)

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

(continues on next page)

78 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


# operators
a = destroy(DIM)
x = a + a.dag()
H = DELTA * a.dag() * a

rho_0 = coherent(DIM, np.sqrt(INTENSITY))


times = np.arange(0, 1, 0.0025)

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()

Stochastic Master Equation - Homodyne Detection


6 Jx
x
4

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

3.6. Time Evolution and Quantum System Dynamics 79


QuTiP: Quantum Toolbox in Python, Release 5.0.4

parallel. See the sections Changing the Number of Trajectories, Reproducibility and Running trajectories in parallel
for details.

3.6.7 Solving Problems with Time-dependent Hamiltonians

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:

H_t = QobjEvo([num(N), [create(N), lambda t: np.sin(t)], [destroy(N), lambda t: np.


˓→sin(t)]])

3. coefficent based: The product of a Qobj with a Coefficient, created by the coefficient function, result in
a QobjEvo:

coeff = coefficent(lambda t: np.sin(t))


H_t = num(N) + (destroy(N) + create(N)) * coeff

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:

result = mesolve(H_t, ...)


result = mesolve([num(N), [destroy(N) + create(N), lambda t: np.sin(t)]], ...)
result = mesolve(oper, ...)

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:

result = mesolve(H_t, ..., c_ops=[num(N), [destroy(N) + create(N), lambda t: np.


˓→sin(t)]])

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

80 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

ustate = basis(3, 0)
excited = basis(3, 1)
ground = basis(3, 2)

N = 2 # Set where to truncate Fock state for cavity


sigma_ge = tensor(qeye(N), ground * excited.dag()) # |g><e|
sigma_ue = tensor(qeye(N), ustate * excited.dag()) # |u><e|
a = tensor(destroy(N), qeye(3))
ada = tensor(num(N), qeye(3))

c_ops = [] # Build collapse operators


kappa = 1.5 # Cavity decay rate
c_ops.append(np.sqrt(kappa) * a)
gamma = 6 # Atomic decay rate
c_ops.append(np.sqrt(5*gamma/9) * sigma_ue) # Use Rb branching ratio of 5/9 e->u
c_ops.append(np.sqrt(4*gamma/9) * sigma_ge) # 4/9 e->g

t = np.linspace(-15, 15, 100) # Define time vector


psi0 = tensor(basis(N, 0), ustate) # Define initial state

state_GG = tensor(basis(N, 1), ground) # Define states onto which to project


sigma_GG = state_GG * state_GG.dag()
state_UU = tensor(basis(N, 0), ustate)
sigma_UU = state_UU * state_UU.dag()

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)

H = [H0, [H1, H1_coeff]]


output = mesolve(H, psi0, t, c_ops, [ada, sigma_UU, sigma_GG])

We can call the Monte Carlo solver in the exact same way (if using the default ntraj=500):

output = mcsolve(H, psi0, t, c_ops, [ada, sigma_UU, sigma_GG])

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

def col_coeff(t, args): # coefficient function


return np.sqrt(kappa * np.exp(-t))

N = 10 # number of basis states


a = destroy(N)
(continues on next page)

3.6. Time Evolution and Quantum System Dynamics 81


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


H = a.dag() * a # simple HO
psi0 = basis(N, 9) # initial state
c_ops = [QobjEvo([a, col_coeff])] # time-dependent collapse term
times = np.linspace(0, 10, 100)
output = mesolve(H, psi0, times, c_ops, [a.dag() * a])

Qobjevo

QobjEvo as a time dependent quantum system, as it’s main functionality create a Qobj at a time:

>>> print(H_t(np.pi / 2))


Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', isherm=True
Qobj data =
[[0. 1.]
[1. 1.]]

QobjEvo shares a lot of properties with the Qobj.

Property Attribute Description


Dimensions Q.dims Shapes the tensor structure.
Shape Q.shape Dimensions of underlying data matrix.
Type Q.type Is object of type ‘ket, ‘bra’, ‘oper’, or ‘super’?
Representation Q.superrep Representation used if type is ‘super’?
Is constant Q.isconstant Does the QobjEvo depend on 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())

L = -1j * (spre(H) - spost(H.dag()))


L += spre(c_op) * spost(c_op.dag()) - 0.5 * spre(c_op.dag() * c_op) - 0.5 * spost(c_
˓→op.dag() * c_op)

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:

>>> def H1_coeff(t, args):


>>> return args['A'] * np.exp(-(t/args['sigma'])**2)

or, new from v5, add the extra parameter directly:

82 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

>>> def H1_coeff(t, A, sigma):


>>> return A * np.exp(-(t / sigma)**2)

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:

>>> system = [sigmaz(), [sigmax(), H1_coeff]]


>>> args={'A': 9, 'sigma': 5}
>>> qevo = QobjEvo(system, args=args)

But without args, the QobjEvo creation will fail:

>>> 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.

def system(t, A, sigma):


return H0 + H1 * (A * np.exp(-(t / sigma)**2))

mesolve(system, ..., args=args)

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:

>>> new_qevo = QobjEvo(qevo, args={"A": 5, "sigma": 0.2})


>>> new_qevo(1) == qevo(1, {"A": 5, "sigma": 0.2})
True

QobjEvo created from a monolithic function can also use arguments:

3.6. Time Evolution and Quantum System Dynamics 83


QuTiP: Quantum Toolbox in Python, Release 5.0.4

def oper(t, w):


return num(N) + (destroy(N) + create(N)) * np.sin(t*w)

H_t = QobjEvo(oper, args={"w": np.pi})

When merging two or more QobjEvo, each will keep it arguments, but calling it with updated are will affect all
parts:

>>> qevo1 = QobjEvo([[sigmap(), lambda t, a: a]], args={"a": 1})


>>> qevo2 = QobjEvo([[sigmam(), lambda t, a: a]], args={"a": 2})
>>> summed_evo = qevo1 + qevo2
>>> print(summed_evo(0))
Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', isherm=False
Qobj data =
[[0. 1.]
[2. 0.]]
>>> print(summed_evo(0, a=3, b=1))
Quantum object: dims=[[2], [2]], shape=(2, 2), type='oper', isherm=True
Qobj data =
[[0. 3.]
[3. 0.]]

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.

def coeff(t, A, sigma):


return A * np.exp(-(t / sigma)**2)

H = QobjEvo([H0, [H1, coeff]], args=args)

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.

coeff = "A * exp(-(t / sigma)**2)"

H = QobjEvo([H0, [H1, coeff]], args=args)

Here is a list of defined variables:


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, np (numpy), spe (scipy.special) and
cython_special (scipy cython interface).
Array coefficients : Use the spline interpolation of an array. Useful when the coefficient is hard to define as a
function or obtained from experimental data. The times at which the array are defined must be passed as tlist:

84 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

times = np.linspace(-sigma*5, sigma*5, 500)


coeff = A * exp(-(times / sigma)**2)

H = QobjEvo([H0, [H1, coeff]], tlist=times)

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.

times = np.array([0, 0.1, 0.3, 0.6, 1.0])


coeff = times * (1.1 - times)
tlist = np.linspace(-0.1, 1.1, 25)

H = QobjEvo([qeye(1), coeff], tlist=times)


plt.plot(tlist, [H(t).norm() for t in tlist], label="CubicSpline")

H = QobjEvo([qeye(1), coeff], tlist=times, order=0)


plt.plot(tlist, [H(t).norm() for t in tlist], label="step")

H = QobjEvo([qeye(1), coeff], tlist=times, order=1)


plt.plot(tlist, [H(t).norm() for t in tlist], label="linear")

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:

3.6. Time Evolution and Quantum System Dynamics 85


QuTiP: Quantum Toolbox in Python, Release 5.0.4

N = 5
times = np.linspace(-0.1, 1.1, 13)
coeff = np.exp(-times)

c_ops = [QobjEvo([destroy(N), coeff], tlist=times)]


tlist = np.linspace(0, 1, 11)
data = mesolve(qeye(N), basis(N, N-1), tlist, c_ops=c_ops, e_ops=[num(N)]).expect[0]
plt.plot(tlist, data)

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

Different coefficient types can be mixed in a QobjEvo.


Given the multiple choices of input style, the first question that arises is which option to choose? In short, the
function based method (first option) is the most general, allowing for essentially arbitrary coefficients expressed
via user defined functions. However, by automatically compiling your system into C++ code, the second option
(string based) tends to be more efficient and run faster. Of course, for small system sizes and evolution times, the
difference will be minor. Lastly the spline method is usually as fast the string method, but it cannot be modified
once created.

86 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Working with pulses

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)

tlist = np.linspace(0, 1, 201)


H = [sigmaz(), [sigmax(), pulse]]
psi0 = basis(2,1)

data1 = sesolve(H, psi0, tlist, e_ops=num(2)).expect[0]


data2 = sesolve(H, psi0, tlist, e_ops=num(2), options={"max_step": 0.01}).expect[0]

plt.plot(tlist, data1, label="no max_step")


plt.plot(tlist, data2, label="fixed max_step")
plt.fill_between(tlist, [pulse(t) for t in tlist], color="g", alpha=0.2, label="pulse
˓→")

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

0.0 0.2 0.4 0.6 0.8 1.0

3.6. Time Evolution and Quantum System Dynamics 87


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.6.8 Solver Class Interface

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.

Reusing Hamiltonian Data

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:

times = np.linspace(0.0, 6.0, 601)


a = tensor(qeye(2), destroy(10))
sm = tensor(destroy(2), qeye(10))
e_ops = [a.dag() * a, sm.dag() * sm]
H = QobjEvo(
[a.dag()*a + sm.dag()*sm, [(sm*a.dag() + sm.dag()*a), lambda t, A: A]],
args={"A": 0.5*np.pi}
)

solver = MESolver(H, c_ops=[np.sqrt(0.1) * a], options={"atol": 1e-8})


solver.options["normalize_output"] = True
psi0 = tensor(fock(2, 0), fock(10, 5))
data1 = solver.run(psi0, times, e_ops=e_ops)
psi1 = tensor(fock(2, 0), coherent(10, 2 - 1j))
data2 = solver.run(psi1, times, e_ops=e_ops)

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()

88 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Master Equation time evolution


5 cavity photon number
atom excitation probability

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:

data1 = solver.run(psi0, times, e_ops=e_ops)


data2 = solver.run(psi0, times, e_ops=e_ops, args={"A": 0.25*np.pi})
data3 = solver.run(psi0, times, e_ops=e_ops, args={"A": 0.125*np.pi})

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()

3.6. Time Evolution and Quantum System Dynamics 89


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Master Equation time evolution


5.0 A=pi/2
A=pi/4
A=pi/8
4.5
Expectation values

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()

90 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Master Equation time evolution


5.0 c

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.

Feedback: Accessing the solver state from evolution operators

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.

def f(t, e1):


ex = (e1.real - 5)
return (ex > 0) * ex * 10

times = np.linspace(0.0, 1.0, 301)


a = tensor(qeye(2), destroy(10))
sm = tensor(destroy(2), qeye(10))
e_ops = [a.dag() * a, sm.dag() * sm]
(continues on next page)

3.6. Time Evolution and Quantum System Dynamics 91


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


psi0 = tensor(fock(2, 0), fock(10, 8))
e_ops = [a.dag() * a, sm.dag() * sm]

H = [a*a.dag(), [sm*a.dag() + sm.dag()*a, f]]


data = mesolve(H, psi0, times, c_ops=[a], e_ops=e_ops,
args={"e1": MESolver.ExpectFeedback(a.dag() * a)}
).expect

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()

Master Equation time evolution


8 cavity photon number
atom excitation probability
7
6
Expectation values

5
4
3
2
1
0
0.0 0.2 0.4 0.6 0.8 1.0
Time

92 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.6.9 Bloch-Redfield master equation

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.

Brief Derivation and Definitions

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

3.6. Time Evolution and Quantum System Dynamics 93


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 𝑛
𝛼,𝛽
}︃
∑︁ 𝛽 𝛽
+ 𝛿𝑎𝑐 𝐴𝛼 𝛼
𝑑𝑛 𝐴𝑛𝑏 𝑆𝛼𝛽 (𝜔𝑑𝑛 ) − 𝐴𝑎𝑐 𝐴𝑑𝑏 𝑆𝛼𝛽 (𝜔𝑑𝑏 ) ,
𝑛

is the Bloch-Redfield tensor.


The Bloch-Redfield master equation in the form Eq. (3.29) is suitable for numerical implementation. The input
parameters are the system Hamiltonian 𝐻, the system operators through which the environment couples to the
system 𝐴𝛼 , and the noise-power spectrum 𝑆𝛼𝛽 (𝜔) associated with each system-environment interaction term.
To simplify the numerical implementation we assume that 𝐴𝛼 are Hermitian and that cross-correlations between
different environment operators vanish, so that the final expression for the Bloch-Redfield tensor that is imple-
mented in QuTiP is
{︃
ℏ−2 ∑︁ ∑︁
𝑅𝑎𝑏𝑐𝑑 = − 𝛿𝑏𝑑 𝐴𝛼 𝛼 𝛼 𝛼
𝑎𝑛 𝐴𝑛𝑐 𝑆𝛼 (𝜔𝑐𝑛 ) − 𝐴𝑎𝑐 𝐴𝑑𝑏 𝑆𝛼 (𝜔𝑐𝑎 )
2 𝛼 𝑛
}︃
∑︁
𝛼 𝛼 𝛼 𝛼
+ 𝛿𝑎𝑐 𝐴𝑑𝑛 𝐴𝑛𝑏 𝑆𝛼 (𝜔𝑑𝑛 ) − 𝐴𝑎𝑐 𝐴𝑑𝑏 𝑆𝛼 (𝜔𝑑𝑏 ) .
𝑛

94 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Bloch-Redfield master equation in QuTiP

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

delta = 0.2 * 2*np.pi


eps0 = 1.0 * 2*np.pi
gamma1 = 0.5

H = - delta/2.0 * sigmax() - eps0/2.0 * sigmaz()

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)

R, ekets = bloch_redfield_tensor(H, a_ops=[[sigmax(), ohmic_spectrum]])

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:

delta = 0.2 * 2*np.pi


eps0 = 1.0 * 2*np.pi
gamma1 = 0.5
(continues on next page)

3.6. Time Evolution and Quantum System Dynamics 95


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

H = - delta/2.0 * sigmax() - eps0/2.0 * sigmaz()

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)

R = bloch_redfield_tensor(H, [[sigmax(), ohmic_spectrum]], fock_basis=True)

tlist = np.linspace(0, 15.0, 1000)

psi0 = rand_ket(2, seed=1)

e_ops = [sigmax(), sigmay(), sigmaz()]

expt_list = mesolve(R, psi0, tlist, e_ops=e_ops).expect

sphere = Bloch()

sphere.add_points([expt_list[0], expt_list[1], expt_list[2]])

sphere.vector_color = ['r']

sphere.add_vectors(np.array([delta, 0, eps0]) / np.sqrt(delta ** 2 + eps0 ** 2))

sphere.make_sphere()

96 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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.

output = brmesolve(H, psi0, tlist, a_ops=[[sigmax(),ohmic_spectrum]], e_ops=e_ops)

where the resulting output is an instance of the class Result.

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

output = brmesolve(H, psi0, tlist, a_ops=[[sigmax(), ohmic_spectrum]],


e_ops=e_ops, sec_cutoff=-1)

will simulate the same example as above without the secular approximation. Note that using the non-secular version
may lead to negativity issues.

3.6. Time Evolution and Quantum System Dynamics 97


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Time-dependent Bloch-Redfield Dynamics

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:

N = 10 # number of basis states to consider


a = destroy(N)
H = a.dag() * a
psi0 = basis(N, 9) # initial state
kappa = 0.2 # coupling to oscillator
a_ops = [
([a+a.dag(), f'sqrt({kappa}*exp(-t))'], '(w>=0)')
]
tlist = np.linspace(0, 10, 100)

out = brmesolve(H, psi0, tlist, a_ops, e_ops=[a.dag() * a])


actual_answer = 9.0 * np.exp(-kappa * (1.0 - np.exp(-tlist)))

plt.figure()
plt.plot(tlist, out.expect[0])
plt.plot(tlist, actual_answer)
plt.show()

98 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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()]

res_brme = brmesolve(H, psi0, times, a_ops, e_ops)


(continues on next page)

3.6. Time Evolution and Quantum System Dynamics 99


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

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.

3.6.10 Floquet Formalism

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]).

100 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Floquet theory for unitary evolution

The Schrödinger equation with a time-dependent Hamiltonian 𝐻(𝑡) is

𝜕
𝐻(𝑡)Ψ(𝑡) = 𝑖ℏ Ψ(𝑡), (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

Ψ𝛼 (𝑡) = exp(−𝑖𝜖𝛼 𝑡/ℏ)Φ𝛼 (𝑡), (3.32)

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)
𝛼 𝛼

where the coefficients 𝑐𝛼 are determined by the initial wavefunction Ψ(0) =


∑︀
𝛼 𝑐𝛼 Ψ𝛼 (0).

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

ℋ(𝑡)Φ𝛼 (𝑡) = 𝜖𝛼 Φ𝛼 (𝑡), (3.34)

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

𝑈 (𝑇 + 𝑡, 𝑡) exp(−𝑖𝜖𝛼 𝑡/ℏ)Φ𝛼 (𝑡) = exp(−𝑖𝜖𝛼 (𝑇 + 𝑡)/ℏ)Φ𝛼 (𝑇 + 𝑡),

or, since Φ𝛼 (𝑇 + 𝑡) = Φ𝛼 (𝑡),

𝑈 (𝑇 + 𝑡, 𝑡)Φ𝛼 (𝑡) = exp(−𝑖𝜖𝛼 𝑇 /ℏ)Φ𝛼 (𝑡) = 𝜂𝛼 Φ𝛼 (𝑡),

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

𝑈 (𝑡, 0)Φ𝛼 (0) = exp(−𝑖𝜖𝛼 𝑡/ℏ)Φ𝛼 (𝑡),

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 𝑡.

3.6. Time Evolution and Quantum System Dynamics 101


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Floquet formalism in QuTiP

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:

>>> delta = 0.2 * 2*np.pi


>>> eps0 = 1.0 * 2*np.pi
>>> A = 2.5 * 2*np.pi
>>> omega = 1.0 * 2*np.pi
>>> H0 = - delta/2.0 * sigmax() - eps0/2.0 * sigmaz()
>>> H1 = A/2.0 * sigmaz()
>>> args = {'w': omega}
>>> H = [H0, [H1, 'sin(w * t)']]

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:

>>> T = 2*np.pi / omega


>>> floquet_basis = FloquetBasis(H, T, args)
>>> f_energies = floquet_basis.e_quasi
>>> f_energies
array([-2.83131212, 2.83131212])
>>> f_modes_0 = floquet_basis.mode(0)
>>> f_modes_0
[Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[ 0.72964231+0.j ]
[-0.39993746+0.554682j]],
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[0.39993746+0.554682j]
[0.72964231+0.j ]]]

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).

>>> delta = 0.2 * 2 * np.pi


>>> eps0 = 0.0 * 2 * np.pi
>>> omega = 1.0 * 2 * np.pi
>>> A_vec = np.linspace(0, 10, 100) * omega
>>> T = (2 * np.pi) / omega
>>> tlist = np.linspace(0.0, 10 * T, 101)
>>> spsi0 = basis(2, 0)
>>> q_energies = np.zeros((len(A_vec), 2))
>>> H0 = delta / 2.0 * sigmaz() - eps0 / 2.0 * sigmax()
>>> args = {'w': omega}
>>> for idx, A in enumerate(A_vec):
>>> H1 = A / 2.0 * sigmax()
>>> H = [H0, [H1, lambda t, args: np.sin(args['w'] * t)]]
(continues on next page)

102 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


>>> floquet_basis = FloquetBasis(H, T, args)
>>> q_energies[idx,:] = floquet_basis.e_quasi
>>> plt.figure()
>>> plt.plot(A_vec/omega, q_energies[:,0] / delta, 'b', A_vec/omega, q_energies[:,1] /
˓→ delta, 'r')

>>> 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:

>>> f_modes_t = floquet_basis.mode(2.5)


>>> f_modes_t
[Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[-0.89630512-0.23191946j]
[ 0.37793106-0.00431336j]],
Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[-0.37793106-0.00431336j]
[-0.89630512+0.23191946j]]]

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

3.6. Time Evolution and Quantum System Dynamics 103


QuTiP: Quantum Toolbox in Python, Release 5.0.4

>>> psi0 = rand_ket(2)


>>> f_coeff = floquet_basis.to_floquet_basis(psi0)
>>> f_coeff
[(-0.645265993068382+0.7304552549315746j),
(0.15517002114250228-0.1612116102238258j)]

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

delta = 0.2 * 2*np.pi


eps0 = 1.0 * 2*np.pi
A = 0.5 * 2*np.pi
omega = 1.0 * 2*np.pi
T = (2*np.pi)/omega
tlist = np.linspace(0.0, 10 * T, 101)
psi0 = qutip.basis(2, 0)

H0 = - delta/2.0 * qutip.sigmax() - eps0/2.0 * qutip.sigmaz()


H1 = A/2.0 * qutip.sigmaz()
args = {'w': omega}
H = [H0, [H1, lambda t, w: np.sin(w * t)]]

# Create the floquet system for the time-dependent hamiltonian


floquetbasis = qutip.FloquetBasis(H, T, args)

# decompose the inital state in the floquet modes


f_coeff = floquetbasis.to_floquet_basis(psi0)

# 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)

# For reference: calculate the same thing with mesolve


p_ex_ref = qutip.mesolve(H, psi0, tlist, [], [qutip.num(2)], args).expect[0]

# plot the results


pyplot.plot(tlist, np.real(p_ex), 'ro', tlist, 1-np.real(p_ex), 'bo')
pyplot.plot(tlist, np.real(p_ex_ref), 'r', tlist, 1-np.real(p_ex_ref), 'b')
pyplot.xlabel('Time')
pyplot.ylabel('Occupation probability')
pyplot.legend(("Floquet $P_1$", "Floquet $P_0$", "Lindblad $P_1$", "Lindblad $P_0$"))
pyplot.show()

104 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Pre-computing the Floquet modes for one period

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

delta = 0.0 * 2*np.pi


eps0 = 1.0 * 2*np.pi
A = 0.25 * 2*np.pi
omega = 1.0 * 2*np.pi
T = 2*np.pi / omega
tlist = np.linspace(0.0, 10 * T, 101)
psi0 = qutip.basis(2,0)

H0 = - delta/2.0 * qutip.sigmax() - eps0/2.0 * qutip.sigmaz()


H1 = A/2.0 * qutip.sigmax()
args = {'w': omega}
H = [H0, [H1, lambda t, w: np.sin(w * t)]]

# find the floquet modes for the time-dependent hamiltonian


floquetbasis = qutip.FloquetBasis(H, T, args, precompute=tlist)

# decompose the inital state in the floquet modes


f_coeff = floquetbasis.to_floquet_basis(psi0)

# 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)

3.6. Time Evolution and Quantum System Dynamics 105


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

# For reference: calculate the same thing with mesolve


p_ex_ref = qutip.mesolve(H, psi0, tlist, [], [qutip.num(2)], args).expect[0]

# plot the results


pyplot.plot(tlist, np.real(p_ex), 'ro', tlist, 1-np.real(p_ex), 'bo')
pyplot.plot(tlist, np.real(p_ex_ref), 'r', tlist, 1-np.real(p_ex_ref), 'b')
pyplot.xlabel('Time')
pyplot.ylabel('Occupation probability')
pyplot.legend(("Floquet $P_1$", "Floquet $P_0$", "Lindblad $P_1$", "Lindblad $P_0$"))
pyplot.show()

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

output = fsesolve(H, psi0=psi0, tlist=tlist, e_ops=[qutip.num(2)], args=args)


p_ex = output.expect[0]

Floquet theory for dissipative evolution

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
𝜖𝛼 − 𝜖𝛽
∆𝛼𝛽𝑘 = + 𝑘Ω

106 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

𝛾𝛼𝛽𝑘 = 2𝜋𝐽(∆𝛼𝛽𝑘 )|𝑋𝛼𝛽𝑘 |2

The master equation is further simplified by the RWA, which makes the following matrix useful:

∑︁
𝐴𝛼𝛽 = [𝛾𝛼𝛽𝑘 + 𝑛𝑡ℎ (|∆𝛼𝛽𝑘 |)(𝛾𝛼𝛽𝑘 + 𝛾𝛼𝛽−𝑘 )
𝑘=−∞

The density matrix of the system then evolves according to:


∑︁
𝜌˙ 𝛼𝛼 (𝑡) = (𝐴𝛼𝜈 𝜌𝜈𝜈 (𝑡) − 𝐴𝜈𝛼 𝜌𝛼𝛼 (𝑡))
𝜈

1 ∑︁
𝜌˙ 𝛼𝛽 (𝑡) = − (𝐴𝜈𝛼 + 𝐴𝜈𝛽 )𝜌𝛼𝛽 (𝑡) 𝛼 ̸= 𝛽
2 𝜈

The Floquet-Markov master equation in QuTiP

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

delta = 0.0 * 2*np.pi


eps0 = 1.0 * 2*np.pi
A = 0.25 * 2*np.pi
omega = 1.0 * 2*np.pi
T = 2*np.pi / omega
tlist = np.linspace(0.0, 20 * T, 301)
psi0 = qutip.basis(2,0)
(continues on next page)

3.6. Time Evolution and Quantum System Dynamics 107


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

H0 = - delta/2.0 * qutip.sigmax() - eps0/2.0 * qutip.sigmaz()


H1 = A/2.0 * qutip.sigmax()
args = {'w': omega}
H = [H0, [H1, lambda t, w: np.sin(w * t)]]

# noise power spectrum


gamma1 = 0.1
def noise_spectrum(omega):
return (omega>0) * 0.5 * gamma1 * omega/(2*np.pi)

# solve the floquet-markov master equation


output = qutip.fmmesolve(
H, psi0, tlist, [qutip.sigmax()],
spectra_cb=[noise_spectrum], T=T,
args=args, options={"store_floquet_states": True}
)

# calculate expectation values in the computational basis


p_ex = np.zeros(tlist.shape, dtype=np.complex128)
for idx, t in enumerate(tlist):
f_coeff_t = output.floquet_states[idx]
psi_t = output.floquet_basis.from_floquet_basis(f_coeff_t, t)
# Alternatively
psi_t = output.states[idx]
p_ex[idx] = qutip.expect(qutip.num(2), psi_t)

# For reference: calculate the same thing with mesolve


output = qutip.mesolve(H, psi0, tlist,
[np.sqrt(gamma1) * qutip.sigmax()], [qutip.num(2)],
args)
p_ex_ref = output.expect[0]

# plot the results


pyplot.plot(tlist, np.real(p_ex), 'r--', tlist, 1-np.real(p_ex), 'b--')
pyplot.plot(tlist, np.real(p_ex_ref), 'r', tlist, 1-np.real(p_ex_ref), 'b')
pyplot.xlabel('Time')
pyplot.ylabel('Occupation probability')
pyplot.legend(("Floquet $P_1$", "Floquet $P_0$", "Lindblad $P_1$", "Lindblad $P_0$"))
pyplot.show()

108 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

1.0 Floquet P1
Floquet P0
Lindblad P1
0.8 Lindblad P0

Occupation probability 0.6

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:

output = fmmesolve(H, psi0, tlist, [sigmax()], e_ops=[num(2)],


spectra_cb=[noise_spectrum], T=T, args=args)
p_ex = output.expect[0]

3.6.11 Monte Carlo for Non-Markovian Dynamics

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

3.6. Time Evolution and Quantum System Dynamics 109


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

times = np.linspace(0, 1, 201)


psi0 = basis(2, 1)
a0 = destroy(2)
H = a0.dag() * a0

# 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)

# mesolve integration for comparison


d_ops = [[lindblad_dissipator(a0.dag(), a0.dag()), gamma1],
[lindblad_dissipator(a0, a0), gamma2]]
MESol = mesolve(H, psi0, times, d_ops, e_ops=[a0.dag() * a0, a0 * a0.dag()],
args={'kappa': 1.0 / 0.129, 'nth': 0.063})

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()

110 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Monte Carlo time evolution


1.0

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

3.6.12 Setting Options for the Dynamics Solvers

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.

options = {"store_states": True, "atol": 1e-12}

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)

See Integrator for a list of supported methods.


As an example, let us consider changing the integrator, turn the GUI off, and strengthen the absolute tolerance.

options = {method="bdf", "atol": 1e-10, "progress_bar": False}

To use these new settings we can use the keyword argument options in either the mesolve and mcsolve function:

>>> mesolve(H0, psi0, tlist, c_op_list, [sigmaz()], options=options)

or:

3.6. Time Evolution and Quantum System Dynamics 111


QuTiP: Quantum Toolbox in Python, Release 5.0.4

>>> MCSolver(H0, c_op_list, options=options)

3.6.13 Computing propagators

Sometime the evolution of a single state is not sufficient and the full propagator is desired. QuTiP has the
propagator function to compute them:

>>> H = sigmaz() + np.pi *sigmax()


>>> psi_t = sesolve(H, basis(2, 1), [0, 0.5, 1]).states
>>> prop = propagator(H, [0, 0.5, 1])

>>> print((psi_t[1] - prop[1] @ basis(2, 1)).norm())


2.455965272327082e-06

>>> print((psi_t[2] - prop[2] @ basis(2, 1)).norm())


2.0071900004562142e-06

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)):

>>> rho_t = mesolve(H, fock_dm(2, 1), [0, 0.5, 1], c_ops=[sigmam()]).states


>>> prop = propagator(H, [0, 0.5, 1], c_ops=[sigmam()])

>>> print((rho_t[1] - prop[1](fock_dm(2, 1))).norm())


7.23009476734681e-07

>>> print((rho_t[2] - prop[2](fock_dm(2, 1))).norm())


1.2666967766644768e-06

The propagator function is also available as a class:

>>> U = Propagator(H, c_ops=[sigmam()])

>>> state_0_5 = U(0.5)(fock_dm(2, 1))


>>> state_1 = U(1., t_start=0.5)(state_0_5)

>>> print((rho_t[1] - state_0_5).norm())


7.23009476734681e-07

>>> print((rho_t[2] - state_1).norm())


8.355518501351504e-07

The Propagator can take options and args as a solver instance.

Using a solver to compute a propagator

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:

>>> delta = 0.2 * 2*np.pi


>>> eps0 = 1.0 * 2*np.pi
>>> gamma1 = 0.5

>>> H = - delta/2.0 * sigmax() - eps0/2.0 * sigmaz()


(continues on next page)

112 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

>>> 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)

>>> prop = brmesolve(H, qeye(2), [0, 1], a_ops=[[sigmax(), ohmic_spectrum]]).final_


˓→state

3.7 Hierarchical Equations of Motion

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 )

or an under-damped Brownian motion spectral density:

𝛼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.

3.7.2 Bosonic Environments

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 )

3.7. Hierarchical Equations of Motion 113


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Describing the system and bath

First, let us construct the system Hamiltonian, 𝐻𝑠𝑦𝑠 , and the initial system state, rho0:

from qutip import basis, sigmax, sigmaz

# The system Hamiltonian:


eps = 0.5 # energy of the 2-level system
Del = 1.0 # tunnelling term
H_sys = 0.5 * eps * sigmaz() + 0.5 * Del * sigmax()

# Initial state of the system:


rho0 = basis(2,0) * basis(2,0).dag()

Now let us describe the bath properties:

# Bath properties:
gamma = 0.5 # cut off frequency
lam = 0.1 # coupling strength
T = 0.5 # temperature

# System-bath coupling operator:


Q = sigmaz()

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:

from qutip.solver.heom import DrudeLorentzBath


from qutip.solver.heom import DrudeLorentzPadeBath

# Number of expansion terms to retain:


Nk = 2

# 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.

114 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

System and bath dynamics

Now we are ready to construct a solver:

from qutip.solver.heom import HEOMSolver

max_depth = 5 # maximum hierarchy depth to retain


options = {"nsteps": 15_000}

solver = HEOMSolver(H_sys, bath, max_depth=max_depth, options=options)

and to calculate the system evolution as a function of time:

tlist = [0, 10, 20] # times to evaluate the system state at


result = solver.run(rho0, tlist)

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:

# Define the operators that measure the populations of the two


# system states:
P11p = basis(2,0) * basis(2,0).dag()
P22p = basis(2,1) * basis(2,1).dag()

# Define the operator that measures the 0, 1 element of density matrix


# (corresonding to coherence):
P12p = basis(2,0) * basis(2,1).dag()

# Run the solver:


tlist = np.linspace(0, 20, 101)
result = solver.run(rho0, tlist, e_ops={"11": P11p, "22": P22p, "12": P12p})

# Plot the results:


fig, axes = plt.subplots(1, 1, sharex=True, figsize=(8,8))
axes.plot(result.times, result.e_data["11"], 'b', linewidth=2, label="P11")
axes.plot(result.times, result.e_data["12"], 'r', linewidth=2, label="P12")
(continues on next page)

3.7. Hierarchical Equations of Motion 115


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


axes.set_xlabel(r't', fontsize=28)
axes.legend(loc=0, fontsize=12)

1.0 P11
P12

0.8

0.6

0.4

0.2

0.0

0.2

0.0 2.5 5.0 7.5 10.0 12.5 15.0 17.5 20.0


t
Steady-state

Using the same solver, we can also determine the steady state of the combined system and bath using:

steady_state, steady_ados = solver.steady_state()

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.

116 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

# Add terminator to the system Liouvillian:


delta, terminator = bath.terminator()
HL = liouvillian(H_sys) + terminator

# 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).

Matsubara expansion coefficients

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
𝑘

3.7. Hierarchical Equations of Motion 117


QuTiP: Quantum Toolbox in Python, Release 5.0.4

and the imaginary part, 𝐶𝑖𝑚𝑎𝑔 (𝑡):


{︃
𝛾 𝑘=0
𝜈𝑘,𝑖𝑚𝑎𝑔 =
0 𝑘≥1
{︃
−𝜆𝛾 𝑘=0
𝑐𝑘,𝑖𝑚𝑎𝑔 =
0 𝑘≥1

And now the same numbers calculated in Python:

# Convenience functions and parameters:

def cot(x):
return 1. / np.tan(x)

beta = 1. / T

# Number of expansion terms to calculate:


Nk = 2

# C_real expansion terms:


ck_real = [lam * gamma / np.tan(gamma / (2 * T))]
ck_real.extend([
(8 * lam * gamma * T * np.pi * k * T /
((2 * np.pi * k * T)**2 - gamma**2))
for k in range(1, Nk + 1)
])
vk_real = [gamma]
vk_real.extend([2 * np.pi * k * T for k in range(1, Nk + 1)])

# C_imag expansion terms (this is the full expansion):


ck_imag = [lam * gamma * (-1.0)]
vk_imag = [gamma]

After all that, constructing the bath is very straight forward:

from qutip.solver.heom import BosonicBath

bath = BosonicBath(Q, ck_real, vk_real, ck_imag, vk_imag)

And we’re done!


The BosonicBath can be used with the HEOMSolver in exactly the same way as the baths we constructed previ-
ously using the built-in Drude-Lorentz bath expansions.

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:

118 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

# The size of the system:


N_sys = 3

def proj(i, j):


""" A helper function for creating an interaction operator. """
return basis(N_sys, i) * basis(N_sys, j).dag()

# Construct one bath for each system state:


baths = []
for i in range(N_sys):
Q = proj(i, i)
baths.append(DrudeLorentzBath(Q, lam, gamma, T, Nk))

# Construct the system Liouvillian from the system Hamiltonian and


# bath expansion terminators:
H_sys = sum((i + 0.5) * eps * proj(i, i) for i in range(N_sys))
H_sys += sum(
(i + j + 0.5) * Del * proj(i, j)
for i in range(N_sys) for j in range(N_sys)
if i != j
)
HL = liouvillian(H_sys) + sum(bath.terminator()[1] for bath in baths)

# Construct the solver (pass a list of baths):


solver = HEOMSolver(HL, baths, max_depth=max_depth, options=options)

# Run the solver:


rho0 = basis(N_sys, 0) * basis(N_sys, 0).dag()
tlist = np.linspace(0, 5, 200)
e_ops = {
f"P{i}": proj(i, i)
for i in range(N_sys)
}
result = solver.run(rho0, tlist, e_ops=e_ops)

# 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)

3.7. Hierarchical Equations of Motion 119


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 .

120 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Describing the system and bath

First, let us construct the system Hamiltonian, 𝐻𝑠𝑦𝑠 , and the initial system state, rho0:

from qutip import basis, destroy

# The system Hamiltonian:


e1 = 1. # site energy
H_sys = e1 * destroy(2).dag() * destroy(2)

# Initial state of the system:


rho0 = basis(2,0) * basis(2,0).dag()

Now let us describe the bath properties:

# Shared bath properties:


gamma = 0.01 # coupling strength
W = 1.0 # cut-off
T = 0.025851991 # temperature
beta = 1. / T

# Chemical potentials for the two baths:


mu_L = 1.
mu_R = -1.

# System-bath coupling operator:


Q = destroy(2)

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:

from qutip.solver.heom import LorentzianBath


from qutip.solver.heom import LorentzianPadeBath

# Number of expansion terms to retain:


Nk = 2

# 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.

3.7. Hierarchical Equations of Motion 121


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

System and bath dynamics

Now we are ready to construct a solver:

from qutip.solver.heom import HEOMSolver

max_depth = 5 # maximum hierarchy depth to retain


options = {"nsteps": 15_000}
baths = [bath_L, bath_R]

solver = HEOMSolver(H_sys, baths, max_depth=max_depth, options=options)

and to calculate the system evolution as a function of time:

tlist = [0, 10, 20] # times to evaluate the system state at


result = solver.run(rho0, tlist)

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:

# Define the operators that measure the populations of the two


# system states:
P11p = basis(2,0) * basis(2,0).dag()
P22p = basis(2,1) * basis(2,1).dag()

# Run the solver:


tlist = np.linspace(0, 500, 101)
result = solver.run(rho0, tlist, e_ops={"11": P11p, "22": P22p})

# Plot the results:


fig, axes = plt.subplots(1, 1, sharex=True, figsize=(8,8))
axes.plot(result.times, result.e_data["11"], 'b', linewidth=2, label="P11")
axes.plot(result.times, result.e_data["22"], 'r', linewidth=2, label="P22")
axes.set_xlabel(r't', fontsize=28)
axes.legend(loc=0, fontsize=12)

122 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

3.7. Hierarchical Equations of Motion 123


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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”.

def exp_current(aux, exp):


""" Calculate the current for a single exponent. """
sign = 1 if exp.type == exp.types["+"] else -1
op = exp.Q if exp.type == exp.types["+"] else exp.Q.dag()
return 1j * sign * (op * aux).tr()

def heom_current(tag, ado_state):


""" Calculate the current between the system and the given bath. """
level_1_ados = [
(ado_state.extract(label), ado_state.exps(label)[0])
for label in ado_state.filter(tags=[tag])
]
return np.real(sum(exp_current(aux, exp) for aux, exp in level_1_ados))

heom_left_current = lambda t, ado_state: heom_current("L", ado_state)


heom_right_current = lambda t, ado_state: heom_current("R", ado_state)

Once we have defined functions for retrieving the currents for the baths, we can pass them to e_ops and plot the
results:

# Run the solver (returning ADO states):


tlist = np.linspace(0, 100, 201)
result = solver.run(rho0, tlist, e_ops={
"left_currents": heom_left_current,
"right_currents": heom_right_current,
})

# Plot the results:


fig, axes = plt.subplots(1, 1, sharex=True, figsize=(8,8))
axes.plot(
result.times, result.e_data["left_currents"], 'b',
linewidth=2, label=r"Bath L",
)
axes.plot(
result.times, result.e_data["right_currents"], 'r',
linewidth=2, label="Bath R",
)
axes.set_xlabel(r't', fontsize=28)
axes.set_ylabel(r'Current', fontsize=20)
axes.set_title(r'System to Bath Currents', fontsize=20)
axes.legend(loc=0, fontsize=12)

124 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

System to Bath Currents


Bath L
Bath R

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.

Steady state currents

Using the same solver, we can also determine the steady state of the combined system and bath using:

steady_state, steady_ados = solver.steady_state()

and calculate the steady state currents to the two baths from steady_ados using the same heom_current function
we defined previously:

steady_state_current_left = heom_current("L", steady_ados)


steady_state_current_right = heom_current("R", steady_ados)

Now we can add the steady state currents to the previous plot:

3.7. Hierarchical Equations of Motion 125


QuTiP: Quantum Toolbox in Python, Release 5.0.4

# Plot the results and steady state currents:


fig, axes = plt.subplots(1, 1, sharex=True, figsize=(8,8))
axes.plot(
result.times, result.e_data["left_currents"], 'b',
linewidth=2, label=r"Bath L",
)
axes.plot(
result.times, [steady_state_current_left] * len(result.times), 'b:',
linewidth=2, label=r"Bath L (steady state)",
)
axes.plot(
result.times, result.e_data["right_currents"], 'r',
linewidth=2, label="Bath R",
)
axes.plot(
result.times, [steady_state_current_right] * len(result.times), 'r:',
linewidth=2, label=r"Bath R (steady state)",
)
axes.set_xlabel(r't', fontsize=28)
axes.set_ylabel(r'Current', fontsize=20)
axes.set_title(r'System to Bath Currents (with steady states)', fontsize=20)
axes.legend(loc=0, fontsize=12)

126 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

System to Bath Currents (with steady states)


Bath L
Bath L (steady state)
Bath R
Bath R (steady state)
0.004

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!

Padé expansion coefficients

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:

𝑓𝐹 (𝑥) = (exp(𝑥) + 1)−1

3.7. Hierarchical Equations of Motion 127


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

# Convenience functions and parameters:


def deltafun(j, k):
""" Kronecker delta function. """
return 1.0 if j == k else 0.

def f_approx(x, Nk):


""" Padé approxmation to Fermi distribution. """
f = 0.5
for ll in range(1, Nk + 1):
# kappa and epsilon are calculated further down
f = f - 2 * kappa[ll] * x / (x**2 + epsilon[ll]**2)
return f

def kappa_epsilon(Nk):
""" Calculate kappa and epsilon coefficients. """

alpha = np.zeros((2 * Nk, 2 * Nk))


for j in range(2 * Nk):
for k in range(2 * Nk):
alpha[j][k] = (
(deltafun(j, k + 1) + deltafun(j, k - 1))
/ np.sqrt((2 * (j + 1) - 1) * (2 * (k + 1) - 1))
)

eps = [-2. / val for val in eigvalsh(alpha)[:Nk]]

alpha_p = np.zeros((2 * Nk - 1, 2 * Nk - 1))


for j in range(2 * Nk - 1):
(continues on next page)

128 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


for k in range(2 * Nk - 1):
alpha_p[j][k] = (
(deltafun(j, k + 1) + deltafun(j, k - 1))
/ np.sqrt((2 * (j + 1) + 1) * (2 * (k + 1) + 1))
)

chi = [-2. / val for val in eigvalsh(alpha_p)[:Nk - 1]]

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)
]

kappa = [0] + eta_list


epsilon = [0] + eps

return kappa, epsilon

kappa, epsilon = kappa_epsilon(Nk)

# Phew, we made it to function that calculates the coefficients for the


# correlation function expansions:

def C(sigma, mu, Nk):


""" Calculate the expansion coefficients for C_\sigma. """
beta = 1. / T
ck = [0.5 * gamma * W * f_approx(1.0j * beta * W, Nk)]
vk = [W - sigma * 1.0j * mu]
for ll in range(1, Nk + 1):
ck.append(
-1.0j * (kappa[ll] / beta) * gamma * W**2
/ (-(epsilon[ll]**2 / beta**2) + W**2)
)
vk.append(epsilon[ll] / beta - sigma * 1.0j * mu)
return ck, vk

ck_plus_L, vk_plus_L = C(1.0, mu_L, Nk) # C_+, left bath


ck_minus_L, vk_minus_L = C(-1.0, mu_L, Nk) # C_-, left bath

ck_plus_R, vk_plus_R = C(1.0, mu_R, Nk) # C_+, right bath


ck_minus_R, vk_minus_R = C(-1.0, mu_R, Nk) # C_-, right bath

Finally we are ready to construct the FermionicBath :

from qutip.solver.heom import FermionicBath

# 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)

And we’re done!

3.7. Hierarchical Equations of Motion 129


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

3.7.4 Previous implementations

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.

130 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.7.5 References

3.8 Solving for Steady-State Solutions

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.

3.8.2 Steady State solvers in QuTiP

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.

Method Keyword Description


Direct (default) ‘direct’ Direct solution solving 𝐴𝑥 = 𝑏.
Eigenvalue ‘eigen’ Iteratively find the zero eigenvalue of ℒ.
Inverse-Power ‘power’ Solve using the inverse-power method.
SVD ‘svd’ Steady-state solution via the dense SVD of the Liouvillian.

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: ``

Solver Original function Description


“solve” numpy.linalg.solve Dense solver from numpy.
“lstsq” numpy.linalg.lstsq Dense least-squares solver.
“spsolve” scipy.sparse.linalg. Sparse solver from scipy.
spsolve
“gmres” scipy.sparse.linalg.gmres Generalized Minimal RESidual iterative solver.
“lgmres” scipy.sparse.linalg.lgmres LGMRES iterative solver.
“bicgstab” scipy.sparse.linalg. BIConjugate Gradient STABilized iterative
bicgstab solver.
“mkl_spsolve” pardiso Intel Pardiso LU solver from MKL

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).

3.8. Solving for Steady-State Solutions 131


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.8.3 Using the Steadystate Solver

Solving for the steady state solution to the Lindblad master equation for a general system with steadystate can
be accomplished using:

>>> rho_ss = steadystate(H, c_ops)

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:

rho_ss = steadystate(H, c_ops, method="power", solver="spsolve")

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:

rho_ss = steadystate(H, c_ops, solver="spsolve", use_rcm=True)

where use_rcm=True turns on a bandwidth minimization routine.


Although it is not obvious, the 'direct', 'eigen', and 'power' methods all use an LU decomposition internally
and thus can have a large memory overhead. In contrast, iterative solvers such as the 'gmres', 'lgmres', and
'bicgstab' do not factor the matrix and thus take less memory than the LU methods and allow, in principle, for
extremely large system sizes. The downside is that these methods can take much longer than the direct method as
the condition number of the Liouvillian matrix is large, indicating that these iterative methods require a large num-
ber of iterations for convergence. To overcome this, one can use a preconditioner 𝑀 that solves for an approximate
inverse for the (modified) Liouvillian, thus better conditioning the problem, leading to faster convergence. The use
of a preconditioner can actually make these iterative methods faster than the other solution methods. The problem
with precondioning is that it is only well defined for Hermitian matrices. Since the Liouvillian is non-Hermitian,
the ability to find a good preconditioner is not guaranteed. And moreover, if a preconditioner is found, it is not
guaranteed to have a good condition number. QuTiP can make use of an incomplete LU preconditioner when
using the iterative 'gmres', 'lgmres', and 'bicgstab' solvers by setting use_precond=True. The precondi-
tioner optionally makes use of a combination of symmetric and anti-symmetric matrix permutations that attempt
to improve the preconditioning process. These features are discussed in the Additional Solver Arguments section.
Even with these state-of-the-art permutations, the generation of a successful preconditoner for non-symmetric ma-
trices is currently a trial-and-error process due to the lack of mathematical work done in this area. It is always
recommended to begin with the direct solver with no additional arguments before selecting a different method.
Finding the steady-state solution is not limited to the Lindblad form of the master equation. Any time-independent
Liouvillian constructed from a Hamiltonian and collapse operators can be used as an input:

>>> rho_ss = steadystate(L)

where L is the Louvillian. All of the additional arguments can also be used in this case.

132 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.8.4 Additional Solver Arguments

The following additional solver arguments are available for the steady-state solver:

Key- Default Description


word
weight None Set the weighting factor used in the 'direct' method.
use_precond
False Generate a preconditioner when using the 'gmres' and
'lgmres' methods.
use_rcm False Use a Reverse Cuthill-Mckee reordering to minimize the band-
width of the modified Liouvillian used in the LU decomposition.
use_wbm False Use a Weighted Bipartite Matching algorithm to attempt to make
the modified Liouvillian more diagonally dominant, and thus for
favorable for preconditioning.
power_tol 1e-12 Tolerance for the solution when using the ‘power’ method.
power_maxiter
10 Maximum number of iterations of the power method.
power_eps 1e-15 Small weight used in the “power” method.
**kwargs {} Options to pass through the linalg solvers. See the corresponding
documentation from scipy for a full list.

Further information can be found in the steadystate docstrings.

3.8.5 Example: Harmonic Oscillator in Thermal Bath

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

# find steady-state solution


final_state = qutip.steadystate(H, c_op_list)
(continues on next page)

3.8. Solving for Steady-State Solutions 133


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


# find expectation value for particle number in steady state
fexpt = qutip.expect(a.dag() * a, final_state)

tlist = np.linspace(0, 50, 100)


# monte-carlo
mcdata = qutip.mcsolve(H, psi0, tlist, c_op_list, [a.dag() * a], ntraj=100)
# master eq.
medata = qutip.mesolve(H, psi0, tlist, c_op_list, [a.dag() * a])

plt.plot(tlist, mcdata.expect[0], tlist, medata.expect[0], lw=2)


# plot steady-state expt. value as horizontal line (should be = 2)
plt.axhline(y=fexpt, color='r', lw=1.5)
plt.ylim([0, 10])
plt.xlabel('Time', fontsize=14)
plt.ylabel('Number of excitations', fontsize=14)
plt.legend(('Monte-Carlo', 'Master Equation', 'Steady State'))
plt.title(
r'Decay of Fock state $\left|10\rangle\right.$'
r' in a thermal environment with $\langle n\rangle=2$'
)
plt.show()

Decay of Fock state |10 in a thermal environment with n = 2


10
Monte-Carlo
Master Equation
Steady State
8
Number of excitations

0
0 10 20 30 40 50
Time

134 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.9 Permutational Invariance

3.9.1 Permutational Invariant Quantum Solver (PIQS)

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.

from qutip import piqs


N = 10
system = piqs.Dicke(N, emission = 1, pumping = 2)
L = system.liouvillian()
steady = steadystate(L)

For more example of use, see the “Permutational Invariant Lindblad Dynamics” section in the tutorials section of
the website, https://qutip.org/tutorials.html.

3.9. Permutational Invariance 135


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Table 2: Useful PIQS functions.


Operators Command Description
Collective spin algebra jspin(N) The collective spin algebra 𝐽𝑥 , 𝐽𝑦 , 𝐽𝑧 for 𝑁 TLSs
𝐽𝑥 , 𝐽𝑦 , 𝐽𝑧
Collective spin 𝐽𝑥 jspin(N, "x") The collective spin operator 𝐽𝑥. Requires 𝑁 number
of TLSs
Collective spin 𝐽𝑦 jspin(N, "y") The collective spin operator 𝐽𝑦 . Requires 𝑁 number
of TLSs
Collective spin 𝐽𝑧 jspin(N, "z") The collective spin operator 𝐽𝑧 . Requires 𝑁 number
of TLSs
Collective spin 𝐽+ jspin(N, "+") The collective spin operator 𝐽+ .
Collective spin 𝐽− jspin(N, "-") The collective spin operator 𝐽− .
Collective spin 𝐽𝑧 in un- jspin(N, "z", The collective spin operator 𝐽𝑧 in the uncoupled basis
coupled basis basis='uncoupled') of dimension 2𝑁 .
Dicke state |𝑗, 𝑚⟩ density dicke(N, j, m) The density matrix for the Dicke state given by |𝑗, 𝑚⟩
matrix
Excited-state density ma- excited(N) The excited state in the Dicke basis
trix in Dicke basis
Excited-state density ma- excited(N, The excited state in the uncoupled basis
trix in uncoupled basis basis="uncoupled")
Ground-state density ma- ground(N) The ground state in the Dicke basis
trix in Dicke basis
GHZ-state density matrix ghz(N) The GHZ-state density matrix in the Dicke (default)
in the Dicke basis basis for N number of TLS
Collapse operators of the Dicke.c_ops() The collapse operators for the ensemble can be called
ensemble by the c_ops method of the Dicke class.

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.

3.10 Two-time correlation functions

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

⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩ = Tr [𝐴𝑉 (𝑡 + 𝜏, 𝑡) {𝐵𝜌(𝑡)}] = Tr [𝐴𝑉 (𝑡 + 𝜏, 𝑡) {𝐵𝑉 (𝑡, 0) {𝜌(0)}}]

136 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩ = Tr [𝐴𝑉 (𝑡 + 𝜏, 𝑡) {𝐵𝜌ss }] = Tr [𝐴𝑉 (𝜏, 0) {𝐵𝜌ss }] = ⟨𝐴(𝜏 )𝐵(0)⟩ ,

which is independent of 𝑡, so that we only have one time coordinate 𝜏 .


QuTiP provides a family of functions that assists in the process of calculating two-time correlation functions. The
available functions and their usage is shown in the table below. Each of these functions can use one of the following
evolution solvers: Master-equation, Exponential series and the Monte-Carlo. The choice of solver is defined by the
optional argument solver.

QuTiP function Correlation function


qutip.correlation_2op_2t ⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩ or ⟨𝐴(𝑡)𝐵(𝑡 + 𝜏 )⟩.
qutip.correlation_2op_1t ⟨𝐴(𝜏 )𝐵(0)⟩ or ⟨𝐴(0)𝐵(𝜏 )⟩.
qutip.correlation_3op_1t ⟨𝐴(0)𝐵(𝜏 )𝐶(0)⟩.
qutip.correlation_3op_2t ⟨𝐴(𝑡)𝐵(𝑡 + 𝜏 )𝐶(𝑡)⟩.
qutip.correlation_3op ⟨𝐴(𝑡)𝐵(𝑡 + 𝜏 )𝐶(𝑡)⟩.

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.

3.10.1 Steadystate correlation function

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

corr1 = correlation_2op_1t(H, None, times, [np.sqrt(0.5) * a], x, x)


corr2 = correlation_2op_1t(H, None, times, [np.sqrt(1.0) * a], x, x)
corr3 = correlation_2op_1t(H, None, times, [np.sqrt(2.0) * a], x, x)

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()

3.10. Two-time correlation functions 137


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

3.10.2 Emission spectrum

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

N = 4 # number of cavity fock states


wc = wa = 1.0 * 2 * np.pi # cavity and atom frequency
g = 0.1 * 2 * np.pi # coupling strength
kappa = 0.75 # cavity dissipation rate
gamma = 0.25 # atom dissipation rate

# 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)

138 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous 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)

# plot the spectra


fig, ax = pyplot.subplots(1, 1)
ax.plot(wlist1 / (2 * np.pi), spec1, 'b', lw=2, label='eseries method')
ax.plot(wlist2 / (2 * np.pi), spec2, 'r--', lw=2, label='me+fft method')
ax.legend()
ax.set_xlabel('Frequency')
ax.set_ylabel('Power spectrum')
ax.set_title('Vacuum Rabi splitting')
ax.set_xlim(wlist2[0]/(2*np.pi), wlist2[-1]/(2*np.pi))
plt.show()

3.10. Two-time correlation functions 139


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Vacuum Rabi splitting


0.6 eseries method
me+fft method
0.5

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

3.10.3 Non-steadystate correlation function

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

times = np.linspace(0, 10.0, 200)


a = qutip.destroy(10)
x = a.dag() + a
H = a.dag() * a
alpha = 2.5
rho0 = qutip.coherent_dm(10, alpha)
corr = qutip.correlation_2op_2t(H, rho0, times, times, [np.sqrt(0.25) * a], x, x)

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()

140 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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).

Example: first-order optical coherence function

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()]

# start with a coherent state


rho0 = qutip.coherent_dm(N, 2.0)

# first calculate the occupation number as a function of time


(continues on next page)

3.10. Two-time correlation functions 141


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


n = qutip.mesolve(H, rho0, taus, c_ops, [a.dag() * a]).expect[0]

# calculate the correlation function G1 and normalize with n to obtain g1


G1 = qutip.correlation_2op_1t(H, rho0, taus, c_ops, a.dag(), a)
g1 = np.array(G1) / np.sqrt(n[0] * np.array(n))

plt.plot(taus, np.real(g1), 'b', lw=2)


plt.plot(taus, n, 'r', lw=2)
plt.title('Decay of a coherent state to an incoherent (thermal) state')
plt.xlabel(r'$\tau$')
plt.legend([
r'First-order coherence function $g^{(1)}(\tau)$',
r'Occupation number $n(\tau)$',
])
plt.show()

Decay of a coherent state to an incoherent (thermal) state


4 First-order coherence function g(1)( )
Occupation number n( )
3

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.

Example: second-order optical coherence function

The second-order optical coherence function, with time-delay 𝜏 , is defined as

⟨𝑎† (0)𝑎† (𝜏 )𝑎(𝜏 )𝑎(0)⟩


𝑔 (2) (𝜏 ) =
⟨𝑎† (0)𝑎(0)⟩2

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

142 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

for state in states:


rho0 = state['state']

# first calculate the occupation number as a function of time


n = qutip.mesolve(H, rho0, taus, c_ops, [a.dag() * a]).expect[0]

# calculate the correlation function G2 and normalize with n(0)n(t) to


# obtain g2
G2 = qutip.correlation_3op_1t(H, rho0, taus, c_ops, a.dag(), a.dag()*a, a)
g2 = np.array(G2) / (n[0] * np.array(n))

ax.plot(taus, np.real(g2), label=state['label'], lw=2)

ax.legend(loc=0)
ax.set_xlabel(r'$\tau$')
ax.set_ylabel(r'$g^{(2)}(\tau)$')
plt.show()

3.10. Two-time correlation functions 143


QuTiP: Quantum Toolbox in Python, Release 5.0.4

2.0 coherent state


thermal state
1.8 Fock state

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 Plotting on the Bloch Sphere

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.

3.11.2 The Bloch Class

In QuTiP, creating a Bloch sphere is accomplished by calling either:

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()

144 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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:

pnt = [1/np.sqrt(3), 1/np.sqrt(3), 1/np.sqrt(3)]


b.add_points(pnt)
b.render()

3.11. Plotting on the Bloch Sphere 145


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|0

y
x
|1

and then a single vector:

b.fig.clf()
vec = [0, 1, 0]
b.add_vectors(vec)
b.render()

146 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|0

y
x
|1

and then add another vector corresponding to the |up⟩ state:

up = qutip.basis(2, 0)
b.add_states(up)
b.render()

3.11. Plotting on the Bloch Sphere 147


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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()

pnt = [1./np.sqrt(3), 1./np.sqrt(3), 1./np.sqrt(3)]


b.add_points(pnt)
vec = [0, 1, 0]
b.add_vectors(vec)
up = qutip.basis(2, 0)
b.add_states(up)
b.render()

148 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|0

y
x
|1

where we have removed the extra show() commands.


We can also plot multiple points, vectors, and states at the same time by passing list or arrays instead of individual
elements. Before giving an example, we can use the clear() command to remove the current data from our Bloch
sphere instead of creating a new instance:

b.clear()
b.render()

3.11. Plotting on the Bloch Sphere 149


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|0

y
x
|1

Now on the same Bloch sphere, we can plot the three states associated with the x, y, and z directions:

x = (qutip.basis(2, 0) + (1+0j)*qutip.basis(2, 1)).unit()


y = (qutip.basis(2, 0) + (0+1j)*qutip.basis(2, 1)).unit()
z = (qutip.basis(2, 0) + (0+0j)*qutip.basis(2, 1)).unit()

b.add_states([x, y, z])
b.render()

150 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|0

y
x
|1

a similar method works for adding vectors:

b.clear()
vec = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
b.add_vectors(vec)
b.render()

3.11. Plotting on the Bloch Sphere 151


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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()

th = np.linspace(0, 2*np.pi, 20)


xp = np.cos(th)
yp = np.sin(th)
zp = np.zeros(20)

pnts = [xp, yp, zp]


b.add_points(pnts)
b.render()

152 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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()

3.11. Plotting on the Bloch Sphere 153


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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()

154 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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)

b.add_points([xz, yz, zz]) # no 'm'


b.render()

3.11. Plotting on the Bloch Sphere 155


QuTiP: Quantum Toolbox in Python, Release 5.0.4

|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.

3.11.3 Configuring the Bloch sphere

Bloch Class Options

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():

156 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Attribute Function Default Setting


b.axes Matplotlib axes instance for animations. Set by None
axes keyword arg.
b.fig User supplied Matplotlib Figure instance. Set by None
fig keyword arg.
b.font_color Color of fonts ‘black’
b.font_size Size of fonts 20
b.frame_alpha Transparency of wireframe 0.1
b.frame_color Color of wireframe ‘gray’
b.frame_width Width of wireframe 1
b.point_color List of colors for Bloch point markers to cycle ['b', 'r', 'g', '#CC6600']
through
b.point_marker List of point marker shapes to cycle through ['o', 's', 'd', '^']
b.point_size List of point marker sizes (not all markers look the [55, 62, 65, 75]
same size when plotted)
b.sphere_alpha Transparency of Bloch sphere 0.2
b.sphere_color Color of Bloch sphere '#FFDDDD'
b.size Sets size of figure window [7, 7] (700x700 pixels)
b.vector_color List of colors for Bloch vectors to cycle through ['g', '#CC6600', 'b', 'r']
b.vector_width Width of Bloch vectors 4
b.view Azimuthal and Elevation viewing angles [-60,30]
b.xlabel Labels for x-axis ['$x$', ''] +x and -x (labels use LaTeX)
b.xlpos Position of x-axis labels [1.1, -1.1]
b.ylabel Labels for y-axis ['$y$', ''] +y and -y (labels use LaTeX)
b.ylpos Position of y-axis labels [1.2, -1.2]
b.zlabel Labels for z-axis ['$\left|0\right>$', '$\left|1\
right>$'] +z and -z (labels use LaTeX)
b.zlpos Position of z-axis labels [1.2, -1.2]

These properties can also be accessed via the print command:

>>> b = qutip.Bloch()

>>> print(b)
Bloch data:
-----------
Number of points: 0
Number of vectors: 0

Bloch sphere properties:


------------------------
font_color: black
font_size: 20
frame_alpha: 0.2
frame_color: gray
frame_width: 1
point_color: ['b', 'r', 'g', '#CC6600']
point_marker: ['o', 's', 'd', '^']
point_size: [25, 32, 35, 45]
sphere_alpha: 0.2
sphere_color: #FFDDDD
figsize: [5, 5]
vector_color: ['g', '#CC6600', 'b', 'r']
vector_width: 3
vector_style: -|>
vector_mutation: 20
(continues on next page)

3.11. Plotting on the Bloch Sphere 157


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


view: [-60, 30]
xlabel: ['$x$', '']
xlpos: [1.2, -1.2]
ylabel: ['$y$', '']
ylpos: [1.2, -1.2]
zlabel: ['$\\left|0\\right>$', '$\\left|1\\right>$']
zlpos: [1.2, -1.2]

3.11.4 Animating with the Bloch sphere

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.

Example: Qubit Decay

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

def qubit_integrate(w, theta, gamma1, gamma2, psi0, tlist):


# operators and the hamiltonian
sx = qutip.sigmax()
sy = qutip.sigmay()
sz = qutip.sigmaz()
sm = qutip.sigmam()
H = w * (np.cos(theta) * sz + np.sin(theta) * sx)
# collapse operators
c_op_list = []
n_th = 0.5 # temperature
rate = gamma1 * (n_th + 1)
if rate > 0.0: c_op_list.append(np.sqrt(rate) * sm)
rate = gamma1 * n_th
if rate > 0.0: c_op_list.append(np.sqrt(rate) * sm.dag())
rate = gamma2
if rate > 0.0: c_op_list.append(np.sqrt(rate) * sz)
# evolve and calculate expectation values
output = qutip.mesolve(H, psi0, tlist, c_op_list, [sx, sy, sz])
return output.expect[0], output.expect[1], output.expect[2]

## calculate the dynamics


w = 1.0 * 2 * np.pi # qubit angular frequency
theta = 0.2 * np.pi # qubit angle from sigma_z axis (toward sigma_x axis)
gamma1 = 0.5 # qubit relaxation rate
gamma2 = 0.2 # qubit dephasing rate
# initial state
a = 1.0
psi0 = (a*qutip.basis(2, 0) + (1-a)*qutip.basis(2, 1))/np.sqrt(a**2 + (1-a)**2)
tlist = np.linspace(0, 4, 250)
(continues on next page)

158 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


#expectation values for ploting
sx, sy, sz = qubit_integrate(w, theta, gamma1, gamma2, psi0, tlist)

Generating Images for Animation

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

Generating an animation using FFmpeg (for example) is fairly simple:

ffmpeg -i temp/bloch_%01d.png bloch.mp4

Directly Generating an Animation

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

from matplotlib import pyplot, animation

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 = animation.FuncAnimation(fig, animate, np.arange(len(sx)), blit=False,␣


˓→repeat=False)

ani.save('bloch_sphere.mp4', fps=20)

The resulting movie may be viewed here: bloch_decay.mp4

3.11. Plotting on the Bloch Sphere 159


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.12 Visualization of quantum states and processes

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.

3.12.1 Fock-basis probability distribution

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_coherent = coherent_dm(N, np.sqrt(2))

rho_thermal = thermal_dm(N, 2)

rho_fock = fock_dm(N, 2)

Next, we plot histograms of the diagonals of the density matrices:

fig, axes = plt.subplots(1, 3, figsize=(12,3))

bar0 = axes[0].bar(np.arange(0, N)-.5, rho_coherent.diag())

lbl0 = axes[0].set_title("Coherent state")

lim0 = axes[0].set_xlim([-.5, N])

bar1 = axes[1].bar(np.arange(0, N)-.5, rho_thermal.diag())

lbl1 = axes[1].set_title("Thermal state")

lim1 = axes[1].set_xlim([-.5, N])

bar2 = axes[2].bar(np.arange(0, N)-.5, rho_fock.diag())

lbl2 = axes[2].set_title("Fock state")

lim2 = axes[2].set_xlim([-.5, N])

plt.show()

160 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Coherent state Thermal state Fock state


0.35 1.0
0.25 0.30
0.25 0.8
0.20
0.15 0.20 0.6
0.15 0.4
0.10
0.10
0.05 0.05 0.2
0.00 0.00 0.0
0 5 10 15 20 0 5 10 15 20 0 5 10 15 20

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, axes = plt.subplots(1, 3, figsize=(12,3))

fig, axes[0] = plot_fock_distribution(rho_coherent, fig=fig, ax=axes[0]);


axes[0].set_title('Coherent state')

fig, axes[1] = plot_fock_distribution(rho_thermal, fig=fig, ax=axes[1]);


axes[1].set_title('Thermal state')

fig, axes[2] = plot_fock_distribution(rho_fock, fig=fig, ax=axes[2]);


axes[2].set_title('Fock state')

fig.tight_layout()

plt.show()

Coherent state Thermal state Fock state


1.0 1.0 1.0
Occupation probability

Occupation probability

Occupation probability

0.8 0.8 0.8


0.6 0.6 0.6
0.4 0.4 0.4
0.2 0.2 0.2
0.0 0.0 0.0
0 5 10 15 20 0 5 10 15 20 0 5 10 15 20
Fock number Fock number Fock number

3.12.2 Quasi-probability distributions

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.

3.12. Visualization of quantum states and processes 161


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

W_coherent = wigner(rho_coherent, xvec, xvec)

W_thermal = wigner(rho_thermal, xvec, xvec)

W_fock = wigner(rho_fock, xvec, xvec)

# plot the results

fig, axes = plt.subplots(1, 3, figsize=(12,3))

cont0 = axes[0].contourf(xvec, xvec, W_coherent, 100)

lbl0 = axes[0].set_title("Coherent state")

cont1 = axes[1].contourf(xvec, xvec, W_thermal, 100)

lbl1 = axes[1].set_title("Thermal state")

cont0 = axes[2].contourf(xvec, xvec, W_fock, 100)

lbl2 = axes[2].set_title("Fock state")

plt.show()

Coherent state Thermal state Fock state


4 4 4

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

Custom Color Maps

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:

import matplotlib as mpl

from matplotlib import cm


(continues on next page)

162 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)

psi = (basis(10, 0) + basis(10, 3) + basis(10, 9)).unit()

xvec = np.linspace(-5, 5, 500)

W = wigner(psi, xvec, xvec)

wmap = wigner_cmap(W) # Generate Wigner colormap

nrm = mpl.colors.Normalize(-W.max(), W.max())

fig, axes = plt.subplots(1, 2, figsize=(10, 4))

plt1 = axes[0].contourf(xvec, xvec, W, 100, cmap=cm.RdBu, norm=nrm)

axes[0].set_title("Standard Colormap");

cb1 = fig.colorbar(plt1, ax=axes[0])

plt2 = axes[1].contourf(xvec, xvec, W, 100, cmap=wmap) # Apply Wigner colormap

axes[1].set_title("Wigner Colormap");

cb2 = fig.colorbar(plt2, ax=axes[1])

fig.tight_layout()

plt.show()

Standard Colormap Wigner Colormap


0.180 0.180
4 4
0.144 0.144
0.108 0.108
2 2
0.072 0.072
0.036 0.036
0 0
0.000 0.000
0.036 0.036
2 2
0.072 0.072
0.108 0.108
4 4
0.144 0.144
4 2 0 2 4 4 2 0 2 4

3.12. Visualization of quantum states and processes 163


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Q_coherent = qfunc(rho_coherent, xvec, xvec)


Q_thermal = qfunc(rho_thermal, xvec, xvec)
Q_fock = qfunc(rho_fock, xvec, xvec)
fig, axes = plt.subplots(1, 3, figsize=(12,3))
cont0 = axes[0].contourf(xvec, xvec, Q_coherent, 100)
lbl0 = axes[0].set_title("Coherent state")
cont1 = axes[1].contourf(xvec, xvec, Q_thermal, 100)
lbl1 = axes[1].set_title("Thermal state")
cont0 = axes[2].contourf(xvec, xvec, Q_fock, 100)
lbl2 = axes[2].set_title("Fock state")
plt.show()

Coherent state Thermal state Fock state


4 4 4

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))

3.12.3 Visualizing operators

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:

164 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

N = 5

a = tensor(destroy(N), qeye(2))

b = tensor(qeye(N), destroy(2))

sx = tensor(qeye(N), sigmax())

H = a.dag() * a + sx - 0.5 * (a * b.dag() + a.dag() * b)

# visualize H

lbls_list = [[str(d) for d in range(N)], ["u", "d"]]

xlabels = []

for inds in tomography._index_permutations([len(lbls) for lbls in lbls_list]):


xlabels.append("".join([lbls_list[k][inds[k]] for k in range(len(lbls_list))]))

fig, ax = matrix_histogram(H, xlabels, xlabels, limits=[-4,4])

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:

3.12. Visualization of quantum states and processes 165


QuTiP: Quantum Toolbox in Python, Release 5.0.4

rho_ss = steadystate(H, [np.sqrt(0.1) * a, np.sqrt(0.4) * b.dag()])

hinton(rho_ss)

plt.show()

0, 0|0, 1|1, 0|1, 1|2, 0|2, 1|3, 0|3, 1|4, 0|4, 1|


|0, 0
|0, 1 0.3
|1, 0 0.2
|1, 1 0.1
|2, 0 0.0
|2, 1
0.1
|3, 0
0.2
|3, 1
|4, 0 0.3
|4, 1

3.12.4 Quantum process tomography

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

166 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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
∑︀ ∑︀

it describes how much 𝐵𝑚 𝜌in 𝐵𝑛† contributes to 𝜌out .


In a numerical simulation of a quantum process we usually do not have access to the quantum map in the form Eq.
(3.42). Instead, what we usually can do is to calculate the propagator 𝑈 for the density matrix in superoperator
form, using for example the QuTiP function qutip.propagator.propagator. We can then write

𝜖(˜
𝜌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
𝑁
∑︁
𝑈𝐼 = 𝑀𝐼𝐽 𝜒𝐽
𝐽

with the solution

𝜒 = 𝑀 −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:

from qutip.core.gates import swap

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:

U_rho = spre(U_psi) * spost(U_psi.dag())

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.

3.12. Visualization of quantum states and processes 167


QuTiP: Quantum Toolbox in Python, Release 5.0.4

op_basis = [[qeye(2), sigmax(), sigmay(), sigmaz()]] * 2


op_label = [["i", "x", "y", "z"]] * 2

We are now ready to compute 𝜒 using qutip.tomography.qpt, and to plot it using qutip.tomography.
qpt_plot_combined.

chi = qpt(U_rho, op_basis)

fig = qpt_plot_combined(chi, op_label, r'SWAP')

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.

168 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.13 Saving QuTiP Objects and Data Sets

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).

3.13.1 Storing and loading QuTiP objects

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

>>> a = destroy(10); H = a.dag() * a


>>> c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
>>> rho_ss = steadystate(H, c_ops)

The steadystate density matrix rho_ss is an instance of Qobj. It can be stored to a file steadystate.qu using

>>> qsave(rho_ss, 'steadystate')


>>> !ls *.qu
density_matrix_vs_time.qu steadystate.qu

and it can later be loaded again, and used in further calculations

>>> rho_ss_loaded = qload('steadystate')


Loaded Qobj object:
Quantum object: dims = [[10], [10]], shape = (10, 10), type = oper, isHerm = True
>>> a = destroy(10)
>>> np.testing.assert_almost_equal(expect(a.dag() * a, rho_ss_loaded), 0.
˓→9902248289345061)

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

>>> a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.


˓→dag()]

>>> psi0 = rand_ket(10)


>>> times = np.linspace(0, 10, 10)
>>> dm_list = mesolve(H, psi0, times, c_ops, [])
>>> qsave(dm_list, 'density_matrix_vs_time')

And it can then be loaded and used again, for example in an other program

>>> dm_list_loaded = qload('density_matrix_vs_time')


Loaded Result object:
Result object with mesolve data.
--------------------------------
states = True
num_collapse = 0
(continues on next page)

3.13. Saving QuTiP Objects and Data Sets 169


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


>>> a = destroy(10)
>>> expect(a.dag() * a, dm_list_loaded.states)
array([4.63317086, 3.59150315, 2.90590183, 2.41306641, 2.05120716,
1.78312503, 1.58357995, 1.4346382 , 1.32327398, 1.23991233])

3.13.2 Storing and loading datasets

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:

>>> file_data_store(filename, data, numtype="complex", numformat="decimal", sep=",")

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

>>> a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.


˓→dag()]

>>> psi0 = rand_ket(10)


>>> times = np.linspace(0, 100, 100)
>>> medata = mesolve(H, psi0, times, c_ops, [a.dag() * a, a + a.dag(), -1j * (a - a.
˓→dag())])

>>> 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

(continues on next page)

170 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


7.0707070707+0.0000000000j,1.3321818015+0.0000000000j,0.0950352763+0.0000000000j,-0.
˓→1630920429+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

>>> file_data_store('expect.dat', output_data.T, numtype="real")


>>> with open("expect.dat", "r") as f:
... print('\n'.join(f.readlines()[:5]))
# Generated by QuTiP: 100x4 real matrix in decimal format [',' separated values].
0.0000000000,3.2109553666,0.3689771549,0.0185002867
1.0101010101,2.6754598872,0.1298251132,-0.3303672956
2.0202020202,2.2743186810,-0.2106241300,-0.2623894277
3.0303030303,1.9726633457,-0.3037311621,0.0397330921

and if we prefer scientific notation we can request that using the numformat="exp" option

>>> file_data_store('expect.dat', output_data.T, numtype="real", numformat="exp")

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

3.13. Saving QuTiP Objects and Data Sets 171


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(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).

3.14 Generating Random Quantum States & Operators

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 ]]

Random Sampling Func- Dimensions


Variable tions
Type
State vector rand_ket 𝑁 ×1
(ket)
Hermitian op- rand_herm 𝑁 ×𝑁
erator (oper)
Density oper- rand_dm 𝑁 ×𝑁
ator (oper)
Unitary oper- rand_unitary 𝑁 ×𝑁
ator (oper)
stochastic ma- rand_stochastic 𝑁 ×𝑁
trix (oper)
CPTP channel rand_super, (𝑁 × 𝑁 ) × (𝑁 × 𝑁 )
(super) rand_super_bcsz
CPTP map rand_kraus_map 𝑁 × 𝑁 (N**2 operators)
(list of oper)

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

172 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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,

>>> rand_dm(5, density=0.5, distribution="herm")


Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[ 0.298+0.j , 0. +0.j , -0.095+0.1j , 0. +0.j ,-0.105+0.122j],
[ 0. +0.j , 0.088+0.j , 0. +0.j , -0.018-0.001j, 0. +0.j ],
[-0.095-0.1j , 0. +0.j , 0.328+0.j , 0. +0.j ,-0.077-0.033j],
[ 0. +0.j , -0.018+0.001j, 0. +0.j , 0.084+0.j , 0. +0.j ],
[-0.105-0.122j, 0. +0.j , -0.077+0.033j, 0. +0.j , 0.201+0.j ]]

>>> rand_dm_ginibre(5, rank=2)


Quantum object: dims = [[5], [5]], shape = (5, 5), type = oper, isherm = True
Qobj data =
[[ 0.307+0.j , -0.258+0.039j, -0.039+0.184j, 0.041-0.054j, 0.016+0.045j],
[-0.258-0.039j, 0.239+0.j , 0.075-0.15j , -0.053+0.008j,-0.057-0.078j],
[-0.039-0.184j, 0.075+0.15j , 0.136+0.j , -0.05 -0.052j,-0.028-0.058j],
[ 0.041+0.054j, -0.053-0.008j, -0.05 +0.052j, 0.083+0.j , 0.101-0.056j],
[ 0.016-0.045j, -0.057+0.078j, -0.028+0.058j, 0.101+0.056j, 0.236+0.j ]]

See the API documentation: Quantum Objects for details.

Warning: When using the density keyword argument, setting the density too low may result in not enough
diagonal elements to satisfy trace constraints.

3.14.1 Random objects with a given eigen spectrum

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,

>>> eigs = np.arange(5)

>>> H = rand_herm(5, density=0.5, eigenvalues=eigs, distribution="eigen")

>>> 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.

3.14. Generating Random Quantum States & Operators 173


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.14.2 Composite random objects

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]:

>>> rand_unitary([2, 2], density=0.5)


Quantum object: dims = [[2, 2], [2, 2]], shape = (4, 4), type = oper, isherm = True
Qobj data =
[[ 0.887+0.061j, 0. +0.j , 0. +0.j , -0.191-0.416j],
[ 0. +0.j , 0.604+0.116j, -0.32 -0.721j, 0. +0.j ],
[ 0. +0.j , 0.768+0.178j, 0.227+0.572j, 0. +0.j ],
[ 0.412-0.2j , 0. +0.j , 0. +0.j , 0.724+0.516j]]

3.14.3 Controlling the random number generator

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:

>>> rng = np.random.default_rng(12345)


>>> rand_ket(2, seed=rng)
Quantum object: dims=[[2], [1]], shape=(2, 1), type='ket'
Qobj data =
[[-0.697+0.618j],
[-0.326-0.163j]]

3.14.4 Internal matrix format

The internal storage type of the generated random quantum objects can be set with the dtype keyword.

>>> rand_ket(2, dtype="dense").data


Dense(shape=(2, 1), fortran=True)

>>> rand_ket(2, dtype="CSR").data


CSR(shape=(2, 1), nnz=2)

3.15 Modifying Internal QuTiP Settings

3.15.1 User Accessible Parameters

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:

174 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Setting Description Options


auto_tidyup Automatically tidyup sparse quan- True / False
tum objects.
auto_tidyup_atol Tolerance used by tidyup. (sparse float {1e-14}
only)
atol General absolute tolerance. float {1e-12}
rtol General relative tolerance. float {1e-12}
func- Signature expected by function co- {“auto”, “pythonic”, “dict”}
tion_coefficient_style efficients.

3.15.2 Example: Changing Settings

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:

>>> qutip.settings.core["auto_tidyup"] = False

The settings can also be changed for a code block:

>>> with qutip.CoreOptions(atol=1e-5):


>>> assert qutip.qeye(2) * 1e-9 == qutip.qzero(2)

3.16 Measurement of Quantum Objects

Note: New in QuTiP 4.6

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.

3.16.2 Performing a basic measurement (Observable)

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:

3.16. Measurement of Quantum Objects 175


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

from qutip.measurement import measure, measurement_statistics

measure(up, spin_z) == (1.0, up)

measure(down, spin_z) == (-1.0, down)

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:

left = (up - down).unit()

right = (up + down).unit()

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.

176 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.16.3 Performing a basic measurement (Projective)

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.

Z0, Z1 = ket2dm(basis(2, 0)), ket2dm(basis(2, 1))

The probabilities and respective output state are calculated for each projection operator.

measure(up, [Z0, Z1]) == (0, up)

measure(down, [Z0, Z1]) == (1, down)

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)

state_plus = (basis(2, 0) + basis(2, 1)).unit()

state_0plus = tensor(state_0, state_plus)

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| ⊗ 𝐼.

PZ1 = [tensor(Z0, identity(2)), tensor(Z1, identity(2))]

PZ2 = [tensor(identity(2), Z0), tensor(identity(2), Z1)]

Now, as in the previous example, we can measure by supplying a list of projection operators and the state.

measure(state_0plus, PZ1) == (0, state_0plus)

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!

3.16. Measurement of Quantum Objects 177


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.16.4 Obtaining measurement statistics(Observable)

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:

results = {1.0: 0, -1.0: 0} # 1 and -1 are the possible outcomes


for _ in range(1000):
value, new_state = measure(up, spin_x)
results[round(value)] += 1
print(results)

Output:

{1.0: 497, -1.0: 503}

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, eigenstates, probabilities = measurement_statistics(up, spin_x)

>>> 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

178 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

alias to measurement_statistics_observable.

3.16.5 Obtaining measurement statistics(Projective)

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.

collapsed_states, probabilities = measurement_statistics(state_0plus, PZ2)

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]

The function measurement_statistics then returns two values:


• collapsed_states is an array 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 outcome.
Note that the collapsed_states are exactly |00⟩ and |01⟩ with equal probability, as expected. The two lists are in the
same order.

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.16. Measurement of Quantum Objects 179


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.17 Quantum Optimal Control

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.

Fig. 3: Schematic showing the principle of quantum control.

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.

3.17.2 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.
𝑑
𝑑𝑡 |𝜓⟩ = −𝑖𝐻(𝑡) |𝜓⟩

180 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Note we use units where ℏ = 1 throughout. The solutions to Schrödinger’s equation are of the form:

|𝜓(𝑡)⟩ = 𝑈 (𝑡) |𝜓0 ⟩

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.

3.17.3 The GRAPE algorithm

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

3.17. Quantum Optimal Control 181


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

3.17.4 The CRAB Algorithm

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.

182 Chapter 3. Users Guide


QuTiP: Quantum Toolbox in Python, Release 5.0.4

3.17.5 Optimal Quantum Control in QuTiP

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.

3.17. Quantum Optimal Control 183


QuTiP: Quantum Toolbox in Python, Release 5.0.4

184 Chapter 3. Users Guide


Chapter 4

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

186 Chapter 4. Gallery


Chapter 5

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

class Qobj(arg=None, dims=None, copy=True, superrep=None, isherm=None, isunitary=None)


A class for representing quantum objects, such as quantum operators and states.
The Qobj class is the QuTiP representation of quantum operators and state vectors. This class also im-
plements math operations +,-,* between Qobj instances (and / by a C-number), as well as a collection of
common operator/state operations. The Qobj constructor optionally takes a dimension list and/or shape
list as arguments.
Parameters
inpt: array_like, data object or :obj:`.Qobj`
Data for vector/matrix representation of the quantum object.
dims: list
Dimensions of object used for tensor products.
shape: list
Shape of underlying data structure (matrix shape).
copy: bool
Flag specifying whether Qobj should get a copy of the input data, or use the original.
Attributes
data
[object] The data object storing the vector / matrix representation of the Qobj.
dtype
[type] The data-layer type used for storing the data. The possible types are described in
Qobj.to.
dims
[list] List of dimensions keeping track of the tensor structure.
shape
[list] Return the shape of the Qobj data.
type
[str] Type of quantum object: ‘bra’, ‘ket’, ‘oper’, ‘operator-ket’, ‘operator-bra’, or ‘super’.

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

copy() Create copy of Qobj


conj() Conjugate of quantum object.
contract() Contract subspaces of the tensor structure which
cosm() Cosine of quantum object.
dag() Adjoint (dagger) of quantum object.
data_as(format, copy) Vector / matrix representation of quantum object.
diag() Diagonal elements of quantum object.
dnorm() Diamond norm of quantum operator.
dual_chan() Dual channel of quantum object representing a C
eigenenergies(sparse=False, sort=’low’, eigvals=0, tol=0, maxiter=100000) Returns eigenenergies (eigenvalues) of a quantum
eigenstates(sparse=False, sort=’low’, eigvals=0, tol=0, maxiter=100000) Returns eigenenergies and eigenstates of quantum
expm() Matrix exponential of quantum object.
full(order=’C’) Returns dense array of quantum object data attrib
groundstate(sparse=False, tol=0, maxiter=100000) Returns eigenvalue and eigenket for the groundsta
inv() Return a Qobj corresponding to the matrix invers

188 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Table 1 – continued from previous page


logm() Matrix logarithm of quantum operator.
matrix_element(bra, ket) Returns the matrix element of operator between b
norm(norm=’tr’, sparse=False, tol=0, maxiter=100000) Returns norm of a ket or an operator.
overlap(other) Overlap between two state vectors or two operato
permute(order) Returns composite qobj with indices reordered.
proj() Computes the projector for a ket or bra vector.
ptrace(sel) Returns quantum object for selected dimensions a
purity() Calculates the purity of a quantum object.
sinm() Sine of quantum object.
sqrtm() Matrix square root of quantum object.
tidyup(atol=1e-12) Removes small elements from quantum object.
tr() Trace of quantum object.
trans() Transpose of quantum object.
transform(inpt, inverse=False) Performs a basis transformation defined by inpt m
trunc_neg(method=’clip’) Removes negative eigenvalues and returns a new
unit(norm=’tr’, sparse=False, tol=0, maxiter=100000) Returns normalized quantum object.

__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

5.1. Classes 189


QuTiP: Quantum Toolbox in Python, Release 5.0.4

TypeError
Quantum object is not square.

Notes

Uses the Q.expm() method.


dag()
Get the Hermitian adjoint of the quantum object.
data_as(format=None, copy=True)
Matrix from quantum object.
Parameters
format
[str, default: None] Type of the output, “ndarray” for Dense, “csr_matrix” for CSR. A
ValueError will be raised if the format is not supported.
copy
[bool {False, True}] Whether to return a copy
Returns
data
[numpy.ndarray, scipy.sparse.matrix_csr, etc.] Matrix in the type of the underlying
libraries.
diag()
Diagonal elements of quantum object.
Returns
diags
[array] Returns array of real values if operators is Hermitian, otherwise complex
values are returned.
dnorm(B=None)
Calculates the diamond norm, or the diamond distance to another operator.
Parameters
B
[Qobj or None] If B is not None, the diamond distance d(A, B) = dnorm(A - B) between
this operator and B is returned instead of the diamond norm.
Returns
d
[float] Either the diamond norm of this operator, or the diamond distance from this
operator to B.
dual_chan()
Dual channel of quantum object representing a completely positive map.
eigenenergies(sparse=False, sort='low', eigvals=0, tol=0, maxiter=100000)
Eigenenergies of a quantum object.
Eigenenergies (eigenvalues) are defined for operators or superoperators only.
Parameters
sparse
[bool] Use sparse Eigensolver
sort
[str] Sort eigenvalues ‘low’ to high, or ‘high’ to low.

190 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 191


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

192 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 193


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

194 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 195


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Uses the Q.expm() method.


sqrtm(sparse=False, tol=0, maxiter=100000)
Sqrt of a quantum operator. Operator must be square.
Parameters
sparse
[bool] Use sparse eigenvalue/vector solver.
tol
[float] Tolerance used by sparse solver (0 = machine precision).
maxiter
[int] Maximum number of iterations used by sparse solver.
Returns
oper
[Qobj] Matrix square root of operator.
Raises
TypeError
Quantum object is not square.

196 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 197


QuTiP: Quantum Toolbox in Python, Release 5.0.4

inverse
[bool] Whether to return inverse transformation.
Returns
oper
[Qobj] Operator in new basis.

Notes

This function is still in development.


trunc_neg(method='clip')
Truncates negative eigenvalues and renormalizes.
Returns a new Qobj by removing the negative eigenvalues of this instance, then renormalizing to obtain
a valid density operator.
Parameters
method
[str] Algorithm to use to remove negative eigenvalues. “clip” simply discards negative
eigenvalues, then renormalizes. “sgs” uses the SGS algorithm (doi:10/bb76) to find
the positive operator that is nearest in the Shatten 2-norm.
Returns
oper
[Qobj] A valid density operator.
unit(inplace=False, norm=None, kwargs=None)
Operator or state normalized to unity. Uses norm from Qobj.norm().
Parameters
inplace
[bool] Do an in-place normalization
norm
[str] Requested norm for states / operators.
kwargs
[dict] Additional key-word arguments to be passed on to the relevant norm function
(see norm for more details).
Returns
obj
[Qobj] Normalized quantum object. Will be the self object if in place.

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).

198 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• a Qobj (which creates a constant QobjEvo term).


• a list of such callables, pairs or Qobjs.
• a QobjEvo (in which case a copy is created, all other arguments are ignored except args which, if
passed, replaces the existing arguments).

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

5.1. Classes 199


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Examples

A QobjEvo constructed from a function:

def f(t, args):


return qutip.qeye(N) * np.exp(args['w'] * t)

QobjEvo(f, args={'w': 1j})

For list based QobjEvo, the list must consist of Qobj or [Qobj, Coefficient] pairs:

QobjEvo([H0, [H1, coeff1], [H2, coeff2]], args=args)

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:

def f1_t(t, args):


return np.exp(-1j * t * args["w1"])

QobjEvo([[H1, f1_t]], args={"w1": 1.})

And of coefficients specified by string expressions:

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:

tlist = np.logspace(-5, 0, 100)


H = QobjEvo(
[H0, [H1, np.exp(-1j * tlist)], [H2, np.cos(2. * tlist)]],
tlist=tlist
)

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:

coeff = qutip.coefficient("exp(-1j*w1*t)", args={"w1": 1})


qevo = H0 + H1 * coeff

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).

200 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

__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.

5.1. Classes 201


QuTiP: Quantum Toolbox in Python, Release 5.0.4

expect(t, state, check_real=True)


Expectation value of this operator at time t with the state.
Parameters
t
[float] Time of the operator to apply.
state
[Qobj] right matrix of the product
check_real
[bool (True)] Whether to convert the result to a real when the imaginary part is smaller
than the real part by a dactor of settings.core['rtol'].
Returns
expect
[float or complex] state.adjoint() @ self @ state if state is a ket.
trace(self @ matrix) is state is an operator or operator-ket.
expect_data(t, state)
Expectation is defined as state.adjoint() @ self @ state if state is a vector, or state is an
operator and self is a superoperator. If state is an operator and self is an operator, then expectation
is trace(self @ matrix).
isbra
Indicates if the system represents a bra state.
isconstant
Does the system change depending on t
isket
Indicates if the system represents a ket state.
isoper
Indicates if the system represents an operator.
isoperbra
Indicates if the system represents a operator-bra state.
isoperket
Indicates if the system represents a operator-ket state.
issuper
Indicates if the system represents a superoperator.
linear_map(op_mapping, *, _skip_check=False)
Apply mapping to each Qobj contribution.

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

202 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 203


QuTiP: Quantum Toolbox in Python, Release 5.0.4

5.1.3 Bloch sphere

class Bloch(fig=None, axes=None, view=None, figsize=None, background=False)


Class for plotting data on the Bloch sphere. Valid data can be either points, vectors, or Qobj objects.
Attributes
axes
[matplotlib.axes.Axes] User supplied Matplotlib axes for Bloch sphere animation.
fig
[matplotlib.figure.Figure] User supplied Matplotlib Figure instance for plotting Bloch
sphere.
font_color
[str, default ‘black’] Color of font used for Bloch sphere labels.
font_size
[int, default 20] Size of font used for Bloch sphere labels.
frame_alpha
[float, default 0.1] Sets transparency of Bloch sphere frame.
frame_color
[str, default ‘gray’] Color of sphere wireframe.
frame_width
[int, default 1] Width of wireframe.
point_color
[list, default [“b”, “r”, “g”, “#CC6600”]] List of colors for Bloch sphere point markers
to cycle through, i.e. by default, points 0 and 4 will both be blue (‘b’).
point_marker
[list, default [“o”, “s”, “d”, “^”]] List of point marker shapes to cycle through.
point_size
[list, default [25, 32, 35, 45]] List of point marker sizes. Note, not all point markers look
the same size when plotted!
sphere_alpha
[float, default 0.2] Transparency of Bloch sphere itself.
sphere_color
[str, default ‘#FFDDDD’] Color of Bloch sphere.
figsize
[list, default [7, 7]] Figure size of Bloch sphere plot. Best to have both numbers the
same; otherwise you will have a Bloch sphere that looks like a football.
vector_color
[list, [“g”, “#CC6600”, “b”, “r”]] List of vector colors to cycle through.
vector_width
[int, default 5] Width of displayed vectors.
vector_style
[str, default ‘-|>’] Vector arrowhead style (from matplotlib’s arrow style).
vector_mutation
[int, default 20] Width of vectors arrowhead.
view
[list, default [-60, 30]] Azimuthal and Elevation viewing angles.
xlabel
[list, default [“$x$”, “”]] List of strings corresponding to +x and -x axes labels, respec-
tively.

204 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 205


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

206 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 207


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

class QFunc(xvec, yvec, g: float = 1.4142135623730951, memory: float = 1024)


Class-based method of calculating the Husimi-Q function of many different quantum states at fixed phase-
space points 0.5*g* (xvec + i*yvec). This class has slightly higher first-usage costs than qfunc, but
subsequent operations will be several times faster. However, it can require quite a lot of memory. Call the
created object as a function to retrieve the Husimi-Q function.
Parameters
xvec, yvec
[array_like] x- and y-coordinates at which to calculate the Husimi-Q function.
g
[float, default: sqrt(2)] Scaling factor for a = 0.5 * g * (x + iy). The value of g
is related to the value of hbar in the commutation relation [𝑥, 𝑦] = 𝑖ℏ via ℏ = 2/𝑔 2 , so
the default corresponds to ℏ = 1.
memory
[real, default: 1024] Size in MB that may be used internally as workspace. This class will
raise MemoryError if subsequently passed a state of sufficiently large dimension that this
bound would be exceeded. In those cases, use qfunc with precompute_memory=None
instead to force using the slower, more memory-efficient algorithm.
See also:

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.

>>> xvec = np.linspace(-2, 2, 101)


>>> states = [qutip.rand_dm(10) for _ in [None]*10]
>>> qfunc = qutip.QFunc(xvec, xvec)

Now we can calculate the Husimi-Q function over each of the states more efficiently with:

>>> husimiq = np.array([qfunc(state) for state in states])

208 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

5.1.5 Solvers

class SESolver(H, *, options=None)


Bases: Solver
Schrodinger equation evolution of a state vector or unitary matrix for a given Hamiltonian.
Parameters
H
[Qobj, QobjEvo] System Hamiltonian as a Qobj or QobjEvo for time-dependent Hamil-
tonians. List of [Qobj, Coefficient] or callable that can be made into QobjEvo are
also accepted.
options
[dict, optional] Options for the solver, see SESolver.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.
classmethod StateFeedback(default=None, raw_data=False, prop=False)
State of the evolution to be used in a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"state": SESolver.StateFeedback()})
The func will receive the ket as state during the evolution.
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
prop
[bool, default][False] Set to True when using sesolve for computing propagators.
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
Solver’s options:
store_final_state: bool, default: False
Whether or not to store the final state of the evolution in the result class.

5.1. Classes 209


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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, *, 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.

210 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 211


QuTiP: Quantum Toolbox in Python, Release 5.0.4

classmethod StateFeedback(default=None, raw_data=False, prop=False)


State of the evolution to be used in a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"state": MESolver.StateFeedback()})
The func will receive the density matrix as state during the evolution.
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
prop
[bool, default][False] Set to True when computing propagators. The default with take
the shape of the propagator instead of a state.
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
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, *, 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.

212 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 213


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

214 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 215


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Note: Operators (c_ops and e_ops) are in the laboratory basis.

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.

216 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 217


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

218 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

5.1. Classes 219


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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))

__call__(t, t_start=0, **args)


Get the propagator from t_start to t.
Parameters
t
[float] Time at which to compute the propagator.
t_start: float [0]
Time at which the propagator start such that:
psi[t] = U.prop(t, t_start) @ psi[t_start]
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.
inv(t, **args)

Get the inverse of the propagator at t, such that


psi_0 = U.inv(t) @ psi_t

Parameters

220 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1.6 Monte Carlo Solvers

class MCSolver(H, c_ops, *, options=None)


Bases: MultiTrajSolver
Monte Carlo Solver of a state vector |𝜓⟩ for a given Hamiltonian and sets of collapse operators. 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.
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.
options
[dict, [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.

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.

5.1. Classes 221


QuTiP: Quantum Toolbox in Python, Release 5.0.4

classmethod StateFeedback(default=None, raw_data=False, open=False)


State of the evolution to be used in a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"state": MCSolver.StateFeedback()})
The func will receive the density matrix as state during the evolution.
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
open
[bool, default False] Set to True when using the monte carlo solver for open systems.
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 monte carlo 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.
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.
method: str, default: “adams”
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.
mpi_options: dict, default: {}
Only applies if map is “mpi”. This dictionary will be passed as keyword arguments to the
mpi4py.futures.MPIPoolExecutor constructor. Note that the max_workers argument is provided
separately through the num_cpus option.
num_cpus: None, int
Number of cpus to use when running in parallel. None detect the number of available cpus.
bitgenerator: {None, “MT19937”, “PCG64”, “PCG64DXSM”, . . . }
Which of numpy.random’s bitgenerator to use. With None, your numpy version’s default is used.
mc_corr_eps: float, default: 1e-10
Small number used to detect non-physical collapse caused by numerical imprecision.
norm_t_tol: float, default: 1e-6
Tolerance in time used when finding the collapse.

222 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

norm_tol: float, default: 1e-4


Tolerance in norm used when finding the collapse.
norm_steps: int, default: 5
Maximum number of tries to find the collapse.
improved_sampling: Bool, default: False
Whether to use the improved sampling algorithm of Abdelhafez et al. PRA (2019)
run(state, tlist, ntraj=1, *, args=None, e_ops=(), timeout=None, target_tol=None, seeds=None)
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.
start(state, t0, seed=None)
Set the initial state and time for a step evolution.
Parameters
state
[Qobj] Initial state of the evolution.

5.1. Classes 223


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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()})

224 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

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, open=False)
State of the evolution to be used in a time-dependent operator.
When used as an args:
QobjEvo([op, func], args={"state": MCSolver.StateFeedback()})
The func will receive the density matrix as state during the evolution.
Parameters
default
[Qobj or qutip.core.data.Data, default][None] Initial value to be used at setup of the
system.
open
[bool, default False] Set to True when using the monte carlo solver for open systems.
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.
current_martingale()
Returns the value of the influence martingale along the current trajectory. The value of the martingale
is the product of the continuous and the discrete contribution. The current time and the collapses that
have happened are read out from the internal integrator.
property options
Options for non-Markovian Monte Carlo 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.

5.1. Classes 225


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.
method: str, default: “adams”
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.
mpi_options: dict, default: {}
Only applies if map is “mpi”. This dictionary will be passed as keyword arguments to the
mpi4py.futures.MPIPoolExecutor constructor. Note that the max_workers argument is provided
separately through the num_cpus option.
num_cpus: None, int
Number of cpus to use when running in parallel. None detect the number of available cpus.
bitgenerator: {None, “MT19937”, “PCG64”, “PCG64DXSM”, . . . }
Which of numpy.random’s bitgenerator to use. With None, your numpy version’s default is used.
mc_corr_eps: float, default: 1e-10
Small number used to detect non-physical collapse caused by numerical imprecision.
norm_t_tol: float, default: 1e-6
Tolerance in time used when finding the collapse.
norm_tol: float, default: 1e-4
Tolerance in norm used when finding the collapse.
norm_steps: int, default: 5
Maximum number of tries to find the collapse.
completeness_rtol: float, default: 1e-5
Used in determining whether the given Lindblad operators satisfy a certain completeness relation.
If they do not, an additional Lindblad operator is added automatically (with zero rate).
completeness_atol: float, default: 1e-8
Used in determining whether the given Lindblad operators satisfy a certain completeness relation.
If they do not, an additional Lindblad operator is added automatically (with zero rate).
martingale_quad_limit: float or int, default: 100
An upper bound on the number of subintervals used in the adaptive integration of the martingale.
Note that the ‘improved_sampling’ option is not currently supported.
rate(t, i)
Return the i’th unshifted rate at time t.
Parameters
t
[float] The time at which to calculate the rate.
i
[int] Which rate to calculate.
Returns
rate
[float] The value of rate i at time t.

226 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 227


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

228 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

5.1.7 Non-Markovian HEOM Solver

class HEOMSolver(H, bath, max_depth, *, options=None)


HEOM solver that supports multiple baths.
The baths must be all either bosonic or fermionic baths.
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).
options
[dict, optional] Generic solver options. If set to None the default options will be used.
Keyword only. Default: None.
Attributes
ados
[HierarchyADOs] The description of the hierarchy constructed from the given bath and
maximum depth.
rhs
[QobjEvo] The right-hand side (RHS) of the hierarchy evolution ODE. Internally the
system and bath coupling operators are converted to qutip.data.CSR instances during
construction of the RHS, so the operators in the rhs will all be sparse.
property options
Options for HEOMSolver:
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: “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.
method: str, default: “adams”
Which ordinary differential equation integration method to use.
state_data_type: str, default: “dense”
Name of the data type of the state used during the ODE evolution. Use an empty string to keep
the input state type. Many integrators support only work with Dense.

5.1. Classes 229


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

230 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 231


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Nk used in the DrudeLorentzBath . I.e., Nk = N_exp - 1. The Nk parameter in the DrudeLorentzBath


does not count the zeroeth exponent in order to better match common usage in the literature.

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.

class BathExponent(type, dim, Q, ck, vk, ck2=None, sigma_bar_k_offset=None, tag=None)


Represents a single exponent (naively, an excitation mode) within the decomposition of the correlation func-
tions of a bath.
Parameters
type
[{“R”, “I”, “RI”, “+”, “-”} or BathExponent.ExponentType] The type of bath exponent.
“R” and “I” are bosonic bath exponents that appear in the real and imaginary parts of
the correlation expansion.
“RI” is combined bosonic bath exponent that appears in both the real and imaginary
parts of the correlation expansion. The combined exponent has a single vk. The ck is
the coefficient in the real expansion and ck2 is the coefficient in the imaginary expansion.

232 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

“+” 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:

C(t) = C_real(t) + i * C_imag(t)

then:

C_real(t) = sum(ck_real * exp(- vk_real * t))


C_imag(t) = sum(ck_imag * exp(- vk_imag * t))

5.1. Classes 233


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Defines the coefficients ck and the frequencies vk.


Note that the ck and vk may be complex, even through C_real(t) and C_imag(t) (i.e. the sum) is real.
Parameters
Q
[Qobj] The coupling operator for the bath.
ck_real
[list of complex] The coefficients of the expansion terms for the real part of the correla-
tion function. The corresponding frequencies are passed as vk_real.
vk_real
[list of complex] The frequencies (exponents) of the expansion terms for the real part of
the correlation function. The corresponding ceofficients are passed as ck_real.
ck_imag
[list of complex] The coefficients of the expansion terms in the imaginary part of the
correlation function. The corresponding frequencies are passed as vk_imag.
vk_imag
[list of complex] The frequencies (exponents) of the expansion terms for the imaginary
part of the correlation function. The corresponding ceofficients are passed as ck_imag.
combine
[bool, default True] Whether to combine exponents with the same frequency (and cou-
pling operator). See 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.
classmethod combine(exponents, rtol=1e-05, atol=1e-07)
Group bosonic exponents with the same frequency and return a single exponent for each frequency
present.
Exponents with the same frequency are only combined if they share the same coupling operator .Q.
Note that combined exponents take their tag from the first exponent in the group being combined (i.e.
the one that occurs first in the given exponents list).
Parameters
exponents
[list of BathExponent] The list of exponents to combine.
rtol
[float, default 1e-5] The relative tolerance to use to when comparing frequencies and
coupling operators.
atol
[float, default 1e-7] The absolute tolerance to use to when comparing frequencies and
coupling operators.
Returns
list of BathExponent
The new reduced list of exponents.
class DrudeLorentzBath(Q, lam, gamma, T, Nk, combine=True, tag=None)
A helper class for constructing a Drude-Lorentz bosonic bath from the bath parameters (see parameters
below).
Parameters

234 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 235


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

236 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

class FermionicBath(Q, ck_plus, vk_plus, ck_minus, vk_minus, tag=None)


A helper class for constructing a fermionic bath from the expansion coefficients and frequencies for the +
and - modes of the bath correlation function.
There must be the same number of + and - modes and their coefficients must be specified in the same order
so that ck_plus[i], vk_plus[i] are the plus coefficient and frequency corresponding to the minus mode
ck_minus[i], vk_minus[i].
In the fermionic case the order in which excitations are created or destroyed is important, resulting in two
different correlation functions labelled C_plus(t) and C_plus(t):

C_plus(t) = sum(ck_plus * exp(- vk_plus * t))


C_minus(t) = sum(ck_minus * exp(- vk_minus * t))

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.

5.1. Classes 237


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

class LorentzianPadeBath(Q, gamma, w, mu, T, Nk, tag=None)


A helper class for constructing a Padé expansion for Lorentzian fermionic 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 LorentzianBath which constructs a simpler exponential expansion that con-
verges much more slowly in this particular case.
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.
class HierarchyADOs(exponents, max_depth)
A description of ADOs (auxilliary density operators) with the hierarchical equations of motion.
The list of ADOs is constructed from a list of bath exponents (corresponding to one or more baths). Each
ADO is referred to by a label that lists the number of “excitations” of each bath exponent. The level of a
label within the hierarchy is the sum of the “excitations” within the label.
For example the label (0, 0, ..., 0) represents the density matrix of the system being solved and is the
only 0th level label.
The labels with a single 1, i.e. (1, 0, ..., 0), (0, 1, 0, ... 0), etc. are the 1st level labels.
The second level labels all have either two 1s or a single 2, and so on for the third and higher levels of the
hierarchy.
Parameters

238 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 239


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Examples

ados.exps((1, 0, 0)) would return [ados.exponents[0]]


ados.exps((2, 0, 0)) would return [ados.exponents[0], ados.exponents[0]].
ados.exps((1, 2, 1)) would return [ados.exponents[0], ados.exponents[1], ados.
exponents[1], ados.exponents[2]].
filter(level=None, tags=None, dims=None, types=None)
Return a list of ADO labels for ADOs whose “excitations” match the given patterns.
Each of the filter parameters (tags, dims, types) may be either unspecified (None) or a list. Unspecified
parameters are excluded from the filtering.
All specified filter parameters must be lists of the same length. Each position in the lists describes a
particular excitation and any exponent that matches the filters may supply that excitation. The level of
all labels returned is thus equal to the length of the filter parameter lists.
Within a filter parameter list, items that are None represent wildcards and match any value of that
exponent attribute
Parameters
level
[int] The hierarchy depth to return ADOs from.
tags
[list of object or None] Filter parameter that matches the .tag attribute of exponents.
dims
[list of int] Filter parameter that matches the .dim attribute of exponents.
types
[list of BathExponent types or list of str] Filter parameter that matches the .type at-
tribute of exponents. Types may be supplied by name (e.g. “R”, “I”, “+”) instead of
by the actual type (e.g. BathExponent.types.R).
Returns
list of tuple
The ADO label for each ADO whose exponent excitations (i.e. label) match the given
filters or level.
idx(label)
Return the index of the ADO label within the list of labels, i.e. within self.labels.
Parameters
label
[tuple] The label to look up.
Returns
int
The index of the label within the list of ADO labels.

240 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 241


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

5.1.8 Stochastic Solver

class SMESolver(H, sc_ops, heterodyne, *, c_ops=(), options=None)


Stochastic Master 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.
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 SMESolver.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)})
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": SMESolver.StateFeedback()})
The func will receive the density matrix as state during the evolution.

Note: Not supported by the rouchon mehtod.

242 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 243


QuTiP: Quantum Toolbox in Python, Release 5.0.4

mpi_options: dict, default: {}


Only applies if map is “mpi”. This dictionary will be passed as keyword arguments to the
mpi4py.futures.MPIPoolExecutor constructor. Note that the max_workers argument is provided
separately through the num_cpus option.
num_cpus: None, int, default: None
Number of cpus to use when running in parallel. None detect the number of available cpus.
bitgenerator: {None, “MT19937”, “PCG64DXSM”, . . . }, default: None
Which of numpy.random’s bitgenerator to use. With None, your numpy version’s default is used.
run(state, tlist, ntraj=1, *, args=None, e_ops=(), timeout=None, target_tol=None, seeds=None)
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.
start(state, t0, seed=None)
Set the initial state and time for a step evolution.
Parameters

244 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)})

5.1. Classes 245


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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": SMESolver.StateFeedback()})
The func will receive the density matrix as state during the evolution.

Note: Not supported by the rouchon mehtod.

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.

246 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.
mpi_options: dict, default: {}
Only applies if map is “mpi”. This dictionary will be passed as keyword arguments to the
mpi4py.futures.MPIPoolExecutor constructor. Note that the max_workers argument is provided
separately through the num_cpus option.
num_cpus: None, int, default: None
Number of cpus to use when running in parallel. None detect the number of available cpus.
bitgenerator: {None, “MT19937”, “PCG64DXSM”, . . . }, default: None
Which of numpy.random’s bitgenerator to use. With None, your numpy version’s default is used.
run(state, tlist, ntraj=1, *, args=None, e_ops=(), timeout=None, target_tol=None, seeds=None)
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.

5.1. Classes 247


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

248 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

5.1.9 Integrator

class IntegratorScipyAdams(system, options)


Integrator using Scipy ode with zvode integrator using adams method. Ordinary Differential Equation solver
by netlib (https://www.netlib.org/odepack).
Usable with method="adams"
property options
Supported options by zvode integrator:
atol
[float, default: 1e-8] Absolute tolerance.
rtol
[float, default: 1e-6] Relative tolerance.
order
[int, default: 12, ‘adams’ or 5, ‘bdf’] Order of integrator <=12 ‘adams’, <=5 ‘bdf’
nsteps
[int, default: 2500] Max. number of internal steps/call.
first_step
[float, default: 0] Size of initial step (0 = automatic).
min_step
[float, default: 0] Minimum step size (0 = automatic).
max_step
[float, default: 0] Maximum step size (0 = automatic) When using pulses, change to half the thinest
pulse otherwise it may be skipped.
class IntegratorScipyBDF(system, options)
Integrator using Scipy ode with zvode integrator using bdf method. Ordinary Differential Equation solver
by netlib (https://www.netlib.org/odepack).
Usable with method="bdf"
property options
Supported options by zvode integrator:
atol
[float, default: 1e-8] Absolute tolerance.
rtol
[float, default: 1e-6] Relative tolerance.
order
[int, default: 12, ‘adams’ or 5, ‘bdf’] Order of integrator <=12 ‘adams’, <=5 ‘bdf’
nsteps
[int, default: 2500] Max. number of internal steps/call.
first_step
[float, default: 0] Size of initial step (0 = automatic).
min_step
[float, default: 0] Minimum step size (0 = automatic).
max_step
[float, default: 0] Maximum step size (0 = automatic) When using pulses, change to half the thinest
pulse otherwise it may be skipped.

5.1. Classes 249


QuTiP: Quantum Toolbox in Python, Release 5.0.4

class IntegratorScipylsoda(system, options)


Integrator using Scipy ode with lsoda integrator. ODE solver by netlib (https://www.netlib.org/odepack)
Automatically choose between ‘Adams’ and ‘BDF’ methods to solve both stiff and non-stiff systems.
Usable with method="lsoda"
property options
Supported options by lsoda integrator:
atol
[float, default: 1e-8] Absolute tolerance.
rtol
[float, default: 1e-6] Relative tolerance.
nsteps
[int, default: 2500] Max. number of internal steps/call.
max_order_ns
[int, default: 12] Maximum order used in the nonstiff case (<= 12).
max_order_s
[int, default: 5] Maximum order used in the stiff case (<= 5).
first_step
[float, default: 0] Size of initial step (0 = automatic).
max_step
[float, default: 0] Maximum step size (0 = automatic) When using pulses, change to half the thinest
pulse otherwise it may be skipped.
min_step
[float, default: 0] Minimum step size (0 = automatic)
class IntegratorScipyDop853(system, options)
Integrator using Scipy ode with dop853 integrator. Eight order runge-kutta method by Dormand & Prince.
Use fortran implementation from [E. Hairer, S.P. Norsett and G. Wanner, Solving Ordinary Differential
Equations i. Nonstiff Problems. 2nd edition. Springer Series in Computational Mathematics, Springer-
Verlag (1993)].
Usable with method="dop853"
property options
Supported options by dop853 integrator:
atol
[float, default: 1e-8] Absolute tolerance.
rtol
[float, default: 1e-6] Relative tolerance.
nsteps
[int, default: 2500] Max. number of internal steps/call.
first_step
[float, default: 0] Size of initial step (0 = automatic).
max_step
[float, default: 0] Maximum step size (0 = automatic)
ifactor, dfactor
[float, default: 6., 0.3] Maximum factor to increase/decrease step size by in one step
beta
[float, default: 0] Beta parameter for stabilised step size control.
See scipy.integrate.ode ode for more detail

250 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

class IntegratorVern7(system, options)


QuTiP’s implementation of Verner’s “most efficient” Runge-Kutta method of order 7. These are Runge-Kutta
methods with variable steps and dense output.
The implementation uses QuTiP’s Data objects for the state, allowing sparse, GPU or other data layer objects
to be used efficiently by the solver in their native formats.
See https://www.sfu.ca/~jverner/ for a detailed description of the methods.
Usable with method="vern7"
property options
Supported options by verner method:
atol
[float, default: 1e-8] Absolute tolerance.
rtol
[float, default: 1e-6] Relative tolerance.
nsteps
[int, default: 1000] Max. number of internal steps/call.
first_step
[float, default: 0] Size of initial step (0 = automatic).
min_step
[float, default: 0] Minimum step size (0 = automatic).
max_step
[float, default: 0] Maximum step size (0 = automatic) When using pulses, change to half the thinest
pulse otherwise it may be skipped.
interpolate
[bool, default: True] Whether to use interpolation step, faster most of the time.
class IntegratorVern9(system, options)
QuTiP’s implementation of Verner’s “most efficient” Runge-Kutta method of order 9. These are Runge-Kutta
methods with variable steps and dense output.
The implementation uses QuTiP’s Data objects for the state, allowing sparse, GPU or other data layer objects
to be used efficiently by the solver in their native formats.
See https://www.sfu.ca/~jverner/ for a detailed description of the methods.
Usable with method="vern9"
property options
Supported options by verner method:
atol
[float, default: 1e-8] Absolute tolerance.
rtol
[float, default: 1e-6] Relative tolerance.
nsteps
[int, default: 1000] Max. number of internal steps/call.
first_step
[float, default: 0] Size of initial step (0 = automatic).
min_step
[float, default: 0] Minimum step size (0 = automatic).
max_step
[float, default: 0] Maximum step size (0 = automatic) When using pulses, change to half the thinest
pulse otherwise it may be skipped.

5.1. Classes 251


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1.10 Stochastic Integrator

class RouchonSODE(rhs, options)


Stochastic integration method keeping the positivity of the density matrix. See eq. (4) Pierre Rouchon and
Jason F. Ralpha, Efficient Quantum Filtering for Quantum Feedback Control, arXiv:1410.5345 [quant-ph],
Phys. Rev. A 91, 012118, (2015).
• Order: strong 1

252 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 253


QuTiP: Quantum Toolbox in Python, Release 5.0.4

class Implicit_Milstein_SODE(rhs, options)


An order 1.0 implicit strong Taylor scheme. Implicit Milstein scheme for the numerical simulation of stiff
stochastic differential equations. Eq. (2.11) with alpha=0.5 of chapter 12.2 of Peter E. Kloeden and Exkhard
Platen, Numerical Solution of Stochastic Differential Equations.
• Order strong 1.0
property options
Supported options by Implicit Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Tolerance for the time steps.
solve_method
[str, default: None] Method used for solver the Ax=b of the implicit step. Accept methods sup-
ported by qutip.core.data.solve. When the system is constant, the inverse of the matrix A
can be used by entering inv.
solve_options
[dict, default: {}] Options to pass to the call to qutip.core.data.solve.
class Implicit_Taylor1_5_SODE(rhs, options)
Order 1.5 implicit strong Taylor scheme. Solver with more terms of the Ito-Taylor expansion. Eq. (2.18)
with alpha=0.5 of chapter 12.2 of Peter E. Kloeden and Exkhard Platen, Numerical Solution of Stochastic
Differential Equations.
• Order strong 1.5
property options
Supported options by Implicit Order 1.5 strong Taylor Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.
tol
[float, default: 1e-10] Tolerance for the time steps.
solve_method
[str, default: None] Method used for solver the Ax=b of the implicit step. Accept methods sup-
ported by qutip.core.data.solve. When the system is constant, the inverse of the matrix A
can be used by entering inv.
solve_options
[dict, default: {}] Options to pass to the call to qutip.core.data.solve.
derr_dt
[float, default: 1e-6] Finite time difference used to compute the derrivative of the hamiltonian and
sc_ops.
class PlatenSODE(rhs, options)
Explicit scheme, creates the Milstein using finite differences instead of analytic derivatives. Also contains
some higher order terms, thus converges better than Milstein while staying strong order 1.0. Does not require
derivatives. See eq. (7.47) of chapter 7 of H.-P. Breuer and F. Petruccione, The Theory of Open Quantum
Systems.
• Order: strong 1, weak 2
property options
Supported options by Explicit Stochastic Integrators:
dt
[float, default: 0.001] Internal time step.

254 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1.11 Solver Options and Results

class Result(e_ops, options: ResultOptions, *, solver=None, stats=None, **kw)


Base class for storing 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 e_data and expect attributes of this result object.
e_data is a dictionary and expect is a list, where each item contains the values of
the corresponding e_op.

5.1. Classes 255


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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).

256 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1. Classes 257


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

258 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 259


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

260 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1.12 Permutational Invariance

class Dicke(N, hamiltonian=None, emission=0.0, dephasing=0.0, pumping=0.0, collective_emission=0.0,


collective_dephasing=0.0, collective_pumping=0.0)
The Dicke class which builds the Lindbladian and Liouvillian matrix.
Parameters
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 functions.
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

Examples

>>> from qutip.piqs import Dicke, jspin


>>> N = 2
>>> jx, jy, jz = jspin(N)
>>> jp = jspin(N, "+")
>>> jm = jspin(N, "-")
>>> ensemble = Dicke(N, emission=1.)
>>> L = ensemble.liouvillian()

Attributes

5.1. Classes 261


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

262 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.1. Classes 263


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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).

264 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.1.13 Distribution functions

class Distribution(data=None, xvecs=[], xlabels=[])


A class for representation spatial distribution functions.
The Distribution class can be used to prepresent spatial distribution functions of arbitray dimension (although
only 1D and 2D distributions are used so far).
It is indented as a base class for specific distribution function, and provide implementation of basic functions
that are shared among all Distribution functions, such as visualization, calculating marginal distributions,
etc.
Parameters
data
[array_like] Data for the distribution. The dimensions must match the lengths of the
coordinate arrays in xvecs.
xvecs
[list] List of arrays that spans the space for each coordinate.
xlabels
[list] List of labels for each coordinate.
marginal(dim=0)
Calculate the marginal distribution function along the dimension dim. Return a new Distribution in-
stance describing this reduced- dimensionality distribution.
Parameters
dim
[int] The dimension (coordinate index) along which to obtain the marginal distribution.
Returns

5.1. Classes 265


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2.1 Manipulation and Creation of States and Operators

Quantum States

basis(dimensions, n=None, offset=None, *, dtype=None)


Generates the vector representation of a Fock 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.

266 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

A subtle incompatibility with the quantum optics toolbox: In QuTiP:

basis(N, 0) = ground state

but in the qotoolbox:

basis(N, 1) = ground state

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)

5.2. Functions 267


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Returns the selected Bell state:


1
|𝐵00 ⟩ = √ (|00⟩ + |11⟩)
2
1
|𝐵01 ⟩ = √ (|00⟩ − |11⟩)
2
1
|𝐵10 ⟩ = √ (|01⟩ + |10⟩)
2
1
|𝐵11 ⟩ = √ (|01⟩ − |10⟩)
2

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]

268 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.]]

>>> bra("31", [5, 2])


Quantum object: dims = [[1, 1], [5, 2]], shape = [1, 10], type = bra
Qobj data =
[[ 0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]]

coherent(N, alpha, offset=0, method=None, *, dtype=None)


Generates a coherent state with eigenvalue alpha.
Constructed using displacement operator on vacuum state.
Parameters
N
[int] Number of Fock states in Hilbert space.
alpha
[float/complex] Eigenvalue of coherent state.
offset
[int, default: 0] The lowest number state that is included in the finite number state rep-
resentation of the state. Using a non-zero offset will make the default method ‘analytic’.
method
[string {‘operator’, ‘analytic’}, optional] Method for generating coherent state.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
state
[qobj] Qobj quantum object for coherent state

5.2. Functions 269


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 ]]

coherent_dm(N, alpha, offset=0, method='operator', *, dtype=None)


Density matrix representation of a coherent state.
Constructed via outer product of coherent
Parameters
N
[int] Number of basis states in Hilbert space.
alpha
[float/complex] Eigenvalue for coherent state.
offset
[int, default: 0] The lowest number state that is included in the finite number state rep-
resentation of the state.
method
[string {‘operator’, ‘analytic’}, optional] Method for generating coherent density matrix.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
dm
[qobj] Density matrix representation of coherent state.

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.

270 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 ]]

fock(dimensions, n=None, offset=None, *, dtype=None)


Bosonic Fock (number) state.
Same as basis.
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
[int or list of ints, default: 0 for all dimensions] Integer corresponding to desired 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, 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
Requested number state |𝑛⟩.

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]]

fock_dm(dimensions, n=None, offset=None, *, dtype=None)


Density matrix representation of a Fock state
Constructed via outer product of basis.
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
[int or list of ints, default: 0 for all dimensions] Integer corresponding to desired 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.

5.2. Functions 271


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

Returns the N-qubit GHZ-state:


[ |00...00> + |11...11> ] / sqrt(2)

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(seq, dim=2, *, dtype=None)


Produces a multiparticle ket 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’ (hori-
zontal and vertical polarization) Note: for dimension > 9 you need to use a list.
dim
[int or list of ints, default: 2] 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

272 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.]]

>>> ket("31", [5, 2])


Quantum object: dims = [[5, 2], [1, 1]], shape = [10, 1], type = ket
Qobj data =
[[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 1.]
[ 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().

5.2. Functions 273


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

274 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 275


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

>>> state_index_number([2, 2, 2], 6)


[1, 1, 0]

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.

276 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

>>> for state in state_number_enumerate([2,2]):


>>> print(state)
( 0 0 )
( 0 1 )
( 1 0 )
( 1 1 )

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

>>> state_number_index([2, 2, 2], [1, 1, 0])


6

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.

state_number_qobj(dims, state, *, dtype=None)


Return a Qobj representation of a quantum state specified by the state array state.

Note: Deprecated in QuTiP 5.0, use basis instead.

5.2. Functions 277


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Example

>>> state_number_qobj([2, 2, 2], [1, 0, 1])


Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = [8, 1], type = ket
Qobj data =
[[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 0.]
[ 1.]
[ 0.]
[ 0.]]

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.

thermal_dm(N, n, method='operator', *, dtype=None)


Density matrix for a thermal state of n particles
Parameters
N
[int] Number of basis states in Hilbert space.
n
[float] Expectation value for number of particles in thermal state.
method
[string {‘operator’, ‘analytic’}, default: ‘operator’] string that sets the method used to
generate the thermal state probabilities
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
dm
[qobj] Thermal state density matrix.

278 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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]]

>>> thermal_dm(5, 1, 'analytic')


Quantum object: dims = [[5], [5]], shape = [5, 5], type = oper, isHerm = True
Qobj data =
[[ 0.5 0. 0. 0. 0. ]
[ 0. 0.25 0. 0. 0. ]
[ 0. 0. 0.125 0. 0. ]
[ 0. 0. 0. 0.0625 0. ]
[ 0. 0. 0. 0. 0.03125]]

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)

Returns the N-qubit W-state:


[ |100..0> + |010..0> + |001..0> + ... |000..1> ] / sqrt(n)

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

5.2. Functions 279


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

New in version 3.2.


commutator(A, B, kind='normal')
Return the commutator of kind kind (normal, anti) of the two operators A and B.
Parameters
A, B
[Qobj, QobjEvo] The operators to compute the commutator of.
kind: str {“normal”, “anti”}, default: “anti”
Which kind of commutator to compute.
create(N, offset=0, *, dtype=None)
Creation (raising) operator.
Parameters

280 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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]]

destroy(N, offset=0, *, dtype=None)


Destruction (lowering) operator.
Parameters
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 lowering operator.

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]]

displace(N, alpha, offset=0, *, dtype=None)


Single-mode displacement operator.
Parameters

5.2. Functions 281


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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]]

fcreate(n_sites, site, dtype=None)


Fermionic creation operator. We use the Jordan-Wigner transformation, making use of the Jordan-Wigner
ZZ..Z strings, to construct this as follows:
𝜎𝑥 − 𝑖𝜎𝑦
𝑎𝑗 = 𝜎𝑧⊗𝑗 ⊗ ( ) ⊗ 𝐼 ⊗𝑁 −𝑗−1
2
Parameters
n_sites
[int] Number of sites in Fock space.
site
[int] The site in Fock space to add a fermion to. Corresponds to j in the above JW
transform.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Qobj for raising operator.

282 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.]]

fdestroy(n_sites, site, dtype=None)


Fermionic destruction operator. We use the Jordan-Wigner transformation, making use of the Jordan-Wigner
ZZ..Z strings, to construct this as follows:
𝜎𝑥 + 𝑖𝜎𝑦
𝑎𝑗 = 𝜎𝑧⊗𝑗 ⊗ ( ) ⊗ 𝐼 ⊗𝑁 −𝑗−1
2
Parameters
n_sites
[int] Number of sites in Fock space.
site
[int, default: 0] The site in Fock space to add a fermion to. Corresponds to j in the above
JW transform.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
oper
[qobj] Qobj for destruction operator.

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

5.2. Functions 283


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.]]

jmat(j, which=None, *, dtype=None)


Higher-order spin operators:
Parameters
j
[float] Spin of operator
which
[str, optional] Which operator to return ‘x’,’y’,’z’,’+’,’-‘. If not given, then output is
[‘x’,’y’,’z’]
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.
Returns
jmat
[Qobj or tuple of Qobj] qobj for requested spin operator(s).

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)

284 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

(continued from previous page)


[ 0. 0. 0.]
[ 0. 0. -1.]]]

momentum(N, offset=0, *, dtype=None)


Momentum operator p=-1j/sqrt(2)*(a-a.dag())
Parameters
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] Momentum operator as Qobj.
num(N, offset=0, *, dtype=None)
Quantum object for number operator.
Parameters
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 number operator.

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]]

phase(N, phi0=0, *, dtype=None)


Single-mode Pegg-Barnett phase operator.
Parameters
N
[int] Number of basis states in the Hilbert space.

5.2. Functions 285


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

The Pegg-Barnett phase operator is Hermitian on a truncated Hilbert space.


position(N, offset=0, *, dtype=None)
Position operator 𝑥 = 1/𝑠𝑞𝑟𝑡(2) * (𝑎 + 𝑎.𝑑𝑎𝑔())
Parameters
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] Position operator as Qobj.
qdiags(diagonals, offsets=None, dims=None, shape=None, *, dtype=None)
Constructs an operator from an array of diagonals.
Parameters
diagonals
[sequence of array_like] Array of elements to place along the selected diagonals.
offsets
[sequence of ints, optional]
Sequence for diagonals to be set:
• k=0 main diagonal
• k>0 kth upper diagonal
• k<0 kth lower diagonal
dims
[list, optional] Dimensions for operator
shape
[list, tuple, optional] Shape of operator. If omitted, a square operator large enough to
contain the diagonals is generated.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to
is accepted.

286 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Examples

>>> qdiags(sqrt(range(1, 4)), 1)


Quantum object: dims = [[4], [4]], shape = [4, 4], type = oper, isherm = False
Qobj data =
[[ 0. 1. 0. 0. ]
[ 0. 0. 1.41421356 0. ]
[ 0. 0. 0. 1.73205081]
[ 0. 0. 0. 0. ]]

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.

5.2. Functions 287


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

288 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 289


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

290 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 291


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Examples

>>> squeeze(4, 0.25)


Quantum object: dims = [[4], [4]], shape = [4, 4], type = oper, isHerm = False
Qobj data =
[[ 0.98441565+0.j 0.00000000+0.j 0.17585742+0.j 0.00000000+0.j]
[ 0.00000000+0.j 0.95349007+0.j 0.00000000+0.j 0.30142443+0.j]
[-0.17585742+0.j 0.00000000+0.j 0.98441565+0.j 0.00000000+0.j]
[ 0.00000000+0.j -0.30142443+0.j 0.00000000+0.j 0.95349007+0.j]]

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.

292 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 293


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

294 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 295


QuTiP: Quantum Toolbox in Python, Release 5.0.4

qrot(theta, phi, *, dtype=None)


Single qubit rotation driving by Rabi oscillation with 0 detune.
Parameters
phi
[float] The inital phase of the rabi pulse.
theta
[float] The duration of the rabi pulse.
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
Returns
qrot_gate
[Qobj] Quantum object representation of physical qubit rotation under a rabi pulse.
qubit_clifford_group(*, dtype=None)
Generates the Clifford group on a single qubit, using the presentation of the group given by Ross and Selinger
(http://www.mathstat.dal.ca/~selinger/newsynth/).
Parameters
dtype
[str or type, [keyword only] [optional]] Storage representation. Any data-layer known to
qutip.data.to is accepted.
rx(phi, *, dtype=None)
Single-qubit rotation for operator sigmax with angle phi.
Parameters
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.
ry(phi, *, dtype=None)
Single-qubit rotation for operator sigmay with angle phi.
Parameters
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.
rz(phi, *, dtype=None)
Single-qubit rotation for operator sigmaz with angle phi.
Parameters

296 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 297


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

298 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

toff_gate
[qobj] Quantum object representation of Toffoli gate.

Energy Restricted Operators

enr_destroy(dims, excitations, *, dtype=None)


Generate annilation operators for modes in a excitation-number-restricted state space. For example, consider
a system consisting of 4 modes, each with 5 states. The total hilbert space size is 5**4 = 625. If we are only
interested in states that contain up to 2 excitations, we only need to include states such as
(0, 0, 0, 0) (0, 0, 0, 1) (0, 0, 0, 2) (0, 0, 1, 0) (0, 0, 1, 1) (0, 0, 2, 0) . . .
This function creates annihilation operators for the 4 modes that act within this state space:
a1, a2, a3, a4 = enr_destroy([5, 5, 5, 5], excitations=2)
From this point onwards, the annihiltion operators a1, . . . , a4 can be used to setup a Hamiltonian, collapse
operators and expectation-value operators, etc., following the usual pattern.
Parameters
dims
[list] A list of the dimensions of each subsystem of a composite quantum system.
excitations
[integer] The maximum number of excitations that are to be included in the state space.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to is
accepted.
Returns
a_ops
[list of qobj] A list of annihilation operators for each mode in the composite quantum
system described by dims.
enr_fock(dims, excitations, state, *, dtype=None)
Generate the Fock state representation in a excitation-number restricted state space. The dims argument is a
list of integers that define the number of quantums states of each component of a composite quantum system,
and the excitations specifies the maximum number of excitations for the basis states that are to be included
in the state space. The state argument is a tuple of integers that specifies the state (in the number basis
representation) for which to generate the Fock state representation.
Parameters
dims
[list] A list of the dimensions of each subsystem of a composite quantum system.
excitations
[integer] The maximum number of excitations that are to be included in the state space.
state
[list of integers] The state in the number basis representation.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to is
accepted.
Returns
ket
[Qobj] A Qobj instance that represent a Fock state in the exication-number- restricted
state space defined by dims and exciations.

5.2. Functions 299


QuTiP: Quantum Toolbox in Python, Release 5.0.4

enr_identity(dims, excitations, *, dtype=None)


Generate the identity operator for the excitation-number restricted state space defined by the dims and exci-
ations arguments. See the docstring for enr_fock for a more detailed description of these arguments.
Parameters
dims
[list] A list of the dimensions of each subsystem of a composite quantum system.
excitations
[integer] The maximum number of excitations that are to be included in the state space.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to is
accepted.
Returns
op
[Qobj] A Qobj instance that represent the identity operator in the exication-number-
restricted state space defined by dims and exciations.
enr_state_dictionaries(dims, excitations)
Return the number of states, and lookup-dictionaries for translating a state tuple to a state index, and vice
versa, for a system with a given number of components and maximum number of excitations.
Parameters
dims: list
A list with the number of states in each sub-system.
excitations
[integer] The maximum numbers of dimension
Returns
nstates, state2idx, idx2state: integer, dict, dict
The number of states nstates, a dictionary for looking up state indices from a state tu-
ple, and a dictionary for looking up state state tuples from state indices. state2idx and
idx2state are reverses of each other, i.e., state2idx[idx2state[idx]] = idx and
idx2state[state2idx[state]] = state.
enr_thermal_dm(dims, excitations, n, *, dtype=None)
Generate the density operator for a thermal state in the excitation-number- restricted state space defined by
the dims and exciations arguments. See the documentation for enr_fock for a more detailed description of
these arguments. The temperature of each mode in dims is specified by the average number of excitatons n.
Parameters
dims
[list] A list of the dimensions of each subsystem of a composite quantum system.
excitations
[integer] The maximum number of excitations that are to be included in the state space.
n
[integer] The average number of exciations in the thermal state. n can be a float (which
then applies to each mode), or a list/array of the same length as dims, in which each
element corresponds specifies the temperature of the corresponding mode.
dtype
[type or str, optional] Storage representation. Any data-layer known to qutip.data.to is
accepted.
Returns

300 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Random Operators and States

This module is a collection of random state and operator generators.


rand_dm(dimensions, density=0.75, distribution='ginibre', *, eigenvalues=(), rank=None, seed=None,
dtype=None)
Creates a random density matrix of the desired 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.

density
[float, default: 0.75] Density between [0,1] of output density matrix. Used by the
“pure”, “eigen” and “herm”.

distribution : str {“ginibre”, “hs”, “pure”, “eigen”, “uniform”},


default: “ginibre”
Method used to obtain the density matrices.
• “ginibre” : Ginibre random density operator of rank rank by using the algorithm
of [BCSZ08].
• “hs” : Hilbert-Schmidt ensemble, equivalent to a full rank ginibre operator.
• “pure” : Density matrix created from a random ket.
• “eigen” : A density matrix with the given eigenvalues.
• “herm” : Build from a random hermitian matrix using rand_herm.

5.2. Functions 301


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

302 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 303


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

304 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 305


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Superoperators and Liouvillians

lindblad_dissipator(a, b=None, data_only=False, chi=None)


Lindblad dissipator (generalized) for a single pair of collapse operators (a, b), or for a single collapse operator
(a) when b is not specified:
1 1
𝒟[𝑎, 𝑏]𝜌 = 𝑎𝜌𝑏† − 𝑎† 𝑏𝜌 − 𝜌𝑎† 𝑏
2 2
Parameters
a
[Qobj or QobjEvo] Left part of collapse operator.
b
[Qobj or QobjEvo, optional] Right part of collapse operator. If not specified, b defaults
to a.
chi
[float, optional] In some systems it is possible to determine the statistical moments
(mean, variance, etc) of the probability distribution of the occupation numbers of states
by numerically evaluating the derivatives of the steady state occupation probability as a
function of an artificial phase parameter chi which multiplies the a \rho a^dagger
term of the dissipator by e ^ (i * chi). The factor e ^ (i * chi) is introduced via
the generating function of the statistical moments. For examples of the technique, see
Full counting statistics of nano-electromechanical systems and Photon-mediated elec-
tron transport in hybrid circuit-QED. This parameter is deprecated and may be removed
in QuTiP 5.
data_only
[bool, default: False] Return the data object instead of a Qobj
Returns
D
[qobj, QobjEvo] Lindblad dissipator superoperator.
liouvillian(H=None, c_ops=None, data_only=False, chi=None)
Assembles the Liouvillian superoperator from a Hamiltonian and a list of collapse operators.
Parameters
H
[Qobj or QobjEvo, optional] System Hamiltonian or Hamiltonian component of a Liou-
villian. Considered 0 if not given.
c_ops
[array_like of Qobj or QobjEvo, optional] A list or array of collapse operators.
data_only
[bool, default: False] Return the data object instead of a Qobj
chi
[array_like of float, optional] In some systems it is possible to determine the statis-
tical moments (mean, variance, etc) of the probability distributions of occupation of
various states by numerically evaluating the derivatives of the steady state occupa-
tion probability as a function of artificial phase parameters chi which are included
in the lindblad_dissipator for each collapse operator. See the documentation of
lindblad_dissipator for references and further details. This parameter is deprecated
and may be removed in QuTiP 5.
Returns
L
[Qobj or QobjEvo] Liouvillian superoperator.

306 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 307


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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())).

308 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 309


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Operators and Superoperator Dimensions

Internal use module for manipulating dims specifications.


from_tensor_rep(tensorrep, dims)
Reverse operator of to_tensor_rep. Create a Qobj From a N-dimensions numpy array and dimensions
with N indices.
Parameters
tensorrep: ndarray
Numpy array with one dimension for each index in dims.
dims: list of list, Dimensions
Dimensions of the Qobj.
Returns
Qobj
Re constructed Qobj
to_tensor_rep(q_oper)
Transform a Qobj to a numpy array whose shape is the flattened dimensions.
Parameters
q_oper: Qobj
Object to reshape
Returns
ndarray:
Numpy array with one dimension for each index in dims.

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)

310 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

5.2.2 Functions acting on states and operators

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

>>> expect(num(4), basis(4, 3)) == 3


True

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

5.2. Functions 311


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

>>> tensor([sigmax(), sigmax()])


Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm =␣
˓→True

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

partial_transpose(rho, mask, method='dense')


Return the partial transpose of a Qobj instance rho, where mask is an array/list with length that equals the
number of components of rho (that is, the length of rho.dims[0]), and the values in mask indicates whether
or not the corresponding subsystem is to be transposed. The elements in mask can be boolean or integers 0
or 1, where True/1 indicates that the corresponding subsystem should be tranposed.
Parameters
rho
[Qobj] A density matrix.

312 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 313


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Examples

>>> rho=0.5*fock_dm(2,0)+0.5*fock_dm(2,1)
>>> entropy_linear(rho)
0.5

entropy_mutual(rho, selA, selB, base=2.718281828459045, sparse=False)


Calculates the mutual information S(A:B) between selection components of a system density matrix.
Parameters
rho
[qobj] Density matrix for composite quantum systems
selA
[int/list] int or list of first selected density matrix components.
selB
[int/list] int or list of second selected density matrix components.
base
[{e, 2}, default: e] Base of logarithm.
sparse
[bool, default: False] Use sparse eigensolver.
Returns
ent_mut
[float] Mutual information between selected components.
entropy_relative(rho, sigma, base=2.718281828459045, sparse=False, tol=1e-12)
Calculates the relative entropy S(rho||sigma) between two density matrices.
Parameters
rho
[Qobj] First density matrix (or ket which will be converted to a density matrix).
sigma
[Qobj] Second density matrix (or ket which will be converted to a density matrix).
base
[{e, 2}, default: e] Base of logarithm. Defaults to e.
sparse
[bool, default: False] Flag to use sparse solver when determining the eigenvectors of the
density matrices. Defaults to False.
tol
[float, default: 1e-12] Tolerance to use to detect 0 eigenvalues or dot producted between
eigenvectors. Defaults to 1e-12.
Returns
rel_ent
[float] Value of relative entropy. Guaranteed to be greater than zero and should equal
zero only when rho and sigma are identical.

314 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

References

See Nielsen & Chuang, “Quantum Computation and Quantum Information”, Section 11.3.1, pg. 511 for a
detailed explanation of quantum relative entropy.

Examples

First we define two density matrices:

>>> rho = qutip.ket2dm(qutip.ket("00"))


>>> sigma = rho + qutip.ket2dm(qutip.ket("01"))
>>> sigma = sigma.unit()

Then we calculate their relative entropy using base 2 (i.e. log2) and base e (i.e. log).

>>> qutip.entropy_relative(rho, sigma, base=2)


1.0
>>> qutip.entropy_relative(rho, sigma)
0.6931471805599453

entropy_vn(rho, base=2.718281828459045, sparse=False)


Von-Neumann entropy of density matrix
Parameters
rho
[qobj] Density matrix.
base
[{e, 2}, default: e] Base of logarithm.
sparse
[bool, default: False] Use sparse eigensolver.
Returns
entropy
[float] Von-Neumann entropy of rho.

Examples

>>> rho=0.5*fock_dm(2,0)+0.5*fock_dm(2,1)
>>> entropy_vn(rho,2)
1.0

Density Matrix Metrics

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

5.2. Functions 315


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

316 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

hellinger_dist(A, B, sparse=False, tol=0)


Calculates the quantum Hellinger distance between two density matrices.
Formula:
hellinger_dist(A, B) = sqrt(2 - 2 * tr(sqrt(A) * sqrt(B)))
See: D. Spehner, F. Illuminati, M. Orszag, and W. Roga, “Geometric measures of quantum correlations with
Bures and Hellinger distances” arXiv:1611.03449
Parameters

5.2. Functions 317


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

See V. Vedral and M. B. Plenio, Phys. Rev. A 57, 1619 (1998).


process_fidelity(oper, target=None)
Returns the process fidelity of a quantum channel to the target channel, or to the identity channel if no target
is given. The process fidelity between two channels is defined as the state fidelity between their normalized
Choi matrices.
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/list, optional] A unitary operator, or a superoperator in supermatrix, Choi or chi-
matrix form, or a list of Kraus operators
Returns
fid
[float] Process fidelity between oper and target, or between oper and identity.

318 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 319


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

320 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 321


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Measurement of quantum states

Module for measuring quantum objects.


measure(state, ops, tol=None)
A dispatch method that provides measurement results handling both observable style measurements and
projector style measurements (POVMs and PVMs).
For return signatures, please check:
• measure_observable for observable measurements.
• measure_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 (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.

measure_observable(state, op, tol=None)


Perform a measurement specified by an operator on the given state.
This function simulates the classic quantum measurement described in many introductory texts on quantum
mechanics. The measurement collapses the state to one of the eigenstates of the given operator and the result
of the measurement is the corresponding eigenvalue.
Parameters

322 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Measure the z-component of the spin of the spin-up basis state:

>>> measure_observable(basis(2, 0), sigmaz())


(1.0, Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[-1.]
[ 0.]])

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:

>>> measure_observable(basis(2, 1), sigmax())


(-1.0, Quantum object: dims = [[2], [1]], shape = (2, 1), type = ket
Qobj data =
[[-0.70710678]
[ 0.70710678]])

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:

>>> measure_observable(ket2dm(basis(2, 1)), sigmax())


(-1.0, Quantum object: dims = [[2], [2]], shape = (2, 2), type = oper
Qobj data =
[[ 0.5 -0.5]
[-0.5 0.5]])

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

5.2. Functions 323


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

measurement_statistics_observable(state, op, tol=None)


Return the measurement eigenvalues, eigenstates (or projectors) and measurement probabilities for the given
state and measurement operator.
Parameters
state
[Qobj] The ket or density matrix specifying the state to measure.
op
[Qobj] The measurement operator.

324 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2.4 Dynamics and Time-Evolution

Schrödinger Equation

This module provides solvers for the unitary Schrodinger equation.


sesolve(H, psi0, tlist, e_ops=None, args=None, options=None, **kwargs)
Schrodinger equation evolution of a state vector or unitary matrix for a given Hamiltonian.
Evolve the state vector (psi0) using a given Hamiltonian (H), by integrating the set of ordinary differential
equations that define the system. Alternatively evolve a unitary matrix in solving the Schrodinger operator
equation.
The output is either the state vector or unitary matrix 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. e_ops cannot be used
in conjunction with solving the Schrodinger operator equation
Time-dependent operators

5.2. Functions 325


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

326 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 327


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Monte Carlo Evolution

mcsolve(H, state, tlist, c_ops=(), e_ops=None, ntraj=500, *, args=None, options=None, seeds=None,


target_tol=None, timeout=None, **kwargs)
Monte Carlo evolution of a state vector |𝜓⟩ for a given Hamiltonian and sets of collapse operators. 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.

328 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 329


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Small number used to detect non-physical collapse caused by numerical imprecision.


• improved_sampling : Bool
Whether to use the improved sampling algorithm from Abdelhafez et al. PRA (2019)
Additional options are listed under options. More options may be available depending
on the selected differential equation integration method, see Integrator.
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 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.

330 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 331


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Parameters used in determining whether the given Lindblad operators satisfy a


certain completeness relation. If they do not, an additional Lindblad operator is
added automatically (with zero rate).
• martingale_quad_limit : float or int
An upper bound on the number of subintervals used in the adaptive integration of the
martingale.
Note that the ‘improved_sampling’ option is not currently supported. Additional op-
tions are listed under options. More options may be available depending on the selected
differential equation integration method, see Integrator.
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 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.

Krylov Subspace Solver

krylovsolve(H, psi0, tlist, krylov_dim, e_ops=None, args=None, options=None)


Schrodinger equation evolution of a state vector for time independent Hamiltonians using Krylov method.
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)).
The output is either the state vector or unitary matrix 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. e_ops cannot be used
in conjunction with solving the Schrodinger operator 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)

332 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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].

5.2. Functions 333


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Bloch-Redfield Master Equation

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.

334 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

Floquet States and Floquet-Markov Master Equation

floquet_tensor(H, c_ops, spectra_cb, T=0, w_th=0.0, kmax=5, nT=100)


Construct a tensor that represents the master equation in the floquet basis.
Simplest RWA approximation [Grifoni et al, Phys.Rep. 304 229 (1998)]
Parameters
H
[QobjEvo, FloquetBasis] Periodic Hamiltonian a floquet basis system.
T
[float, optional] The period of the time-dependence of the hamiltonian. Optional if H is
a FloquetBasis object.
c_ops
[list of Qobj] list of collapse operators.

5.2. Functions 335


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

336 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 337


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Stochastic Schrödinger Equation and Master Equation

smesolve(H, rho0, tlist, c_ops=(), sc_ops=(), heterodyne=False, *, e_ops=(), args={}, ntraj=500,


options=None, seeds=None, target_tol=None, timeout=None, **kwargs)
Solve stochastic master 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.
rho0
[Qobj] Initial density matrix or state vector (ket).
tlist
[list / array] List of times for 𝑡.
c_ops
[list of (QobjEvo, QobjEvo compatible format), optional] Deterministic collapse oper-
ator which will contribute with a standard Lindblad type of dissipation.
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 evalu-
ate 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.

338 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

When using a parallel map, the trajectories can be re-ordered.


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 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.

5.2. Functions 339


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

340 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Constructing time dependent systems

coefficient(base, *, tlist=None, args={}, args_ctypes={}, order=3, compile_opt=None,


function_style=None, boundary_conditions=None, **kwargs)
Build Coefficient for time dependent systems:
` QobjEvo = Qobj + Qobj * Coefficient + Qobj * Coefficient + ... `
The coefficients can be a function, a string or a numpy array. Other packages may add support for other kind
of coefficients.
For function based coefficients, the function signature must be either:
• f(t, ...) where the other arguments are supplied as ordinary “pythonic” arguments (e.g. f(t, w,
a=5))
• f(t, args) where the arguments are supplied in a “dict” named args

5.2. Functions 341


QuTiP: Quantum Toolbox in Python, Release 5.0.4

By default the signature style is controlled by the qutip.settings.


core["function_coefficient_style"] setting, but it may be overriden here by specifying either
function_style="pythonic" or function_style="dict".
Examples:
• pythonic style function signature:

def f1_t(t, w):


return np.exp(-1j * t * w)

coeff1 = coefficient(f1_t, args={"w": 1.})

• dict style function signature:

def f2_t(t, args):


return np.exp(-1j * t * args["w"])

coeff2 = coefficient(f2_t, args={"w": 1.})

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:

coeff = coefficient('exp(-1j*w1*t)', args={"w1":1.})

‘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.

342 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Hierarchical Equations of Motion

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 =

5.2. Functions 343


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.
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).
args
[dict, optional] Change the args of the RHS for the evolution.
options
[dict, optional] Generic solver options.
• 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_ados : bool
Whether or not to store the HEOM ADOs.
• 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.
• state_data_type: str {‘dense’, ‘CSR’, ‘Dia’, }
Name of the data type of the state used during the ODE evolution. Use an empty
string to keep the input state type. Many integrator can only work with Dense.
• 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.
Returns

344 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

coherence_function_g1(H, state0, taulist, c_ops, a_op, solver='me', args=None, options=None)


Calculate the normalized first-order quantum coherence function:

⟨𝐴† (𝜏 )𝐴(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.

5.2. Functions 345


QuTiP: Quantum Toolbox in Python, Release 5.0.4

coherence_function_g2(H, state0, taulist, c_ops, a_op, solver='me', args=None, options=None)


Calculate the normalized second-order quantum coherence function:

⟨𝐴† (0)𝐴† (𝜏 )𝐴(𝜏 )𝐴(0)⟩


𝑔 (2) (𝜏 ) =
⟨𝐴† (𝜏 )𝐴(𝜏 )⟩⟨𝐴† (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] List of collapse operators, may be time-dependent for solver choice of me.
a_op
[Qobj] Operator A.
args
[dict, optional] Dictionary of arguments to be passed to solver.
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
g2, G2
[tuple] The normalized and unnormalized second-order coherence function.
correlation_2op_1t(H, state0, taulist, c_ops, a_op, b_op, solver='me', reverse=False, args=None,
options=None)
Calculate the two-operator one-time correlation function: ⟨𝐴(𝜏 )𝐵(0)⟩ along one time axis using the quan-
tum 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.
b_op
[Qobj, QobjEvo] Operator B.

346 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

See, Gardiner, Quantum Noise, Section 5.2.


correlation_2op_2t(H, state0, tlist, taulist, c_ops, a_op, b_op, solver='me', reverse=False, args=None,
options=None)
Calculate the two-operator two-time correlation function: ⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩ along two time axes 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.
tlist
[array_like] List of times for 𝑡. tlist must be positive and contain the element 0. When
taking steady-steady correlations only one tlist value is necessary, i.e. when 𝑡 → ∞.
If tlist is None, tlist=[0] is assumed.
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.
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.

5.2. Functions 347


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

See, Gardiner, Quantum Noise, Section 5.2.


correlation_3op(solver, state0, tlist, taulist, A=None, B=None, C=None)
Calculate the three-operator two-time correlation function:
⟨𝐴(𝑡)𝐵(𝑡 + 𝜏 )𝐶(𝑡)⟩.
from a open system Solver.
Note: it is not possible to calculate a physically meaningful correlation where 𝜏 < 0.
Parameters
solver
[MESolver, BRSolver] Qutip solver for an open system.
state0
[Qobj] Initial state density matrix 𝜌(𝑡0 ) or state vector 𝜓(𝑡0 ).
tlist
[array_like] List of times for 𝑡. tlist must be positive and contain the element 0.
taulist
[array_like] List of times for 𝜏 . taulist must be positive and contain the element 0.
A, B, C
[Qobj, QobjEvo, optional, default=None] Operators A, B, C from the equation
<A(t)B(t+\tau)C(t)> in the Schrodinger picture. They do not need to be all pro-
vided. For exemple, if A is not provided, <B(t+\tau)C(t)> is computed.
Returns
corr_mat
[array] An 2-dimensional array (matrix) of correlation values for the times specified by
tlist (first index) and taulist (second index). If tlist is None, then a 1-dimensional
array of correlation values is returned instead.
correlation_3op_1t(H, state0, taulist, c_ops, a_op, b_op, c_op, solver='me', args=None, options=None)
Calculate the three-operator two-time correlation function: ⟨𝐴(0)𝐵(𝜏 )𝐶(0)⟩ along one time axis using the
quantum regression theorem and the evolution solver indicated by the solver parameter.
Note: it is not possibly to calculate a physically meaningful correlation of this form where 𝜏 < 0.
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.

348 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

See, Gardiner, Quantum Noise, Section 5.2.


correlation_3op_2t(H, state0, tlist, taulist, c_ops, a_op, b_op, c_op, solver='me', args=None,
options=None)
Calculate the three-operator two-time correlation function: ⟨𝐴(𝑡)𝐵(𝑡 + 𝜏 )𝐶(𝑡)⟩ along two time axes using
the quantum regression theorem and the evolution solver indicated by the solver parameter.
Note: it is not possibly to calculate a physically meaningful correlation of this form where 𝜏 < 0.
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.
tlist
[array_like] List of times for 𝑡. tlist must be positive and contain the element 0. When
taking steady-steady correlations only one tlist value is necessary, i.e. when 𝑡 → ∞. If
tlist is None, tlist=[0] is assumed.
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.

5.2. Functions 349


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

See, Gardiner, Quantum Noise, Section 5.2.


spectrum(H, wlist, c_ops, a_op, b_op, solver='es')
Calculate the spectrum of the correlation function lim𝑡→∞ ⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩, i.e., the Fourier transform of the
correlation function:
∫︁ ∞
𝑆(𝜔) = lim ⟨𝐴(𝑡 + 𝜏 )𝐵(𝑡)⟩ 𝑒−𝑖𝜔𝜏 𝑑𝜏.
−∞ 𝑡→∞

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.

350 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

pseudo_inverse(L, rhoss=None, w=None, method='splu', *, use_rcm=False, **kwargs)


Compute the pseudo inverse for a Liouvillian superoperator, optionally given its steady state density matrix
(which will be computed if not given).
Parameters
L
[Qobj] A Liouvillian superoperator for which to compute the pseudo inverse.
rhoss
[Qobj, optional] A steadystate density matrix as Qobj instance, for the Liouvillian su-
peroperator L.
w
[double, optional] frequency at which to evaluate pseudo-inverse. Can be zero for dense
systems and large sparse systems. Small sparse systems can fail for zero frequencies.
sparse
[bool, optional] Flag that indicate whether to use sparse or dense matrix methods when
computing the pseudo inverse.
method
[str, optional] Method used to compte matrix inverse. Choice are ‘pinv’ to use scipy’s
function of the same name, or a linear system solver. Default supported solver are:
• “solve”, “lstsq” dense solver from numpy.linalg
• “spsolve”, “gmres”, “lgmres”, “bicgstab”, “splu” 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
L use these data backends, see the corresponding libraries linalg for available solver.
use_rcm
[bool, default: False] Use reverse Cuthill-Mckee reordering to minimize fill-in in the LU
factorization of the Liouvillian.
kwargs
[dictionary] Additional keyword arguments for setting parameters for solver methods.
Returns

5.2. Functions 351


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

352 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

Calculates the effective steady state for a driven


system with a time-dependent cosinusoidal term:
ˆ0 + 𝒪
ℋ̂(𝑡) = 𝐻 ˆ cos(𝜔𝑑 𝑡)

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.

5.2. Functions 353


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

See: Sze Meng Tan, https://painterlab.caltech.edu/wp-content/uploads/2019/06/qe_quantum_optics_


toolbox.pdf, Section (16)

Propagators

propagator(H, t, c_ops=(), args=None, options=None, **kwargs)


Calculate the propagator U(t) for the density matrix or wave function such that 𝜓(𝑡) = 𝑈 (𝑡)𝜓(0) or 𝜌v𝑒𝑐 (𝑡) =
𝑈 (𝑡)𝜌v𝑒𝑐 (0) where 𝜌v𝑒𝑐 is the vector representation of the density matrix.
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.
t
[float or array-like] Time or list of times for which to evaluate the propagator. If a single
time t is passed, the propagator from 0 to t is computed. When t is a list, the propagators
from the first time in the list to each elements in t is returned. In that case, the first output
will always be the identity matrix.
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.
**kwargs
Extra parameters to use when creating the QobjEvo from a list format H.
Returns
U
[Qobj, list] Instance representing the propagator(s) 𝑈 (𝑡). Return a single Qobj when t
is a number or a list when t is a list.
propagator_steadystate(U)
Find the steady state for successive applications of the propagator 𝑈 .
Parameters
U
[Qobj] Operator representing the propagator.

354 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Returns
a
[Qobj] Instance representing the steady-state density matrix.

Scattering in Quantum Optical Systems

Photon scattering in quantum optical systems


This module includes a collection of functions for numerically computing photon scattering in driven arbitrary sys-
tems coupled to some configuration of output waveguides. The implementation of these functions closely follows
the mathematical treatment given in K.A. Fischer, et. al., Scattering of Coherent Pulses from Quantum Optical
Systems (2017, arXiv:1710.02875).
scattering_probability(H, psi0, n_emissions, c_ops, tlist, system_zero_state=None,
construct_effective_hamiltonian=True)
Compute the integrated probability of scattering n photons in an arbitrary system. This function accepts a
nonlinearly spaced array of times.
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 photons emitted by the system (into any combination of waveguides).
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; tlist need not be linearly spaced.
system_zero_state
[Qobj, optional] State representing zero excitations in the system. Defaults to ba-
sis(systemDims, 0).
construct_effective_hamiltonian
[bool, default: True] Whether
∑︀ an effective Hamiltonian should be constructed from H
and c_ops: 𝐻𝑒𝑓 𝑓 = 𝐻 − 2𝑖 𝑛 𝜎𝑛† 𝜎𝑛 Default: True.
Returns
scattering_prob
[float] The probability of scattering n photons from the system over the time range spec-
ified.
temporal_basis_vector(waveguide_emission_indices, n_time_bins)
Generate a temporal basis vector for emissions at specified time bins into specified waveguides.
Parameters
waveguide_emission_indices
[list or tuple] List of indices where photon emission occurs for each waveguide, e.g.
[[t1_wg1], [t1_wg2, t2_wg2], [], [t1_wg4, t2_wg4, t3_wg4]].
n_time_bins
[int] Number of time bins; the range over which each index can vary.

5.2. Functions 355


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Permutational Invariant Quantum Solver (PIQS)


This module calculates the Liouvillian for the dynamics of ensembles of identical two-level systems (TLS) in the
presence of local and collective processes by exploiting permutational symmetry and using the Dicke basis. It also
allows to characterize nonlinear functions of the density matrix.
am(j, m)
Calculate the operator am used later.
The action of ap is given by: 𝐽− |𝑗, 𝑚⟩ = 𝐴− (𝑗𝑚)|𝑗, 𝑚 − 1⟩
Parameters
j: float
The value for j.
m: float
The value for m.

356 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 357


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

358 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 359


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

360 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

5.2. Functions 361


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

362 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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. Functions 363


QuTiP: Quantum Toolbox in Python, Release 5.0.4

5.2.5 Visualization

Pseudoprobability Functions

qfunc(state: Qobj, xvec, yvec, g: float = 1.4142135623730951, precompute_memory: float = 1024)


Husimi-Q function of a given state vector or density matrix at phase-space points 0.5 * g * (xvec +
i*yvec).
Parameters
state
[Qobj] A state vector or density matrix. This cannot have tensor-product structure.
xvec, yvec
[array_like] x- and y-coordinates at which to calculate the Husimi-Q function.
g
[float, default: sqrt(2)] Scaling factor for a = 0.5 * g * (x + iy). The value of g
is related to the value of ℏ in the commutation relation [𝑥, 𝑦] = 𝑖ℏ via ℏ = 2/𝑔 2 , so the
default corresponds to ℏ = 1.
precompute_memory
[real, default: 1024] Size in MB that may be used during calculations as working space
when dealing with density-matrix inputs. This is ignored for state-vector inputs. The
bound is not quite exact due to other, order-of-magnitude smaller, intermediaries being
necessary, but is a good approximation. If you want to use the same iterative algorithm
for density matrices that is used for single kets, set precompute_memory=None.
Returns
ndarray
Values representing the Husimi-Q function calculated over the specified range [xvec,
yvec].
See also:

QFunc
a class-based version, more efficient if you want to calculate the Husimi-Q function for several states
over the same coordinates.

spin_q_function(rho, theta, phi)


The Husimi Q function for spins is defined as Q(theta, phi) = SCS.dag() * rho * SCS for the spin
coherent state SCS = spin_coherent( j, theta, phi) where j is the spin length. The implementation
here is more efficient as it doesn’t generate all of the SCS at theta and phi (see references).
The spin Q 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 Husimi-Q function.
phi
[array_like] Azimuthal angle at which to calculate the Husimi-Q function.
Returns
Q, THETA, PHI
[2d-array] Values representing the spin Husimi Q function at the values specified by
THETA and PHI.

364 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

[1] Agarwal, G. S. (1981). Phys. Rev. A, 24(6), 2889–2896. https://doi.org/10.1103/PhysRevA.24.2889


[2] Dowling, J. P., Agarwal, G. S., & Schleich, W. P. (1994). Phys. Rev. A, 49(5), 4101–4109. https:
//doi.org/10.1103/PhysRevA.49.4101
[3] Conversion between Wigner 3-j symbol and Clebsch-Gordan coefficients taken from Wikipedia (https:
//en.wikipedia.org/wiki/3-j_symbol)
wigner(psi, xvec, yvec=None, method='clenshaw', g=1.4142135623730951, sparse=False, parfor=False)
Wigner function for a state vector or density matrix at points xvec + i * yvec.
Parameters
state
[qobj] A state vector or density matrix.
xvec
[array_like] x-coordinates at which to calculate the Wigner function.
yvec
[array_like] y-coordinates at which to calculate the Wigner function. Does not apply to
the ‘fft’ method.
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.
method
[string {‘clenshaw’, ‘iterative’, ‘laguerre’, ‘fft’}, default: ‘clenshaw’] Select method
‘clenshaw’ ‘iterative’, ‘laguerre’, or ‘fft’, where ‘clenshaw’ and ‘iterative’ use an iter-
ative method to evaluate the Wigner functions for density matrices |𝑚 >< 𝑛|, while
‘laguerre’ uses the Laguerre polynomials in scipy for the same task. The ‘fft’ method
evaluates the Fourier transform of the density matrix. The ‘iterative’ method is default,

5.2. Functions 365


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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)

Graphs and Visualization

Functions for visualizing results of quantum dynamics simulations, visualizations of quantum states and processes.

hinton(rho, x_basis=None, y_basis=None, color_style='scaled', label_top=True, *, cmap=None,


colorbar=True, fig=None, ax=None)
Draws a Hinton diagram to visualize a density matrix or superoperator.
Parameters
rho
[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.

366 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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

>>> import qutip

>>> dm = qutip.rand_dm(4)
>>> fig, ax = qutip.hinton(dm)
>>> fig.show()

>>> qutip.settings.colorblind_safe = True


>>> fig, ax = qutip.hinton(dm, color_style="threshold")
>>> fig.show()
>>> qutip.settings.colorblind_safe = False

>>> fig, ax = qutip.hinton(dm, color_style="phase")


>>> fig.show()

matrix_histogram(M, 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 a histogram for the matrix M, with the given x and y labels and title.
Parameters
M
[Matrix of Qobj] The matrix to visualize
x_basis
[list of strings, optional] list of x ticklabels

5.2. Functions 367


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

368 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

‘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.

5.2. Functions 369


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

370 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

plot_qubism(ket, theme='light', how='pairs', grid_iteration=1, legend_iteration=0, *, fig=None, ax=None)


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.

Note: colorblind_safe does not apply because of its unique colormap

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

See also [1].

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.

5.2. Functions 371


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Note: colorblind_safe does not apply because of its unique colormap

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.

plot_spin_distribution(P, THETA, PHI, projection='2d', *, cmap=None, colorbar=False, fig=None,


ax=None)
Plots a spin distribution (given as meshgrid data).
Parameters
P
[matrix] 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

372 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 373


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

Special thanks to Russell P Rundle for writing this function.


sphereplot(values, theta, phi, *, cmap=None, colorbar=True, fig=None, ax=None)
Plots a matrix of values on a sphere
Parameters
values
[array] Data set to be plotted
theta
[float] Angle with respect to z-axis. Its range is between 0 and pi
phi
[float] Angle in x-y plane. Its range is between 0 and 2*pi
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 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.
Functions to animate results of quantum dynamics simulations,
anim_fock_distribution(rhos, fock_numbers=None, color='green', unit_y_range=True, *, fig=None,
ax=None)
Animation of the Fock distribution for a density matrix (or ket) that describes an oscillator mode.
Parameters

374 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 375


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

376 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

5.2. Functions 377


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Note: colorblind_safe does not apply because of its unique colormap

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.

378 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Notes

See also [1].

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.

Note: colorblind_safe does not apply because of its unique colormap

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.

anim_sphereplot(V, theta, phi, *, cmap=None, colorbar=True, fig=None, ax=None)


animation of a matrices of values on a sphere
Parameters
V
[list of array instances] Data set to be plotted
theta
[float] Angle with respect to z-axis. Its range is between 0 and pi
phi
[float] Angle in x-y plane. Its range is between 0 and 2*pi
cmap
[a matplotlib colormap instance, optional] Color map to use when plotting.

5.2. Functions 379


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

380 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2. Functions 381


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Returns
fig, ani
[tuple] A tuple of the matplotlib figure and the animation instance used to produce the
figure.

Notes

Special thanks to Russell P Rundle for writing this function.


This module contains utility functions that enhance Matplotlib in one way or another.
complex_phase_cmap()
Create a cyclic colormap for representing the phase of complex variables
Returns
cmap
A matplotlib linear segmented colormap.
wigner_cmap(W, levels=1024, shift=0, max_color='#09224F', mid_color='#FFFFFF', min_color='#530017',
neg_color='#FF97D4', invert=False)
A custom colormap that emphasizes negative values by creating a nonlinear colormap.
Parameters
W
[array] Wigner function array, or any array.
levels
[int, default: 1024] Number of color levels to create.
shift
[float, default: 0] Shifts the value at which Wigner elements are emphasized. This pa-
rameter should typically be negative and small (i.e -1e-5).
max_color
[str, default: ‘#09224F’] String for color corresponding to maximum value of data. Ac-
cepts any string format compatible with the Matplotlib.colors.ColorConverter.
mid_color
[str, default: ‘#FFFFFF’] Color corresponding to zero values. Accepts any string format
compatible with the Matplotlib.colors.ColorConverter.
min_color
[str, default: ‘#530017’] Color corresponding to minimum data values. Accepts any
string format compatible with the Matplotlib.colors.ColorConverter.
neg_color
[str, default: ‘#FF97D4’] Color that starts highlighting negative values. Accepts any
string format compatible with the Matplotlib.colors.ColorConverter.
invert
[bool, default: False] Invert the color scheme for negative values so that smaller negative
values have darker color.
Returns
Returns a Matplotlib colormap instance for use in plotting.

382 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Quantum Process Tomography

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.

5.2. Functions 383


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

5.2.6 Non-Markovian Solvers

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.

384 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• threshold : float Threshold for halting. Halts if ||𝑇𝑛 − 𝑇𝑛−1 || is below treshold.
Returns
output: Result
An instance of the class Result.

5.2.7 Utility Functions

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

5.2. Functions 385


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 I/O Functions

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.

386 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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:

result = [task(value, *task_args, **task_kwargs) for value in values]

Use the loky module instead of multiprocessing.


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.
mpi_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:

5.2. Functions 387


QuTiP: Quantum Toolbox in Python, Release 5.0.4

result = [task(value, *task_args, **task_kwargs) for value in values]

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:

result = [task(value, *task_args, **task_kwargs) for value in values]

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.

388 Chapter 5. API documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

serial_map(task, values, task_args=None, task_kwargs=None, reduce_func=None, map_kw=None,


progress_bar=None, progress_bar_kwargs={})
Serial mapping function with the same call signature as parallel_map, for easy switching between serial and
parallel execution. This is functionally equivalent to:

result = [task(value, *task_args, **task_kwargs) for value in values]

This function work as a drop-in replacement of parallel_map.


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 argument to the task function.
task_kwargs
[dictionary, optional] The optional additional keyword argument to the task function.
reduce_func
[func, optional] If provided, it will be called with the output of each tasks instead of
storing a them in a list. It should return None or a number. When returning a number, it
represent the estimation of the number of task 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.

5.2. Functions 389


QuTiP: Quantum Toolbox in Python, Release 5.0.4

map_kw: dict, optional


Dictionary containing: - timeout: float, Maximum time (sec) for the whole map. -
fail_fast: bool, Raise an error at the first.
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.

IPython Notebook Tools

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.

390 Chapter 5. API documentation


Chapter 6

Change Log

6.1 QuTiP 5.0.4 (2024-08-30)

Micro release to add support for numpy 2.1

6.1.1 Bug Fixes

• Fixed rounding error in dicke_trace_function that resulted in negative eigenvalues. (#2466, by Andrey
Nikitin)

6.2 QuTiP 5.0.3 (2024-06-20)

Micro release to add support for numpy 2.

6.2.1 Bug Fixes

• Bug Fix in Process Matrix Rendering. (#2400, by Anush Venkatakrishnan)


• Fix steadystate permutation being reversed. (#2443)
• Add parallelizing support for vernN methods with mcsolve. (#2454 by Utkarsh)

6.2.2 Documentation

• Added qutip.core.gates to apidoc/functions.rst and a Gates section to guide-states.rst. (#2441, by alan-nala)

6.2.3 Miscellaneous

• Add support for numpy 2 (#2421, #2457)


• Add support for scipy 1.14 (#2469)

391
QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.3 QuTiP 5.0.2 (2024-05-16)

6.3.1 Bug Fixes

• Use CSR as the default for expand_operator (#2380, by BoxiLi)


• Fix import of the partial_transpose function. Ensures that the negativity function can handle both kets and
density operators as input. (#2371, by vikas-chaudhary-2802)
• Ensure that end_condition of mcsolve result doesn’t say target tolerance reached when it hasn’t (#2382, by
magzpavz)
• Fix two bugs in steadystate floquet solver, and adjust tests to be sensitive to this issue. (#2393, by Neill
Lambert)

6.3.2 Documentation

• Correct a mistake in the doc (#2401, by PositroniumJS)


• Fix #2156: Correct a sample of code in the doc (#2409, by PositroniumJS)

6.3.3 Miscellaneous

• Better metadata management in operators creation functions (#2388)


• Implicitly set minimum python version to 3.9 (#2413)
• Qobj.__eq__ uses core’s settings rtol. (#2425)
• Only normalize solver states when the initial state is already normalized. (#2427)

6.4 QuTiP 5.0.1 (2024-04-03)

Patch update fixing small issues with v5.0.0 release


• Fix broken links in the documentation when migrating to readthedocs
• Fix readthedocs search feature
• Add setuptools to runtime compilation requirements
• Fix mcsolve documentation for open systems
• Fix OverFlowError in progress bars

6.5 QuTiP 5.0.0 (2024-03-26)

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.

392 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

An extensive list of changes follows.

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>)

6.5. QuTiP 5.0.0 (2024-03-26) 393


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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>)

394 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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>)

6.5.2 Qobj changes

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.

6.5.3 QobjEvo changes

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.

6.5. QuTiP 5.0.0 (2024-03-26) 395


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

6.5.4 Solver changes

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:

396 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

6.5. QuTiP 5.0.0 (2024-03-26) 397


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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).

398 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.5.5 QuTiP core

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.

6.5.6 QuTiP settings

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. QuTiP 5.0.0 (2024-03-26) 399


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.5.7 Visualization

• Added arguments to plot_wigner and plot_wigner_fock_distribution to specify parameters for


wigner.
• Removed Bloch3D. The same functionality is provided by Bloch.
• Added fig, ax and cmap keyword arguments to all visualization functions.
• Most visualization functions now respect the colorblind_safe setting.
• Added new functions to create animations from a list of Qobj or directly from solver results with saved states.

6.5.8 Package reorganization

• 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.

6.5.10 Feature removals

• 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

400 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.5.11 Changes from QuTiP 5.0.0b1:

6.5.12 Features

• Add dtype to printed ouput of qobj (#2352 by Rochisha Agarwal)

6.5.13 Miscellaneous

• Allow scipy 1.12 to be used with qutip. (#2354 by Pieter Eendebak)

6.6 QuTiP 5.0.0b1 (2024-03-04)

6.6.1 Features

• Create a Dimension class (#1996)


• Add arguments of plot_wigner() and plot_wigner_fock_distribution() to specify parameters for wigner().
(#2057, by Kosuke Mizuno)
• Restore feedback to solvers (#2210)
• Added mpi_pmap, which uses the mpi4py module to run computations in parallel through the MPI interface.
(#2296, by Paul)
• Only pre-compute density matrices if keep_runs_results is False (#2303, by Matt Ord)

6.6.2 Bug Fixes

• 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

• Improve fidelity doc-string (#2257)


• Improve documentation in guide/dynamics (#2271)
• Improve states and operator parameters documentation. (#2289)
• Rework kraus_to_choi making it faster (#2284, by Bogdan Reznychenko)
• Remove Bloch3D: redundant to Bloch (#2306)
• Allow tests to run without matplotlib and ipython. (#2311)
• Add too small step warnings in fixed dt SODE solver (#2313)

6.6. QuTiP 5.0.0b1 (2024-03-04) 401


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• Add dtype to Qobj and QobjEvo (#2325)


• Fix typos in expect documentation (#2331, by gabbence95)
• Allow measurement functions to support degenerate operators. (#2342)

6.7 QuTiP 5.0.0a2 (2023-09-06)

6.7.1 Features

• Add support for different spectra types for bloch_redfield_tensor (#1951)


• Improve qutip import times by setting logger names explicitly. (#1981, by Pieter Eendebak)
• Change the order of parameters in expand_operator (#1991)
• Add svn and solve to dispatched (#2002)
• Added nm_mcsolve to provide support for Monte-Carlo simulations of master equations with possibly nega-
tive rates. The method implemented here is described in arXiv:2209.08958 [quant-ph]. (#2070 by pmenczel)
• Add support for combining bosonic and fermionic HEOM baths (#2089)
• Added __repr__ to QobjEvo (#2111 by lklivingstone)
• Improve print(qutip.settings) by make it shorter (#2113 by tamakoshi2001)
• Create the trace_oper_ket operation (#2126)
• Speed up the construction of the RHS of the HEOM solver by a factor of 4x by converting the final step to
Cython. (#2128)
• Rewrite the stochastic solver to use the v5 solver interface. (#2131)
• Add Qobj.get to extract underlying data in original format. (#2141)
• Add qeye_like and qzero_like (#2153)
• Add capacity to dispatch on Data (#2157)
• Added fermionic annihilation and creation operators. (#2166 by khnikhil)
• Changed arguments and applied colorblind_safe to functions in visualization.py (#2170 by Yuji Tamakoshi)
• Changed arguments and applied colorblind_safe to plot_wigner_sphere and matrix_histogram in visualiza-
tion.py (#2193 by Yuji Tamakoshi)
• Added Dia data layer which represents operators as multi-diagonal matrices. (#2196)
• Added support for animated plots. (#2203 by Yuji Tamakoshi)
• Improved sampling algorithm for mcsolve (#2218 by Daniel Weiss)
• Added support for early termination of map functions. (#2222)

6.7.2 Bug Fixes

• Add missing state transformation to floquet_markov_mesolve (#1952 by christian512)


• Added default _isherm value (True) for momentum and position operators. (#2032 by Asier Galicia)
• Changed qutip-notebooks to qutip-tutorials and fixed the typo in the link redirecting to the changelog section
in the PR template. (#2107 by Valan Baptist Mathuranayagam)
• Increase missing colorbar padding for matrix_histogram_complex() from 0 to 0.05. (#2181 by SJUW)
• Raise error on insufficient memory. (#2224)
• Fixed fallback to fsesolve call in fmmesolve (#2225)

402 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.7.3 Removals

• Remove qutip.control and replace with qutip_qtrl. (#2116)


• Deleted _solve in countstat.py and used _data.solve. (#2120 by Yuji Tamakoshi)
• Deprecate three_level_atom (#2221)
• Deprecate orbital (#2223)

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

• Update scipy version requirement to 1.5+ (#1982 by Pieter Eendebak)


• Added __all__ to qutip/measurements.py and qutip/core/semidefinite.py (#2103 by Rushiraj Gadhvi)
• Restore towncrier check (#2105)
• qutip.ipynbtools.version_table() can now be called without Cython installed (#2110 by Rushiraj Gadhvi)
• Moved HTMLProgressBar from qutip/ipynbtools.py to qutip/ui/progressbar.py (#2112 by Harsh Khilawala)
• Added new argument bc_type to take boundary conditions when creating QobjEvo (#2114 by Avatar Srinidhi
PV)
• Remove Windows build warning suppression. (#2119)
• Optimize dispatcher by dispatching on positional only args. (#2135)
• Clean semidefinite (#2138)
• Migrate transfertensor.py to solver (#2142)
• Add a test for progress_bar (#2150)
• Enable cython 3 (#2151)
• Added tests for visualization.py (#2192 by Yuji Tamakoshi)
• Sorted arguments of sphereplot so that the order is similar to those of plot_spin_distribution (#2219 by Yuji
Tamakoshi)

Version 5.0.0a1 (February 7, 2023)

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.

6.7. QuTiP 5.0.0a2 (2023-09-06) 403


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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>)

404 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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>)

6.7.7 Qobj changes

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.

6.7.8 QobjEvo changes

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.

6.7. QuTiP 5.0.0a2 (2023-09-06) 405


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

6.7.9 Solver changes

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.

406 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

6.7. QuTiP 5.0.0a2 (2023-09-06) 407


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

6.7.10 QuTiP core

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.

6.7.11 QuTiP settings

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"].

408 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.7.12 Package reorganization

• 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.

6.7.14 Feature removals

• 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.

6.8 QuTiP 4.7.5 (2024-01-29)

Patch release for QuTiP 4.7. It adds support for SciPy 1.12.

6.8.1 Bug Fixes

• Remove use of scipy.<numpy-func> in parallel.py, incompatible with scipy==1.12 (#2305 by Evan McKin-
ney)

6.9 QuTiP 4.7.4 (2024-01-15)

6.9.1 Bug Fixes

• Adapt to deprecation from matplotlib 3.8 (#2243, reported by Bogdan Reznychenko)


• Fix name of temp files for removal after use. (#2251, reported by Qile Su)
• Avoid integer overflow in Qobj creation. (#2252, reported by KianHwee-Lim)
• Ignore DeprecationWarning from pyximport (#2287)
• Add partial support and tests for python 3.12. (#2294)

6.8. QuTiP 4.7.5 (2024-01-29) 409


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 QuTiP 4.7.3 (2023-08-22)

6.10.1 Bug Fixes

• Non-oper qobj + scalar raise an error. (#2208 reported by vikramkashyap)


• Fixed issue where extract_states did not preserve hermiticity. Fixed issue where rand_herm did not set the
private attribute _isherm to True. (#2214 by AGaliciaMartinez)
• ssesolve average states to density matrices (#2216 reported by BenjaminDAnjou)

6.10.2 Miscellaneous

• Exclude cython 3.0.0 from requirement (#2204)


• Run in no cython mode with cython >=3.0.0 (#2207)

6.11 QuTiP 4.7.2 (2023-06-28)

This is a bugfix release for QuTiP 4.7.X. It adds support for numpy 1.25 and scipy 1.11.

6.11.1 Bug Fixes

• 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

• Fixed typo in stochastic.py (#2049, by eltociear)


• ptrace always return density matrix (#2185, issue by udevd)
• mesolve can support mixed callable and Qobj for e_ops (#2184 issue by balopat)

410 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 4.7.1 (December 11, 2022)

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

• Improve qutip import times by setting logger names explicitly. (#1980)

6.11.4 Bug Fixes

• 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

• Add towncrier for managing the changelog. (#1927)


• Update the version of numpy used to build documentation to 1.22.0. (#1940)
• Clarify returned objects from bloch_redfield_tensor(). (#1950)
• Update Floquet Markov solver docs. (#1958)
• Update the roadmap and ideas to show completed work as of August 2022. (#1967)

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)

6.11. QuTiP 4.7.2 (2023-06-28) 411


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 4.7.0 (April 13, 2022)

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)

412 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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)

6.11.8 Bug Fixes

• 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)

6.11.9 Documentation Improvements

• Added contributors image to the documentation. (#1828 by Leonard Assis)


• Fixed the Theory of Quantum Information bibliography link. (#1840 by Anto Luketina)
• Fixed minor grammar errors in the dynamics guide. (#1822 by Victor Omole)
• Fixed many small documentation typos. (#1569 by Ashish Panigrahi)
• Added Pulser to the list of libraries that use QuTiP. (#1570 by Ashish Panigrahi)
• Corrected typo in the states and operators guide. (#1567 by Laurent Ajdnik)

6.11. QuTiP 4.7.2 (2023-06-28) 413


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• Converted http links to https. (#1555 by Jake Lishamn)

6.11.10 Developer Changes

• 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)

Version 4.6.3 (February 9, 2022)

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)

414 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.12 Bug Fixes

• 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)

6.11.13 Documentation Improvements

• 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)

6.11. QuTiP 4.7.2 (2023-06-28) 415


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.14 Developer Changes

• 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)

Version 4.6.2 (June 2, 2021)

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)

416 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.16 Bug Fixes

• 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)

6.11.17 Developer Changes

• Read documentation version and release from the VERSION file.

Version 4.6.1 (May 4, 2021)

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

• Add the [full] pip install target (by Jake Lishman)

6.11.19 Bug Fixes

• 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)

6.11.20 Developer Changes

• 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)

6.11. QuTiP 4.7.2 (2023-06-28) 417


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 4.6.0 (April 11, 2021)

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)

6.11.22 Bug Fixes

• 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)

418 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

6.11.24 Developer Changes

• 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)

Version 4.5.3 (February 19, 2021)

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.

6.11. QuTiP 4.7.2 (2023-06-28) 419


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 4.5.2 (July 14, 2020)

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

• Add support for Scipy 1.5. (by Jake Lishman)


• Improved speed of zcsr_inner, which affects Qobj.overlap. (by Jake Lishman)
• Better error messages when installation requirements are not satisfied. (by Eric Giguère)

6.11.27 Bug Fixes

• 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.28 Developer Changes

• Converted more of the codebase to PEP 8.


• Fix several instances of unsafe mutable default values and unsafe is comparisons.

Version 4.5.1 (May 15, 2020)

6.11.29 Improvements

• husimi and wigner now accept half-integer spin (by maij)


• Better error messages for failed string coefficient compilation. (issue raised by nohchangsuk)

6.11.30 Bug Fixes

• Safer naming for temporary files. (by Eric Giguère)


• Fix clebsch function for half-integer (by Thomas Walker)
• Fix randint’s dtype to uint32 for compatibility with Windows. (issue raised by Boxi Li)
• Corrected stochastic’s heterodyne’s m_ops (by eliegenois)
• Mac pool use spawn. (issue raised by goerz)
• Fix typos in QobjEvo._shift. (by Eric Giguère)
• Fix warning on Travis CI. (by Ivan Carvalho)

420 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.31 Deprecations

• qutip.graph functions will be deprecated in QuTiP 5.0 in favour of scipy.sparse.csgraph.

6.11.32 Developer Changes

• Add Boxi Li to authors. (by Alex Pitchford)


• Skip some tests that cause segfaults on Mac. (by Nathan Shammah and Eric Giguère)
• Use Python 3.8 for testing on Mac and Linux. (by Simon Cross and Eric Giguère)

Version 4.5.0 (January 31, 2020)

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. QuTiP 4.7.2 (2023-06-28) 421


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.34 Bug Fixes

• Fixed PolyDataMapper construction for Bloch3d (by Sam Griffiths).


• Fixed error checking for null matrix in essolve (by Nathan Shammah).
• Fixed name collision for parallel propagator (by Nathan Shammah).
• Fixed dimensional incongruence in propagator (by Nathan Shammah)
• Fixed bug by rewriting clebsch function based on long integer fraction (by Eric Giguère).
• Fixed bugs in QobjEvo’s args depending on state and added solver tests using them (by Eric Giguère).
• Fixed bug in sesolve calculation of average states when summing the timeslot states (by Alex Pitchford).
• Fixed bug in steadystate solver by removing separate arguments for MKL and Scipy (by Tarun Raheja).
• Fixed Bloch.add_ponts by setting edgecolor = None in plot_points (by Nathan Shammah).
• Fixed error checking for null matrix in essolve solver affecting also ode2es (by Peter Kirton).
• Removed unnecessary shebangs in .pyx and .pxd files (by Samesh Lakhotia).
• Fixed sesolve and import of os in codegen (by Alex Pitchford).
• Updated plot_fock_distribution by removing the offset value 0.4 in the plot (by Rajiv-B).

Version 4.4.1 (August 29, 2019)

6.11.35 Improvements

• QobjEvo do not need to start from 0 anymore (by Eric Giguère).


• Add a quantum object purity function (by Nathan Shammah and Shahnawaz Ahmed).
• Add step function interpolation for array time-coefficient (by Boxi Li).
• Generalize expand_oper for arbitrary dimensions, and new method for cyclic permutations of given target
cubits (by Boxi Li).

6.11.36 Bug Fixes

• 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).

422 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 4.4.0 (July 03, 2019)

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.38 Bug Fixes

• Fixed bug that made QuTiP incompatible with SciPy 1.3.

Version 4.3.0 (July 14, 2018)

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. QuTiP 4.7.2 (2023-06-28) 423


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.40 Bug Fixes

• Fixed bug that stopped simdiag working for python 3.


• Fixed semidefinite cvxpy Variable and Parameter.
• Fixed iterative lu solve atol keyword issue.
• Fixed unitary op evolution rhs matrix in ssesolve.
• Fixed interpolating function to return zero outside range.
• Fixed dnorm complex casting bug.
• Fixed control.io path checking issue.
• Fixed ENR fock dimension.
• Fixed hard coded options in propagator ‘batch’ mode
• Fixed bug in trace-norm for non-Hermitian operators.
• Fixed bug related to args not being passed to coherence_function_g2
• Fixed MKL error checking dict key error

Version 4.2.0 (July 28, 2017)

6.11.41 Improvements

• MAJOR FEATURE: Initial implementation of time-dependent Bloch-Redfield Solver.


• Qobj tidyup is now an order of magnitude faster.
• Time-dependent codegen now generates output NumPy arrays faster.
• Improved calculation for analytic coefficients in coherent states (Sebastian Kramer).
• Input array to correlation FFT method now checked for validity.
• Function-based time-dependent mesolve and sesolve routines now faster.
• Codegen now makes sure that division is done in C, as opposed to Python.
• Can now set different controls for a each timeslot in quantum optimization. This allows time-varying controls
to be used in pulse optimisation.

6.11.42 Bug Fixes

• rcsolve importing old Odeoptions Class rather than Options.


• Non-int issue in spin Q and Wigner functions.
• Qobj’s should tidyup before determining isherm.
• Fixed time-dependent RHS function loading on Win.
• Fixed several issues with compiling with Cython 0.26.
• Liouvillian superoperators were hard setting isherm=True by default.
• Fixed an issue with the solver safety checks when inputing a list with Python functions as time-dependence.
• Fixed non-int issue in Wigner_cmap.
• MKL solver error handling not working properly.

424 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 4.1.0 (March 10, 2017)

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.

6.11.44 Bug Fixes

• Cleanup of temp. Cython files now more robust and working under Windows.

Version 4.0.2 (January 5, 2017)

6.11.45 Bug Fixes

• td files no longer left behind by correlation tests


• Various fast sparse fixes

Version 4.0.0 (December 22, 2016)

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

6.11. QuTiP 4.7.2 (2023-06-28) 425


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.47 Bug Fixes

• recompilation of pyx files on first import removed


• tau array in control.pulseoptim funcs now works

Version 3.2.0 (Never officially released)

6.11.48 New Features

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

426 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

6.11. QuTiP 4.7.2 (2023-06-28) 427


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.50 Bug Fixes

• Fixes for countstat and psuedo-inverse functions


• Fixed Qobj division tests on 32-bit systems.
• Removed extra call to Python in time-dependent Cython code.
• Fixed issue with repeated Bloch sphere saving.
• Fixed T_0 triplet state not normalized properly. (Fixed by Eric Hontz)
• Simplified compiler flags (support for ARM systems).
• Fixed a decoding error in qload.
• Fixed issue using complex.h math and np.kind_t variables.
• Corrected output states mismatch for ntraj=1 in the mcf90 solver.
• Qobj data is now copied by default to avoid a bug in multiplication. (Fixed by Richard Brierley)
• Fixed bug overwriting hardware_info in __init__. (Fixed by Johannes Feist)
• Restored ability to explicity set Q.isherm, Q.type, and Q.superrep.
• Fixed integer depreciation warnings from NumPy.
• Qobj * (dense vec) would result in a recursive loop.
• Fixed args=None -> args={} in correlation functions to be compatible with mesolve.
• Fixed depreciation warnings in mcsolve.
• Fixed neagtive only real parts in rand_ket.
• Fixed a complicated list-cast-map-list antipattern in super operator reps. (Fixed by Stefan Krastanov)
• Fixed incorrect isherm for sigmam spin operator.
• Fixed the dims when using final_state_output in mesolve and sesolve.

Version 3.1.0 (January 1, 2015)

6.11.51 New Features

• MAJOR FEATURE: New module for quantum control (qutip.control).


• NAMESPACE CHANGE: QuTiP no longer exports symbols from NumPy and matplotlib, so those modules
must now be explicitly imported when required.
• New module for counting statistics.
• Stochastic solvers now run trajectories in parallel.
• New superoperator and tensor manipulation functions (super_tensor, composite, tensor_contract).
• New logging module for debugging (qutip.logging).
• New user-available API for parallelization (parallel_map).
• New enhanced (optional) text-based progressbar (qutip.ui.EnhancedTextProgressBar)
• Faster Python based monte carlo solver (mcsolve).
• Support for progress bars in propagator function.
• Time-dependent Cython code now calls complex cmath functions.
• Random numbers seeds can now be reused for successive calls to mcsolve.
• The Bloch-Redfield master equation solver now supports optional Lindblad type collapse operators.

428 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• Improved handling of ODE integration errors in mesolve.


• Improved correlation function module (for example, improved support for time-dependent problems).
• Improved parallelization of mcsolve (can now be interrupted easily, support for IPython.parallel, etc.)
• Many performance improvements, and much internal code restructuring.

6.11.52 Bug Fixes

• 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.

Version 3.0.1 (Aug 5, 2014)

6.11.53 Bug Fixes

• 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.

Version 3.0.0 (July 17, 2014)

6.11.54 New Features

• 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.

6.11. QuTiP 4.7.2 (2023-06-28) 429


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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).

430 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Version 2.2.0 (March 01, 2013)

6.11.56 New Features

• Added Support for Windows


• New Bloch3d class for plotting 3D Bloch spheres using Mayavi.
• Bloch sphere vectors now look like arrows.
• Partial transpose function.
• Continuos variable functions for calculating correlation and covariance matrices, the Wigner covariance
matrix and the logarithmic negativity for for multimode fields in Fock basis.
• The master-equation solver (mesolve) now accepts pre-constructed Liouvillian terms, which makes it possi-
ble to solve master equations that are not on the standard Lindblad form.
• Optional Fortran Monte Carlo solver (mcsolve_f90) by Arne Grimsmo.
• A module of tools for using QuTiP in IPython notebooks.
• Increased performance of the steady state solver.
• New Wigner colormap for highlighting negative values.
• More graph styles to the visualization module.

6.11.57 Bug Fixes

• Function based time-dependent Hamiltonians now keep the correct phase.


• mcsolve no longer prints to the command line if ntraj=1.

Version 2.1.0 (October 05, 2012)

6.11.58 New Features

• New method for generating Wigner functions based on Laguerre polynomials.


• coherent(), coherent_dm(), and thermal_dm() can now be expressed using analytic values.
• Unittests now use nose and can be run after installation.
• Added iswap and sqrt-iswap gates.
• Functions for quantum process tomography.
• Window icons are now set for Ubuntu application launcher.
• The propagator function can now take a list of times as argument, and returns a list of corresponding propa-
gators.

6.11.59 Bug Fixes

• mesolver now correctly uses the user defined rhs_filename in Odeoptions().


• rhs_generate() now handles user defined filenames properly.
• Density matrix returned by propagator_steadystate is now Hermitian.
• eseries_value returns real list if all imag parts are zero.
• mcsolver now gives correct results for strong damping rates.
• Odeoptions now prints mc_avg correctly.

6.11. QuTiP 4.7.2 (2023-06-28) 431


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• Do not check for PyObj in mcsolve when gui=False.


• Eseries now correctly handles purely complex rates.
• thermal_dm() function now uses truncated operator method.
• Cython based time-dependence now Python 3 compatible.
• Removed call to NSAutoPool on mac systems.
• Progress bar now displays the correct number of CPU’s used.
• Qobj.diag() returns reals if operator is Hermitian.
• Text for progress bar on Linux systems is no longer cutoff.

Version 2.0.0 (June 01, 2012)

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:

6.11.60 New Features

• 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.

Important: This breaks compatibility with QuTiP version 1.x.

• 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.

432 Chapter 6. Change Log


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• QuTiP includes a collection of unit tests for verifying the installation.


• Demos window now lets you copy and paste code from each example.

Version 1.1.4 (May 28, 2012)

6.11.61 Bug Fixes

• Fixed bug pointed out by Brendan Abolins.


• Qobj.tr() returns zero-dim ndarray instead of float or complex.
• Updated factorial import for scipy version 0.10+

Version 1.1.3 (November 21, 2011)

6.11.62 New Functions

• Allow custom naming of Bloch sphere.

6.11.63 Bug Fixes

• Fixed text alignment issues in AboutBox.


• Added fix for SciPy V>0.10 where factorial was moved to scipy.misc module.
• Added tidyup function to tensor function output.
• Removed openmp flags from setup.py as new Mac Xcode compiler does not recognize them.
• Qobj diag method now returns real array if all imaginary parts are zero.
• Examples GUI now links to new documentation.
• Fixed zero-dimensional array output from metrics module.

Version 1.1.2 (October 27, 2011)

6.11.64 Bug Fixes

• Fixed issue where Monte Carlo states were not output properly.

Version 1.1.1 (October 25, 2011)

THIS POINT-RELEASE INCLUDES VASTLY IMPROVED TIME-INDEPENDENT MCSOLVE AND


ODESOLVE PERFORMANCE

6.11.65 New Functions

• Added linear entropy function.


• Number of CPU’s can now be changed.

6.11. QuTiP 4.7.2 (2023-06-28) 433


QuTiP: Quantum Toolbox in Python, Release 5.0.4

6.11.66 Bug Fixes

• Metrics no longer use dense matrices.


• Fixed Bloch sphere grid issue with matplotlib 1.1.
• Qobj trace operation uses only sparse matrices.
• Fixed issue where GUI windows do not raise to front.

Version 1.1.0 (October 04, 2011)

THIS RELEASE NOW REQUIRES THE GCC COMPILER TO BE INSTALLED

6.11.67 New Functions

• tidyup function to remove small elements from a Qobj.


• Added concurrence function.
• Added simdiag for simultaneous diagonalization of operators.
• Added eigenstates method returning eigenstates and eigenvalues to Qobj class.
• Added fileio for saving and loading data sets and/or Qobj’s.
• Added hinton function for visualizing density matrices.

6.11.68 Bug Fixes

• Switched Examples to new Signals method used in PySide 1.0.6+.


• Switched ProgressBar to new Signals method.
• Fixed memory issue in expm functions.
• Fixed memory bug in isherm.
• Made all Qobj data complex by default.
• Reduced ODE tolerance levels in Odeoptions.
• Fixed bug in ptrace where dense matrix was used instead of sparse.
• Fixed issue where PyQt4 version would not be displayed in about box.
• Fixed issue in Wigner where xvec was used twice (in place of yvec).

Version 1.0.0 (July 29, 2011)

• Initial release.

434 Chapter 6. Change Log


Chapter 7

Developers

435
QuTiP: Quantum Toolbox in Python, Release 5.0.4

7.1 Lead Developers

• Alex Pitchford
• Nathan Shammah
• Shahnawaz Ahmed
• Neill Lambert
• Eric Giguère
• Boxi Li
• Simon Cross
• Asier Galicia

7.2 Past Lead Developers

• Robert Johansson (RIKEN)


• Paul Nation (Korea University)
• Chris Granade
• Arne Grimsmo
• Jake Lishman

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

436 Chapter 7. Developers


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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

7.3. Contributors 437


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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

438 Chapter 7. Developers


Chapter 8

Development Documentation

This chapter covers the development of QuTiP and its subpackages, including a roadmap for upcoming releases
and ideas for future improvements.

8.1 Contributing to QuTiP Development

8.1.1 Quick Start

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.

8.1.2 Core Library: qutip/qutip

The core library is in the qutip/qutip repository on GitHub.

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

conda create -n qutip-dev python

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 that qutip should not be installed with conda install.

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

python setup.py develop

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.

440 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

pytest qutip/tests/test_qobj.py -k "expm"

to run the tests of Qobj.expm.

8.1. Contributing to QuTiP Development 441


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

8.1.3 Documentation: qutip/qutip (doc directory)

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

conda create -n qutip-doc python=3.8

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

pip install -r requirements.txt

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

python setup.py develop

in the main library repository.


The documentation is built by running the make command. There are several targets to build, but the most useful
will be html to build the webpage documentation, latexpdf to build the PDF documentation (you will also need

442 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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 QuTiP Development Roadmap

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.

8.2. QuTiP Development Roadmap 443


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

8.2.2 Library package structure

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

• current package status: family package qutip


• planned package status: family package qutip
The in-scope components of the main qutip package all currently reside in the base folder. The plan is to move
some components into integrated subpackages as follows:
• core quantum objects and operations
• solver quantum dynamics solvers
What will remain in the base folder will be miscellaneous modules. There may be some opportunity for grouping
some into a visualisation subpackage. There is also some potential for renaming, as some module names have
underscores, which is unconventional.

444 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Qtrl

• current package status: integrated sub-package qutip.control


• planned package status: family package qtrl
There are many OSS Python packages for quantum control optimisation. There are also many different algorithms.
The current control integrated subpackage provides the GRAPE and CRAB algorithms. It is too ambitious for
QuTiP to attempt (or want) to provide for all options. Control optimisation has been deemed out of scope and
hence these components will be separated out into a family package called Qtrl.
Potentially Qtrl may be replaced by separate packages for GRAPE and CRAB, based on the QuTiP Control Frame-
work.

QIP

• current package status: integrated sub-package qutip.qip


• planned package status: family package qutip-qip
The QIP subpackage has been deemed out of scope (feature-wise). It also depends on qutip.control and hence
would be out of scope for dependency reasons. A separate repository has already been made for qutip-qip.

qutip-symbolic

• current package status: independent package sympsi


• planned package status: family package qutip-symbolic
Long ago Robert Johansson and Eunjong Kim developed Sympsi. It is a fairly coomplete library for quantum
computer algebra (symbolic computation). It is primarily a quantum wrapper for Sympy.
It has fallen into unmaintained status. The latest version on the sympsi repo does not work with recent versions of
Sympy. Alex Pitchford has a fork that does ‘work’ with recent Sympy versions – unit tests pass, and most examples
work. However, some (important) examples fail, due to lack of respect for non-commuting operators in Sympy
simplifcation functions (note this was true as of Nov 2019, may be fixed now).
There is a [not discussed with RJ & EK] plan to move this into the QuTiP family to allow the Admin Team to
maintain, develop and promote it. The ‘Sympsi’ name is cute, but a little abstract, and qutip-symbolic is proposed
as an alternative, as it is plainer and more distinct from Sympy.

Affilliated packages

qucontrol-krotov

• code repository: https://github.com/qucontrol/krotov


A package for quantum control optimisation using Krotov, developed mainly by Michael Goerz.
Generally accepted by the Admin Team as well developed and maintained. A solid candiate for affilliation.

8.2. QuTiP Development Roadmap 445


QuTiP: Quantum Toolbox in Python, Release 5.0.4

8.2.3 Development Projects

Solver data layer integration

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.

QuTiP control framework

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

446 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

Status messaging and recording

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

8.2. QuTiP Development Roadmap 447


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• Python logging used in qutip.control


• Dump used in qutip.control
• heom records solver.Stats
Some consolidation of these would be good.
Some processes (some solvers, correlation, control optimisation) have many stages and many layers. Dump was
initially developed to help with debugging, but it is also useful for recording data for analysis. qutip.logging_utils
has been criticised for the way it uses Python logging. The output goes to stderr and hence the output looks like
errors in Jupyter notebooks.
Clearly, storing process stage data is costly in terms of memory and cpu time, so any implementation must be able
to be optionally switched on/off, and avoided completely in low-level processes (cythonized components).
Required features:
• optional recording (storing) of process stage data (states, operators etc)
• optionally write subsets to stdout
• maybe other graphical representations
• option to save subsets to file
• should ideally replace use of ProgressBar, Python logging, control.Dump, solver.Stats

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:

Interactive Bloch sphere

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.

448 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

8.2.4 Completed Development Projects

data layer abstraction

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.

qutip main reorganization

tag
qmain-reorg
status
completed
admin lead
Eric
main dev
Jake Lishman
Reorganise qutip main components to the structure described above.

8.2. QuTiP Development Roadmap 449


QuTiP: Quantum Toolbox in Python, Release 5.0.4

qutip user docs migration

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.

450 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

8.2.5 QuTiP major release roadmap

QuTiP v.5

These Projects need to be completed for the qutip v.5 release.


• data layer abstraction (completed)
• qutip main reorganization (completed)
• qutip user docs migration (completed)
• Solver data layer integration (in-progress)
• QIP migration (completed)
• Qtrl migration
• HEOM revamp (completed)
The planned timeline for the release is:
• alpha version, December 2022. Core features packaged and available for experienced users to test.
• beta version, January 2023. All required features and documentation complete, packaged and ready for
community testing.
• full release, April 2023. Full tested version released.
Planned supported environment:
• python 3.8 .. 3.11
• numpy 1.20 .. 1.23
• scipy 1.5 .. 1.8

8.3 Ideas for future QuTiP development

Ideas for significant new features are listed here. For the general roadmap, see QuTiP Development Roadmap.

8.3.1 QuTiP Interactive

Contents

• Interactive Bloch sphere


• Interactive solvers
• Animated circuits
– Expected outcomes
– Skills
– Difficulty
– Mentors

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:

8.3. Ideas for future QuTiP development 451


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Interactive Bloch sphere

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

• Interactive graphical components for demonstrating quantum dynamics


• Web pages for qutip.org or Jupyter notebooks introducing quantum dynamics using the new components

Skills

• Git, Python and familiarity with the Python scientific computing stack
• elementary understanding of quantum dynamics

Difficulty

• Variable

Mentors

• Nathan Shammah ([email protected])


• Alex Pitchford ([email protected])
• Simon Cross ([email protected])
• Boxi Li ([email protected]) [QuTiP GSoC 2019 graduate]

8.3.2 Pulse level description of quantum circuits

Contents

• Expected outcomes
• Skills
• Difficulty
• Mentors

452 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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

• Boxi Li ([email protected]) [QuTiP GSoC 2019 graduate]


• Nathan Shammah ([email protected])
• Alex Pitchford ([email protected])
1 McKay D C, Alexander T, Bello L, et al. Qiskit backend specifications for openqasm and openpulse experiments[J]. arXiv preprint

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.

8.3. Ideas for future QuTiP development 453


QuTiP: Quantum Toolbox in Python, Release 5.0.4

References

8.3.3 Quantum Error Mitigation

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

454 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Skills

• Background in quantum physics and quantum circuits.


• Git, python and familiarity with the Python scientific computing stack

Difficulty

• Medium

Mentors

• Nathan Shammah ([email protected])


• Alex Pitchford ([email protected])
• Eric Giguère ([email protected])
• Neill Lambert ([email protected])
• Boxi Li ([email protected]) [QuTiP GSoC 2019 graduate]

References

8.3.4 GPU implementation of the Hierarchical Equations of Motion

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

8.3. Ideas for future QuTiP development 455


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Expected outcomes

• A version of HEOM which runs on a GPU.


• Performance comparison with the CPU version.
• Implement dynamic scaling.

Skills

• Git, python and familiarity with the Python scientific computing stack
• CUDA and OpenCL knowledge

Difficulty

• Hard

Mentors

• Neill Lambert ([email protected])


• Alex Pitchford ([email protected])
• Shahnawaz Ahmed ([email protected])
• Simon Cross ([email protected])

References

8.3.5 Google Summer of Code

Many possible extensions and improvements to QuTiP have been documented as part of Google Summer of Code:
• GSoC 2021
• GSoC 2022

8.3.6 Completed Projects

These projects have been completed:

TensorFlow Data Backend

Contents

• Why a TensorFlow backend?


• Challenges
– Expected outcomes
– Skills
– Difficulty
– Mentors
– References

456 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Note: This project was completed as part of GSoC 20213 .

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 .

Why a TensorFlow backend?

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

• Add a qutip.core.data.tensorflow data type.


• Implement specialisations for some important operations (e.g. add, mul, matmul, eigen, etc).
• Write a small benchmark to show how Qobj operations scale on the new backend in comparison to the
existing backends. Run the benchmark both with and without using a GPU.
• Implement enough for a solver to run on top of the new TensorFlow data backend and benchmark that (stretch
goal).

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

8.3. Ideas for future QuTiP development 457


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Difficulty

• Medium

Mentors

• Simon Cross ([email protected])


• Jake Lishman ([email protected])
• Alex Pitchford ([email protected])

References

8.4 Working with the QuTiP Documentation

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

This is rendered in the documentation as follows:

>>> 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:

458 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

.. 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)

A few notes on using the doctest extension:


• By default, each testcode and doctest block is run in a fresh namespace. To share a common namespace,
we can specify a common group across the blocks (within a single .rst file). For example,

.. 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:

8.4. Working with the QuTiP Documentation 459


QuTiP: Quantum Toolbox in Python, Release 5.0.4

First we specify some data:

.. plot::

>>> import numpy as np


>>> x = np.linspace(0, 2 * np.pi, 1000)
>>> x[:10] # doctest: +NORMALIZE_WHITESPACE
array([ 0. , 0.00628947, 0.01257895, 0.01886842, 0.0251579 ,
0.03144737, 0.03773685, 0.04402632, 0.0503158 , 0.05660527])

.. plot::
:context:

>>> import matplotlib.pyplot as plt


>>> plt.plot(x, np.sin(x))
[...]

Note the use of the NORMALIZE_WHITESPACE option to ensure that the multiline output matches.
Render:

>>> import numpy as np


>>> x = np.linspace(0, 2 * np.pi, 1000)
>>> x[:10]
array([ 0. , 0.00628947, 0.01257895, 0.01886842, 0.0251579 ,
0.03144737, 0.03773685, 0.04402632, 0.0503158 , 0.05660527])
>>> import matplotlib.pyplot as plt
>>> plt.plot(x, np.sin(x))
[...]

460 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

A few notes on using the plot directive:


• A useful argument to specify in plot blocks is that of context which ensures that the code is being run in
the namespace of the previous plot block within the same file.
• By default, each rendered figure in one plot block (when using :context:) is carried over to the next block.
• When the context argument is specified with the reset option as :context: reset, the namespace is
reset to a new one and all figures are erased.
• When the context argument is specified with the close-figs option as :context: reset, the names-
pace is reset to a new one and all figures are erased.
The Plot directive cannot be used in conjunction with Doctest because they do not share the same namespace when
used in the same file. Since Plot can also be used in doctest mode, in the case where code examples require both
testing and rendering figures, it is easier to use the Plot directive. To learn more about each directive, it is useful
to refer to their individual pages.

8.5 Release and Distribution

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).

8.5. Release and Distribution 461


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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).

8.5.2 Setting Up The Release Branch

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.

Updating the Requirements

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.

Updating the Changelog

This needs to be done no matter what type of release is being made.


1. Create a new branch to use to make a pull request.
2. Update the changelog using towncrier:
towncrier build –version=<version-number>
Where <version-number> is the expected version number of the release
1. Make a pull request on the main qutip/qutip repository with this changelog, and get other members of
the admin team to approve it.
2. Merge this into master.

462 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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.

Create a New Minor or Major 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

Development Status :: 5 - Production/Stable

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

Development Status :: 2 - Pre-Alpha

because master is never directly released.


You should now have a branch that you can see on the GitHub website that is called qutip-4.7.X (or whatever
minor version), and the state of the code in it should be exactly what you want to release as the new minor release.
If you notice you have made a mistake, you can make additional pull requests to the release branch to fix it. master
should look pretty similar, except the VERSION will be higher and have a .dev suffix, and the “Development Status”
in setup.cfg will be different.
• Activate the readthedocs build for the newly created version branch and set it as the latest.
You are now ready to actually perform the release. Go to deploy.

8.5. Release and Distribution 463


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Create a Bug Fix Release

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.

464 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

8.5.3 Build Release Distribution and 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.

Build and Deploy

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.

8.5. Release and Distribution 465


QuTiP: Quantum Toolbox in Python, Release 5.0.4

Download Built Files

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.

Monitoring Progress (optional)

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.

8.5.4 Making a Release on GitHub

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”.

466 Chapter 8. Development Documentation


QuTiP: Quantum Toolbox in Python, Release 5.0.4

• 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.

HTML File Updates

• 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.

8.5.6 Conda Forge

If not done previously then fork the qutip-feedstock.


Checkout a new branch on your fork, e.g.

$ git checkout -b version-4.0.2

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

$ openssl sha256 qutip-4.0.2.tar.gz

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

8.5. Release and Distribution 467


QuTiP: Quantum Toolbox in Python, Release 5.0.4

build:
number: 0

Push changes to your fork, e.g.

$ git push --set-upstream origin version-4.0.2

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

$ conda config --append channels conda-forge

This should mean that the prerequistes come from the default channel, but the qutip packages are found in conda-
forge.

468 Chapter 8. Development Documentation


Chapter 9

Bibliography

469
QuTiP: Quantum Toolbox in Python, Release 5.0.4

470 Chapter 9. Bibliography


Chapter 10

Copyright and Licensing

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.

10.1 License Terms for Documentation Text

The canonical form of this license is available at https://creativecommons.org/licenses/by/3.0/, which should be


considered the binding version of this license. It is reproduced here for convenience.
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS
PUBLIC LICENSE (“CCPL” OR “LICENSE”). THE WORK IS PROTECTED BY COPYRIGHT AND/OR
OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS
LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE
BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED
TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDER-
ATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
a. “Adaptation” means a work based upon the Work, or upon the Work and other pre-existing works, such
as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or
artistic work, or phonogram or performance and includes cinematographic adaptations or any other
form in which the Work may be recast, transformed, or adapted including in any form recognizably
derived from the original, except that a work that constitutes a Collection will not be considered an
Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical
work, performance or phonogram, the synchronization of the Work in timed-relation with a moving
image (“synching”) will be considered an Adaptation for the purpose of this License.
b. “Collection” means a collection of literary or artistic works, such as encyclopedias and anthologies,
or performances, phonograms or broadcasts, or other works or subject matter other than works listed
in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute
intellectual creations, in which the Work is included in its entirety in unmodified form along with one
or more other contributions, each constituting separate and independent works in themselves, which
together are assembled into a collective whole. A work that constitutes a Collection will not be con-
sidered an Adaptation (as defined above) for the purposes of this License.
c. “Distribute” means to make available to the public the original and copies of the Work or Adaptation,
as appropriate, through sale or other transfer of ownership.
d. “Licensor” means the individual, individuals, entity or entities that offer(s) the Work under the terms
of this License.

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;

472 Chapter 10. Copyright and Licensing


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

10.1. License Terms for Documentation Text 473


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

474 Chapter 10. Copyright and Licensing


QuTiP: Quantum Toolbox in Python, Release 5.0.4

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

476 Chapter 10. Copyright and Licensing


Chapter 11

Indices and tables

• genindex
• modindex
• search

477
QuTiP: Quantum Toolbox in Python, Release 5.0.4

478 Chapter 11. Indices and tables


Bibliography

[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

482 Python Module Index


Index

Symbols brmesolve() (in module qutip.solver.brmesolve), 334


__call__() (Propagator method), 220 BRSolver (class in qutip.solver.brmesolve), 213
__call__() (Qobj method), 189 bures_angle() (in module qutip.core.metrics), 316
__call__() (QobjEvo method), 200 bures_dist() (in module qutip.core.metrics), 316

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

correlation_3op() (in module enr_fock() (in module qutip.core.energy_restricted),


qutip.solver.correlation), 348 299
correlation_3op_1t() (in module enr_identity() (in module
qutip.solver.correlation), 348 qutip.core.energy_restricted), 299
correlation_3op_2t() (in module enr_state_dictionaries() (in module
qutip.solver.correlation), 349 qutip.core.energy_restricted), 300
correlation_matrix() (in module enr_thermal_dm() (in module
qutip.continuous_variables), 320 qutip.core.energy_restricted), 300
correlation_matrix_field() (in module entropy_conditional() (in module qutip.entropy),
qutip.continuous_variables), 320 313
correlation_matrix_quadrature() (in module entropy_linear() (in module qutip.entropy), 313
qutip.continuous_variables), 320 entropy_mutual() (in module qutip.entropy), 314
cosm() (Qobj method), 189 entropy_relative() (in module qutip.entropy), 314
covariance_matrix() (in module entropy_vn() (in module qutip.entropy), 315
qutip.continuous_variables), 321 entropy_vn_dicke() (in module qutip.piqs.piqs),
cphase() (in module qutip.core.gates), 293 359
create() (in module qutip.core.operators), 280 EulerSODE (class in qutip.solver.sode.itotaylor), 253
cs_gate() (in module qutip.core.gates), 293 excited() (in module qutip.piqs.piqs), 360
csign() (in module qutip.core.gates), 293 expect() (in module qutip.core.expect), 311
css() (in module qutip.piqs.piqs), 358 expect() (QobjEvo method), 201
ct_gate() (in module qutip.core.gates), 293 expect_data() (QobjEvo method), 202
current_martingale() (NonMarkovianMCSolver ExpectFeedback() (BRSolver class method), 214
method), 225 ExpectFeedback() (FMESolver class method), 217
cy_gate() (in module qutip.core.gates), 294 ExpectFeedback() (MCSolver class method), 221
cz_gate() (in module qutip.core.gates), 294 ExpectFeedback() (MESolver class method), 211
ExpectFeedback() (NonMarkovianMCSolver class
D method), 225
dag() (Qobj method), 190 ExpectFeedback() (SESolver class method), 209
dag() (QobjEvo method), 201 ExpectFeedback() (SMESolver class method), 242
data_as() (Qobj method), 190 ExpectFeedback() (SSESolver class method), 245
destroy() (in module qutip.core.operators), 281 Explicit1_5_SODE (class in
diag() (Qobj method), 190 qutip.solver.sode.itotaylor), 255
Dicke (class in qutip.piqs.piqs), 261 expm() (Qobj method), 192
dicke() (in module qutip.piqs.piqs), 358 exps() (HierarchyADOs method), 239
dicke_basis() (in module qutip.piqs.piqs), 358 extract() (HierarchyADOsState method), 241
dicke_blocks() (in module qutip.piqs.piqs), 359
dicke_blocks_full() (in module qutip.piqs.piqs), F
359 fcreate() (in module qutip.core.operators), 282
dicke_function_trace() (in module fdestroy() (in module qutip.core.operators), 283
qutip.piqs.piqs), 359 FermionicBath (class in qutip.solver.heom), 236
displace() (in module qutip.core.operators), 281 fidelity() (in module qutip.core.metrics), 317
Distribution (class in qutip.distributions), 265 file_data_read() (in module qutip.fileio), 386
dnorm() (in module qutip.core.metrics), 316 file_data_store() (in module qutip.fileio), 386
dnorm() (Qobj method), 190 filter() (HierarchyADOs method), 240
DrudeLorentzBath (class in qutip.solver.heom), 234 final_state (McResult property), 259
DrudeLorentzPadeBath (class in qutip.solver.heom), final_state (MultiTrajResult property), 258
235 final_state (NmmcResult property), 260
dtype (QobjEvo attribute), 201 floquet_tensor() (in module qutip.solver.floquet),
dual_chan() (Qobj method), 190 335
FloquetBasis (class in qutip.solver.floquet), 218
E FMESolver (class in qutip.solver.floquet), 216
eigenenergies() (Qobj method), 190 fmmesolve() (in module qutip.solver.floquet), 336
eigenstates() (Qobj method), 191 fock() (in module qutip.core.states), 271
energy_degeneracy() (in module qutip.piqs.piqs), fock_dm() (in module qutip.core.states), 271
359 fredkin() (in module qutip.core.gates), 294
enr_destroy() (in module from_floquet_basis() (FloquetBasis method), 218
qutip.core.energy_restricted), 299 from_tensor_rep() (in module
qutip.core.dimensions), 310

484 Index
QuTiP: Quantum Toolbox in Python, Release 5.0.4

fsesolve() (in module qutip.solver.floquet), 337 inv() (Qobj method), 193


full() (Qobj method), 192 isbra (Qobj property), 193
isbra (QobjEvo attribute), 202
G isconstant (QobjEvo attribute), 202
ghz() (in module qutip.piqs.piqs), 360 isdiagonal() (in module qutip.piqs.piqs), 361
ghz_state() (in module qutip.core.states), 272 isdicke() (Pim method), 264
globalphase() (in module qutip.core.gates), 294 isket (Qobj property), 193
ground() (in module qutip.piqs.piqs), 360 isket (QobjEvo attribute), 202
groundstate() (Qobj method), 192 isoper (Qobj property), 193
isoper (QobjEvo attribute), 202
H isoperbra (Qobj property), 193
hadamard_transform() (in module qutip.core.gates), isoperbra (QobjEvo attribute), 202
294 isoperket (Qobj property), 193
hellinger_dist() (in module qutip.core.metrics), isoperket (QobjEvo attribute), 202
317 issuper (Qobj property), 193
HEOMResult (class in qutip.solver.heom), 242 issuper (QobjEvo attribute), 202
heomsolve() (in module qutip.solver.heom), 343 iswap() (in module qutip.core.gates), 295
HEOMSolver (class in qutip.solver.heom), 229
HierarchyADOs (class in qutip.solver.heom), 238 J
HierarchyADOsState (class in qutip.solver.heom), jmat() (in module qutip.core.operators), 284
241 jspin() (in module qutip.piqs.piqs), 361
hilbert_dist() (in module qutip.core.metrics), 318
hinton() (in module qutip.visualization), 366 K
HSolverDL (class in qutip.solver.heom), 231 ket() (in module qutip.core.states), 272
ket2dm() (in module qutip.core.states), 273
I kraus_to_choi() (in module
identity() (in module qutip.core.operators), 283 qutip.core.superop_reps), 308
identity_uncoupled() (in module qutip.piqs.piqs), kraus_to_super() (in module
360 qutip.core.superop_reps), 308
idx() (HierarchyADOs method), 240 krylovsolve() (in module qutip.solver.krylovsolve),
Implicit_Milstein_SODE (class in 332
qutip.solver.sode.itotaylor), 253
Implicit_Taylor1_5_SODE (class in L
qutip.solver.sode.itotaylor), 254 lindblad_dissipator() (in module
IntegratorDiag (class in qutip.core.superoperator), 306
qutip.solver.integrator.qutip_integrator), lindbladian() (Dicke method), 262
252 linear_map() (QobjEvo method), 202
IntegratorKrylov (class in liouvillian() (Dicke method), 262
qutip.solver.integrator.krylov), 252 liouvillian() (in module qutip.core.superoperator),
IntegratorScipyAdams (class in 306
qutip.solver.integrator.scipy_integrator), logarithmic_negativity() (in module
249 qutip.continuous_variables), 321
IntegratorScipyBDF (class in logm() (Qobj method), 193
qutip.solver.integrator.scipy_integrator), loky_pmap() (in module qutip.solver.parallel), 387
249 LorentzianBath (class in qutip.solver.heom), 237
IntegratorScipyDop853 (class in LorentzianPadeBath (class in qutip.solver.heom),
qutip.solver.integrator.scipy_integrator), 238
250
IntegratorScipylsoda (class in M
qutip.solver.integrator.scipy_integrator), m_degeneracy() (in module qutip.piqs.piqs), 361
249 make_sphere() (Bloch method), 207
IntegratorVern7 (class in marginal() (Distribution method), 265
qutip.solver.integrator.qutip_integrator), matmul() (QobjEvo method), 203
250 matmul_data() (QobjEvo method), 203
IntegratorVern9 (class in matrix_element() (Qobj method), 193
qutip.solver.integrator.qutip_integrator), matrix_histogram() (in module qutip.visualization),
251 367
inv() (Propagator method), 220

Index 485
QuTiP: Quantum Toolbox in Python, Release 5.0.4

maximally_mixed_dm() (in module qutip.solver.spectrum, 350


qutip.core.states), 274 qutip.solver.steadystate, 351
McResult (class in qutip.solver.result), 258 qutip.solver.stochastic, 338
mcsolve() (in module qutip.solver.mcsolve), 328 qutip.tomography, 383
MCSolver (class in qutip.solver.mcsolve), 221 qutip.utilities, 385
measure() (in module qutip.measurement), 322 qutip.visualization, 366
measure_observable() (in module qutip.wigner, 364
qutip.measurement), 322 molmer_sorensen() (in module qutip.core.gates), 295
measure_povm() (in module qutip.measurement), 323 momentum() (in module qutip.core.operators), 285
measurement_statistics() (in module mpi_pmap() (in module qutip.solver.parallel), 387
qutip.measurement), 324 MultiTrajResult (class in qutip.solver.result), 256
measurement_statistics_observable() (in mod-
ule qutip.measurement), 324 N
measurement_statistics_povm() (in module n_thermal() (in module qutip.utilities), 385
qutip.measurement), 325 next() (HierarchyADOs method), 241
mesolve() (in module qutip.solver.mesolve), 327 nm_mcsolve() (in module qutip.solver.nm_mcsolve),
MESolver (class in qutip.solver.mesolve), 211 330
Milstein_SODE (class in qutip.solver.sode.itotaylor), NmmcResult (class in qutip.solver.result), 259
253 NonMarkovianMCSolver (class in
mode() (FloquetBasis method), 219 qutip.solver.nm_mcsolve), 224
module norm() (Qobj method), 194
qutip, 390 num() (in module qutip.core.operators), 285
qutip.animation, 374 num_dicke_ladders() (in module qutip.piqs.piqs),
qutip.continuous_variables, 320 361
qutip.core.coefficient, 341 num_dicke_states() (in module qutip.piqs.piqs),
qutip.core.dimensions, 310 362
qutip.core.energy_restricted, 299 num_elements (QobjEvo attribute), 203
qutip.core.expect, 311 num_tls() (in module qutip.piqs.piqs), 362
qutip.core.gates, 292
qutip.core.metrics, 315 O
qutip.core.operators, 280
operator_to_vector() (in module
qutip.core.qobj, 301
qutip.core.superoperator), 306
qutip.core.states, 266
options (BRSolver property), 215
qutip.core.superop_reps, 308
options (EulerSODE property), 253
qutip.core.superoperator, 306
options (Explicit1_5_SODE property), 255
qutip.core.tensor, 311
options (FMESolver property), 217
qutip.entropy, 313
options (HEOMSolver property), 229
qutip.fileio, 386
options (Implicit_Milstein_SODE property), 254
qutip.ipynbtools, 390
options (Implicit_Taylor1_5_SODE property), 254
qutip.matplotlib_utilities, 382
options (IntegratorDiag property), 252
qutip.measurement, 322
options (IntegratorKrylov property), 252
qutip.partial_transpose, 312
options (IntegratorScipyAdams property), 249
qutip.piqs.piqs, 356
options (IntegratorScipyBDF property), 249
qutip.random_objects, 301
options (IntegratorScipyDop853 property), 250
qutip.solver.brmesolve, 334
options (IntegratorScipylsoda property), 250
qutip.solver.correlation, 345
options (IntegratorVern7 property), 251
qutip.solver.floquet, 335
options (IntegratorVern9 property), 251
qutip.solver.heom, 343
options (MCSolver property), 222
qutip.solver.krylovsolve, 332
options (MESolver property), 212
qutip.solver.mcsolve, 328
options (Milstein_SODE property), 253
qutip.solver.mesolve, 327
options (NonMarkovianMCSolver property), 225
qutip.solver.nm_mcsolve, 330
options (PlatenSODE property), 254
qutip.solver.nonmarkov.transfertensor,
options (PredCorr_SODE property), 255
384
options (RouchonSODE property), 253
qutip.solver.parallel, 387
options (SESolver property), 209
qutip.solver.propagator, 354
options (SMESolver property), 243
qutip.solver.scattering, 355
options (SSESolver property), 246
qutip.solver.sesolve, 325
options (Taylor1_5_SODE property), 253

486 Index
QuTiP: Quantum Toolbox in Python, Release 5.0.4

overlap() (Qobj method), 194 qpt() (in module qutip.tomography), 383


qpt_plot() (in module qutip.tomography), 383
P qpt_plot_combined() (in module
parallel_map() (in module qutip.solver.parallel), qutip.tomography), 383
388 qrot() (in module qutip.core.gates), 295
partial_transpose() (in module qsave() (in module qutip.fileio), 386
qutip.partial_transpose), 312 qubit_clifford_group() (in module
permute() (Qobj method), 194 qutip.core.gates), 296
phase() (in module qutip.core.operators), 285 qutip
phase_basis() (in module qutip.core.states), 274 module, 390
phasegate() (in module qutip.core.gates), 295 qutip.animation
photocurrent (McResult property), 259 module, 374
photocurrent (NmmcResult property), 260 qutip.continuous_variables
Pim (class in qutip.piqs.piqs), 263 module, 320
pisolve() (Dicke method), 262 qutip.core.coefficient
PlatenSODE (class in qutip.solver.sode.sode), 254 module, 341
plot_energy_levels() (in module qutip.core.dimensions
qutip.visualization), 369 module, 310
plot_expectation_values() (in module qutip.core.energy_restricted
qutip.visualization), 370 module, 299
plot_fock_distribution() (in module qutip.core.expect
qutip.visualization), 370 module, 311
plot_qubism() (in module qutip.visualization), 370 qutip.core.gates
plot_schmidt() (in module qutip.visualization), 371 module, 292
plot_spin_distribution() (in module qutip.core.metrics
qutip.visualization), 372 module, 315
plot_wigner() (in module qutip.visualization), 373 qutip.core.operators
plot_wigner_sphere() (in module module, 280
qutip.visualization), 373 qutip.core.qobj
position() (in module qutip.core.operators), 286 module, 301
PredCorr_SODE (class in qutip.solver.sode.sode), 255 qutip.core.states
prev() (HierarchyADOs method), 241 module, 266
process_fidelity() (in module qutip.core.metrics), qutip.core.superop_reps
318 module, 308
proj() (Qobj method), 195 qutip.core.superoperator
project() (Distribution method), 266 module, 306
projection() (in module qutip.core.states), 275 qutip.core.tensor
Propagator (class in qutip.solver.propagator), 219 module, 311
propagator() (in module qutip.solver.propagator), qutip.entropy
354 module, 313
propagator_steadystate() (in module qutip.fileio
qutip.solver.propagator), 354 module, 386
pseudo_inverse() (in module qutip.ipynbtools
qutip.solver.steadystate), 351 module, 390
ptrace() (in module qutip.core.qobj), 301 qutip.matplotlib_utilities
ptrace() (Qobj method), 195 module, 382
purity() (Qobj method), 196 qutip.measurement
purity_dicke() (in module qutip.piqs.piqs), 362 module, 322
qutip.partial_transpose
Q module, 312
qutip.piqs.piqs
qdiags() (in module qutip.core.operators), 286
module, 356
qeye() (in module qutip.core.operators), 287
qutip.random_objects
qeye_like() (in module qutip.core.operators), 287
module, 301
QFunc (class in qutip), 208
qutip.solver.brmesolve
qfunc() (in module qutip.wigner), 364
module, 334
qload() (in module qutip.fileio), 386
qutip.solver.correlation
Qobj (class in qutip.core.qobj), 187
module, 345
QobjEvo (class in qutip.core.cy.qobjevo), 198

Index 487
QuTiP: Quantum Toolbox in Python, Release 5.0.4

qutip.solver.floquet Result (class in qutip.solver.result), 255


module, 335 RouchonSODE (class in qutip.solver.sode.rouchon), 252
qutip.solver.heom run() (BRSolver method), 215
module, 343 run() (FMESolver method), 217
qutip.solver.krylovsolve run() (HEOMSolver method), 230
module, 332 run() (MCSolver method), 223
qutip.solver.mcsolve run() (MESolver method), 212
module, 328 run() (NonMarkovianMCSolver method), 227
qutip.solver.mesolve run() (SESolver method), 210
module, 327 run() (SMESolver method), 244
qutip.solver.nm_mcsolve run() (SSESolver method), 247
module, 330 runs_final_states (McResult property), 259
qutip.solver.nonmarkov.transfertensor runs_final_states (MultiTrajResult property), 258
module, 384 runs_final_states (NmmcResult property), 260
qutip.solver.parallel runs_photocurrent (McResult property), 259
module, 387 runs_photocurrent (NmmcResult property), 260
qutip.solver.propagator runs_states (McResult property), 259
module, 354 runs_states (MultiTrajResult property), 258
qutip.solver.scattering runs_states (NmmcResult property), 260
module, 355 rx() (in module qutip.core.gates), 296
qutip.solver.sesolve ry() (in module qutip.core.gates), 296
module, 325 rz() (in module qutip.core.gates), 296
qutip.solver.spectrum
module, 350 S
qutip.solver.steadystate s_gate() (in module qutip.core.gates), 297
module, 351 save() (Bloch method), 207
qutip.solver.stochastic scattering_probability() (in module
module, 338 qutip.solver.scattering), 355
qutip.tomography serial_map() (in module qutip.solver.parallel), 389
module, 383 sesolve() (in module qutip.solver.sesolve), 325
qutip.utilities SESolver (class in qutip.solver.sesolve), 209
module, 385 set_label_convention() (Bloch method), 207
qutip.visualization shape (Qobj property), 196
module, 366 show() (Bloch method), 207
qutip.wigner sigmam() (in module qutip.core.operators), 288
module, 364 sigmap() (in module qutip.core.operators), 289
qutrit_basis() (in module qutip.core.states), 275 sigmax() (in module qutip.core.operators), 289
qutrit_ops() (in module qutip.core.operators), 287 sigmay() (in module qutip.core.operators), 289
qzero() (in module qutip.core.operators), 288 sigmaz() (in module qutip.core.operators), 290
qzero_like() (in module qutip.core.operators), 288 simdiag() (in module qutip), 390
singlet_state() (in module qutip.core.states), 275
R sinm() (Qobj method), 196
rand_dm() (in module qutip.random_objects), 301 smesolve() (in module qutip.solver.stochastic), 338
rand_herm() (in module qutip.random_objects), 302 SMESolver (class in qutip.solver.stochastic), 242
rand_ket() (in module qutip.random_objects), 303 snot() (in module qutip.core.gates), 297
rand_kraus_map() (in module solve() (Pim method), 264
qutip.random_objects), 303 spectrum() (in module qutip.solver.spectrum), 350
rand_stochastic() (in module spectrum_correlation_fft() (in module
qutip.random_objects), 303 qutip.solver.spectrum), 350
rand_super() (in module qutip.random_objects), 304 sphereplot() (in module qutip.visualization), 374
rand_super_bcsz() (in module spin_algebra() (in module qutip.piqs.piqs), 362
qutip.random_objects), 304 spin_coherent() (in module qutip.core.states), 275
rand_unitary() (in module qutip.random_objects), spin_Jm() (in module qutip.core.operators), 290
305 spin_Jp() (in module qutip.core.operators), 290
rate() (NonMarkovianMCSolver method), 226 spin_Jx() (in module qutip.core.operators), 290
rate_shift() (NonMarkovianMCSolver method), spin_Jy() (in module qutip.core.operators), 291
226 spin_Jz() (in module qutip.core.operators), 291
render() (Bloch method), 207 spin_q_function() (in module qutip.wigner), 364

488 Index
QuTiP: Quantum Toolbox in Python, Release 5.0.4

spin_state() (in module qutip.core.states), 276 step() (MESolver method), 213


spin_wigner() (in module qutip.wigner), 365 step() (NonMarkovianMCSolver method), 228
spost() (in module qutip.core.superoperator), 307 step() (SESolver method), 210
spre() (in module qutip.core.superoperator), 307 step() (SMESolver method), 245
sprepost() (in module qutip.core.superoperator), 307 step() (SSESolver method), 248
sqrt_shifted_rate() (NonMarkovianMCSolver super_tensor() (in module qutip.core.tensor), 311
method), 227 superradiant() (in module qutip.piqs.piqs), 363
sqrtiswap() (in module qutip.core.gates), 297 swap() (in module qutip.core.gates), 298
sqrtm() (Qobj method), 196 swapalpha() (in module qutip.core.gates), 298
sqrtnot() (in module qutip.core.gates), 297 sys_dims (BRSolver property), 216
sqrtswap() (in module qutip.core.gates), 297 sys_dims (FMESolver property), 218
squeeze() (in module qutip.core.operators), 291 sys_dims (HEOMSolver property), 231
squeezing() (in module qutip.core.operators), 292 sys_dims (MCSolver property), 224
ssesolve() (in module qutip.solver.stochastic), 340 sys_dims (MESolver property), 213
SSESolver (class in qutip.solver.stochastic), 245 sys_dims (NonMarkovianMCSolver property), 228
start() (BRSolver method), 215 sys_dims (SESolver property), 211
start() (FMESolver method), 218 sys_dims (SMESolver property), 245
start() (HEOMSolver method), 230 sys_dims (SSESolver property), 248
start() (MCSolver method), 223
start() (MESolver method), 213 T
start() (NonMarkovianMCSolver method), 228 t_gate() (in module qutip.core.gates), 298
start() (SESolver method), 210 tau1() (Pim method), 264
start() (SMESolver method), 244 tau2() (Pim method), 264
start() (SSESolver method), 248 tau3() (Pim method), 264
state() (FloquetBasis method), 219 tau4() (Pim method), 264
state_degeneracy() (in module qutip.piqs.piqs), tau5() (Pim method), 264
363 tau6() (Pim method), 265
state_index_number() (in module tau7() (Pim method), 265
qutip.core.states), 276 tau8() (Pim method), 265
state_number_enumerate() (in module tau9() (Pim method), 265
qutip.core.states), 276 tau_column() (in module qutip.piqs.piqs), 363
state_number_index() (in module tau_valid() (Pim method), 265
qutip.core.states), 277 Taylor1_5_SODE (class in qutip.solver.sode.itotaylor),
state_number_qobj() (in module qutip.core.states), 253
277 temporal_basis_vector() (in module
StateFeedback() (BRSolver class method), 214 qutip.solver.scattering), 355
StateFeedback() (FMESolver class method), 217 temporal_scattered_state() (in module
StateFeedback() (MCSolver class method), 221 qutip.solver.scattering), 356
StateFeedback() (MESolver class method), 212 tensor() (in module qutip.core.tensor), 312
StateFeedback() (NonMarkovianMCSolver class tensor_contract() (in module qutip.core.tensor),
method), 225 312
StateFeedback() (SESolver class method), 209 terminator() (DrudeLorentzBath method), 235
StateFeedback() (SMESolver class method), 242 terminator() (DrudeLorentzPadeBath method), 236
StateFeedback() (SSESolver class method), 246 thermal_dm() (in module qutip.core.states), 278
states (McResult property), 259 tidyup() (Qobj method), 197
states (MultiTrajResult property), 258 tidyup() (QobjEvo method), 203
states (NmmcResult property), 260 to() (Qobj method), 197
steady_state() (HEOMSolver method), 231 to() (QobjEvo method), 203
steady_state() (McResult method), 259 to_chi() (in module qutip.core.superop_reps), 308
steady_state() (MultiTrajResult method), 258 to_choi() (in module qutip.core.superop_reps), 308
steady_state() (NmmcResult method), 260 to_floquet_basis() (FloquetBasis method), 219
steadystate() (in module qutip.solver.steadystate), to_kraus() (in module qutip.core.superop_reps), 309
352 to_list() (QobjEvo method), 203
steadystate_floquet() (in module to_stinespring() (in module
qutip.solver.steadystate), 353 qutip.core.superop_reps), 309
step() (BRSolver method), 216 to_super() (in module qutip.core.superop_reps), 309
step() (FMESolver method), 218 to_tensor_rep() (in module qutip.core.dimensions),
step() (MCSolver method), 224 310

Index 489
QuTiP: Quantum Toolbox in Python, Release 5.0.4

toffoli() (in module qutip.core.gates), 298


tr() (Qobj method), 197
trace (NmmcResult property), 261
tracedist() (in module qutip.core.metrics), 319
trans() (Qobj method), 197
trans() (QobjEvo method), 203
transform() (Qobj method), 197
triplet_states() (in module qutip.core.states), 279
trunc_neg() (Qobj method), 198
ttmsolve() (in module
qutip.solver.nonmarkov.transfertensor),
384
tunneling() (in module qutip.core.operators), 292
types (BathExponent attribute), 233

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

You might also like