We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add progressbar for propatgator?
It is really great to use qutip 3.0 in iPython notebook with the HTMLProgressbar, especially when using mesolve or essolve. Unfortunately there is no progressbar when using the propagator function.

Would it be possible to implement this, for propagator (and/or possible other functions), since it calls mesolve, which already has it implemented?

Thanks


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `qutip/propagator.py`
Content:
```
1 # This file is part of QuTiP: Quantum Toolbox in Python.
2 #
3 #    Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson.
4 #    All rights reserved.
5 #
6 #    Redistribution and use in source and binary forms, with or without
7 #    modification, are permitted provided that the following conditions are
8 #    met:
9 #
10 #    1. Redistributions of source code must retain the above copyright notice,
11 #       this list of conditions and the following disclaimer.
12 #
13 #    2. Redistributions in binary form must reproduce the above copyright
14 #       notice, this list of conditions and the following disclaimer in the
15 #       documentation and/or other materials provided with the distribution.
16 #
17 #    3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names
18 #       of its contributors may be used to endorse or promote products derived
19 #       from this software without specific prior written permission.
20 #
21 #    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 #    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 #    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 #    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 #    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 #    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 #    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 #    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 #    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 #    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 #    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 ###############################################################################
33 
34 __all__ = ['propagator', 'propagator_steadystate']
35 
36 import types
37 import numpy as np
38 import scipy.linalg as la
39 import functools
40 
41 from qutip.qobj import Qobj
42 from qutip.rhs_generate import rhs_clear
43 from qutip.superoperator import (vec2mat, mat2vec,
44                                  vector_to_operator, operator_to_vector)
45 from qutip.mesolve import mesolve
46 from qutip.sesolve import sesolve
47 from qutip.states import basis
48 from qutip.solver import Options
49 
50 
51 def propagator(H, t, c_op_list, args=None, options=None, sparse=False):
52     """
53     Calculate the propagator U(t) for the density matrix or wave function such
54     that :math:`\psi(t) = U(t)\psi(0)` or
55     :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)`
56     where :math:`\\rho_{\mathrm vec}` is the vector representation of the
57     density matrix.
58 
59     Parameters
60     ----------
61     H : qobj or list
62         Hamiltonian as a Qobj instance of a nested list of Qobjs and
63         coefficients in the list-string or list-function format for
64         time-dependent Hamiltonians (see description in :func:`qutip.mesolve`).
65 
66     t : float or array-like
67         Time or list of times for which to evaluate the propagator.
68 
69     c_op_list : list
70         List of qobj collapse operators.
71 
72     args : list/array/dictionary
73         Parameters to callback functions for time-dependent Hamiltonians and
74         collapse operators.
75 
76     options : :class:`qutip.Options`
77         with options for the ODE solver.
78 
79     Returns
80     -------
81      a : qobj
82         Instance representing the propagator :math:`U(t)`.
83 
84     """
85 
86     if options is None:
87         options = Options()
88         options.rhs_reuse = True
89         rhs_clear()
90 
91     if isinstance(t, (int, float, np.integer, np.floating)):
92         tlist = [0, t]
93     else:
94         tlist = t
95 
96     if isinstance(H, (types.FunctionType, types.BuiltinFunctionType,
97                       functools.partial)):
98         H0 = H(0.0, args)
99     elif isinstance(H, list):
100         H0 = H[0][0] if isinstance(H[0], list) else H[0]
101     else:
102         H0 = H
103 
104     if len(c_op_list) == 0 and H0.isoper:
105         # calculate propagator for the wave function
106 
107         N = H0.shape[0]
108         dims = H0.dims
109         u = np.zeros([N, N, len(tlist)], dtype=complex)
110 
111         for n in range(0, N):
112             psi0 = basis(N, n)
113             output = sesolve(H, psi0, tlist, [], args, options)
114             for k, t in enumerate(tlist):
115                 u[:, n, k] = output.states[k].full().T
116 
117         # todo: evolving a batch of wave functions:
118         # psi_0_list = [basis(N, n) for n in range(N)]
119         # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options)
120         # for n in range(0, N):
121         #    u[:,n] = psi_t_list[n][1].full().T
122 
123     elif len(c_op_list) == 0 and H0.issuper:
124         # calculate the propagator for the vector representation of the
125         # density matrix (a superoperator propagator)
126 
127         N = H0.shape[0]
128         dims = H0.dims
129 
130         u = np.zeros([N, N, len(tlist)], dtype=complex)
131 
132         for n in range(0, N):
133             psi0 = basis(N, n)
134             rho0 = Qobj(vec2mat(psi0.full()))
135             output = mesolve(H, rho0, tlist, [], [], args, options)
136             for k, t in enumerate(tlist):
137                 u[:, n, k] = mat2vec(output.states[k].full()).T
138 
139     else:
140         # calculate the propagator for the vector representation of the
141         # density matrix (a superoperator propagator)
142 
143         N = H0.shape[0]
144         dims = [H0.dims, H0.dims]
145 
146         u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)
147 
148         if sparse:
149             for n in range(N * N):
150                 psi0 = basis(N * N, n)
151                 psi0.dims = [dims[0], 1]
152                 rho0 = vector_to_operator(psi0)
153                 output = mesolve(H, rho0, tlist, c_op_list, [], args, options)
154                 for k, t in enumerate(tlist):
155                     u[:, n, k] = operator_to_vector(
156                         output.states[k]).full(squeeze=True)
157 
158         else:
159             for n in range(N * N):
160                 psi0 = basis(N * N, n)
161                 rho0 = Qobj(vec2mat(psi0.full()))
162                 output = mesolve(H, rho0, tlist, c_op_list, [], args, options)
163                 for k, t in enumerate(tlist):
164                     u[:, n, k] = mat2vec(output.states[k].full()).T
165 
166     if len(tlist) == 2:
167         return Qobj(u[:, :, 1], dims=dims)
168     else:
169         return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
170 
171 
172 def _get_min_and_index(lst):
173     """
174     Private function for obtaining min and max indicies.
175     """
176     minval, minidx = lst[0], 0
177     for i, v in enumerate(lst[1:]):
178         if v < minval:
179             minval, minidx = v, i + 1
180     return minval, minidx
181 
182 
183 def propagator_steadystate(U):
184     """Find the steady state for successive applications of the propagator
185     :math:`U`.
186 
187     Parameters
188     ----------
189     U : qobj
190         Operator representing the propagator.
191 
192     Returns
193     -------
194     a : qobj
195         Instance representing the steady-state density matrix.
196 
197     """
198 
199     evals, evecs = la.eig(U.full())
200 
201     ev_min, ev_idx = _get_min_and_index(abs(evals - 1.0))
202 
203     evecs = evecs.T
204     rho = Qobj(vec2mat(evecs[ev_idx]), dims=U.dims[0])
205     rho = rho * (1.0 / rho.tr())
206     rho = 0.5 * (rho + rho.dag())  # make sure rho is herm
207     return rho
208
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/qutip/propagator.py b/qutip/propagator.py
--- a/qutip/propagator.py
+++ b/qutip/propagator.py
@@ -46,9 +46,10 @@
 from qutip.sesolve import sesolve
 from qutip.states import basis
 from qutip.solver import Options
+from qutip.ui.progressbar import BaseProgressBar, TextProgressBar
 
-
-def propagator(H, t, c_op_list, args=None, options=None, sparse=False):
+def propagator(H, t, c_op_list, args=None, options=None, sparse=False,
+               progress_bar=None):
     """
     Calculate the propagator U(t) for the density matrix or wave function such
     that :math:`\psi(t) = U(t)\psi(0)` or
@@ -76,6 +77,11 @@
     options : :class:`qutip.Options`
         with options for the ODE solver.
 
+    progress_bar: BaseProgressBar
+        Optional instance of BaseProgressBar, or a subclass thereof, for
+        showing the progress of the simulation. By default no progress bar
+        is used, and if set to True a TextProgressBar will be used.
+
     Returns
     -------
      a : qobj
@@ -83,6 +89,11 @@
 
     """
 
+    if progress_bar is None:
+        progress_bar = BaseProgressBar()
+    elif progress_bar is True:
+        progress_bar = TextProgressBar()
+
     if options is None:
         options = Options()
         options.rhs_reuse = True
@@ -108,11 +119,14 @@
         dims = H0.dims
         u = np.zeros([N, N, len(tlist)], dtype=complex)
 
+        progress_bar.start(N)
         for n in range(0, N):
+            progress_bar.update(n)
             psi0 = basis(N, n)
             output = sesolve(H, psi0, tlist, [], args, options)
             for k, t in enumerate(tlist):
                 u[:, n, k] = output.states[k].full().T
+        progress_bar.finished()
 
         # todo: evolving a batch of wave functions:
         # psi_0_list = [basis(N, n) for n in range(N)]
@@ -129,12 +143,15 @@
 
         u = np.zeros([N, N, len(tlist)], dtype=complex)
 
+        progress_bar.start(N)
         for n in range(0, N):
+            progress_bar.update(n)
             psi0 = basis(N, n)
             rho0 = Qobj(vec2mat(psi0.full()))
             output = mesolve(H, rho0, tlist, [], [], args, options)
             for k, t in enumerate(tlist):
                 u[:, n, k] = mat2vec(output.states[k].full()).T
+        progress_bar.finished()
 
     else:
         # calculate the propagator for the vector representation of the
@@ -146,7 +163,9 @@
         u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)
 
         if sparse:
+            progress_bar.start(N * N)
             for n in range(N * N):
+                progress_bar.update(n)
                 psi0 = basis(N * N, n)
                 psi0.dims = [dims[0], 1]
                 rho0 = vector_to_operator(psi0)
@@ -154,14 +173,18 @@
                 for k, t in enumerate(tlist):
                     u[:, n, k] = operator_to_vector(
                         output.states[k]).full(squeeze=True)
+            progress_bar.finished()
 
         else:
+            progress_bar.start(N * N)
             for n in range(N * N):
+                progress_bar.update(n)
                 psi0 = basis(N * N, n)
                 rho0 = Qobj(vec2mat(psi0.full()))
                 output = mesolve(H, rho0, tlist, c_op_list, [], args, options)
                 for k, t in enumerate(tlist):
                     u[:, n, k] = mat2vec(output.states[k].full()).T
+            progress_bar.finished()
 
     if len(tlist) == 2:
         return Qobj(u[:, :, 1], dims=dims)

{"golden_diff": "diff --git a/qutip/propagator.py b/qutip/propagator.py\n--- a/qutip/propagator.py\n+++ b/qutip/propagator.py\n@@ -46,9 +46,10 @@\n from qutip.sesolve import sesolve\n from qutip.states import basis\n from qutip.solver import Options\n+from qutip.ui.progressbar import BaseProgressBar, TextProgressBar\n \n-\n-def propagator(H, t, c_op_list, args=None, options=None, sparse=False):\n+def propagator(H, t, c_op_list, args=None, options=None, sparse=False,\n+               progress_bar=None):\n     \"\"\"\n     Calculate the propagator U(t) for the density matrix or wave function such\n     that :math:`\\psi(t) = U(t)\\psi(0)` or\n@@ -76,6 +77,11 @@\n     options : :class:`qutip.Options`\n         with options for the ODE solver.\n \n+    progress_bar: BaseProgressBar\n+        Optional instance of BaseProgressBar, or a subclass thereof, for\n+        showing the progress of the simulation. By default no progress bar\n+        is used, and if set to True a TextProgressBar will be used.\n+\n     Returns\n     -------\n      a : qobj\n@@ -83,6 +89,11 @@\n \n     \"\"\"\n \n+    if progress_bar is None:\n+        progress_bar = BaseProgressBar()\n+    elif progress_bar is True:\n+        progress_bar = TextProgressBar()\n+\n     if options is None:\n         options = Options()\n         options.rhs_reuse = True\n@@ -108,11 +119,14 @@\n         dims = H0.dims\n         u = np.zeros([N, N, len(tlist)], dtype=complex)\n \n+        progress_bar.start(N)\n         for n in range(0, N):\n+            progress_bar.update(n)\n             psi0 = basis(N, n)\n             output = sesolve(H, psi0, tlist, [], args, options)\n             for k, t in enumerate(tlist):\n                 u[:, n, k] = output.states[k].full().T\n+        progress_bar.finished()\n \n         # todo: evolving a batch of wave functions:\n         # psi_0_list = [basis(N, n) for n in range(N)]\n@@ -129,12 +143,15 @@\n \n         u = np.zeros([N, N, len(tlist)], dtype=complex)\n \n+        progress_bar.start(N)\n         for n in range(0, N):\n+            progress_bar.update(n)\n             psi0 = basis(N, n)\n             rho0 = Qobj(vec2mat(psi0.full()))\n             output = mesolve(H, rho0, tlist, [], [], args, options)\n             for k, t in enumerate(tlist):\n                 u[:, n, k] = mat2vec(output.states[k].full()).T\n+        progress_bar.finished()\n \n     else:\n         # calculate the propagator for the vector representation of the\n@@ -146,7 +163,9 @@\n         u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)\n \n         if sparse:\n+            progress_bar.start(N * N)\n             for n in range(N * N):\n+                progress_bar.update(n)\n                 psi0 = basis(N * N, n)\n                 psi0.dims = [dims[0], 1]\n                 rho0 = vector_to_operator(psi0)\n@@ -154,14 +173,18 @@\n                 for k, t in enumerate(tlist):\n                     u[:, n, k] = operator_to_vector(\n                         output.states[k]).full(squeeze=True)\n+            progress_bar.finished()\n \n         else:\n+            progress_bar.start(N * N)\n             for n in range(N * N):\n+                progress_bar.update(n)\n                 psi0 = basis(N * N, n)\n                 rho0 = Qobj(vec2mat(psi0.full()))\n                 output = mesolve(H, rho0, tlist, c_op_list, [], args, options)\n                 for k, t in enumerate(tlist):\n                     u[:, n, k] = mat2vec(output.states[k].full()).T\n+            progress_bar.finished()\n \n     if len(tlist) == 2:\n         return Qobj(u[:, :, 1], dims=dims)\n", "issue": "Add progressbar for propatgator?\nIt is really great to use qutip 3.0 in iPython notebook with the HTMLProgressbar, especially when using mesolve or essolve. Unfortunately there is no progressbar when using the propagator function.\n\nWould it be possible to implement this, for propagator (and/or possible other functions), since it calls mesolve, which already has it implemented?\n\nThanks\n\n", "before_files": [{"content": "# This file is part of QuTiP: Quantum Toolbox in Python.\n#\n#    Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson.\n#    All rights reserved.\n#\n#    Redistribution and use in source and binary forms, with or without\n#    modification, are permitted provided that the following conditions are\n#    met:\n#\n#    1. Redistributions of source code must retain the above copyright notice,\n#       this list of conditions and the following disclaimer.\n#\n#    2. Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#\n#    3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names\n#       of its contributors may be used to endorse or promote products derived\n#       from this software without specific prior written permission.\n#\n#    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n#    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n#    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n#    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n#    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n#    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n#    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n#    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n#    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n#    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n#    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n###############################################################################\n\n__all__ = ['propagator', 'propagator_steadystate']\n\nimport types\nimport numpy as np\nimport scipy.linalg as la\nimport functools\n\nfrom qutip.qobj import Qobj\nfrom qutip.rhs_generate import rhs_clear\nfrom qutip.superoperator import (vec2mat, mat2vec,\n                                 vector_to_operator, operator_to_vector)\nfrom qutip.mesolve import mesolve\nfrom qutip.sesolve import sesolve\nfrom qutip.states import basis\nfrom qutip.solver import Options\n\n\ndef propagator(H, t, c_op_list, args=None, options=None, sparse=False):\n    \"\"\"\n    Calculate the propagator U(t) for the density matrix or wave function such\n    that :math:`\\psi(t) = U(t)\\psi(0)` or\n    :math:`\\\\rho_{\\mathrm vec}(t) = U(t) \\\\rho_{\\mathrm vec}(0)`\n    where :math:`\\\\rho_{\\mathrm vec}` is the vector representation of the\n    density matrix.\n\n    Parameters\n    ----------\n    H : qobj or list\n        Hamiltonian as a Qobj instance of a nested list of Qobjs and\n        coefficients in the list-string or list-function format for\n        time-dependent Hamiltonians (see description in :func:`qutip.mesolve`).\n\n    t : float or array-like\n        Time or list of times for which to evaluate the propagator.\n\n    c_op_list : list\n        List of qobj collapse operators.\n\n    args : list/array/dictionary\n        Parameters to callback functions for time-dependent Hamiltonians and\n        collapse operators.\n\n    options : :class:`qutip.Options`\n        with options for the ODE solver.\n\n    Returns\n    -------\n     a : qobj\n        Instance representing the propagator :math:`U(t)`.\n\n    \"\"\"\n\n    if options is None:\n        options = Options()\n        options.rhs_reuse = True\n        rhs_clear()\n\n    if isinstance(t, (int, float, np.integer, np.floating)):\n        tlist = [0, t]\n    else:\n        tlist = t\n\n    if isinstance(H, (types.FunctionType, types.BuiltinFunctionType,\n                      functools.partial)):\n        H0 = H(0.0, args)\n    elif isinstance(H, list):\n        H0 = H[0][0] if isinstance(H[0], list) else H[0]\n    else:\n        H0 = H\n\n    if len(c_op_list) == 0 and H0.isoper:\n        # calculate propagator for the wave function\n\n        N = H0.shape[0]\n        dims = H0.dims\n        u = np.zeros([N, N, len(tlist)], dtype=complex)\n\n        for n in range(0, N):\n            psi0 = basis(N, n)\n            output = sesolve(H, psi0, tlist, [], args, options)\n            for k, t in enumerate(tlist):\n                u[:, n, k] = output.states[k].full().T\n\n        # todo: evolving a batch of wave functions:\n        # psi_0_list = [basis(N, n) for n in range(N)]\n        # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options)\n        # for n in range(0, N):\n        #    u[:,n] = psi_t_list[n][1].full().T\n\n    elif len(c_op_list) == 0 and H0.issuper:\n        # calculate the propagator for the vector representation of the\n        # density matrix (a superoperator propagator)\n\n        N = H0.shape[0]\n        dims = H0.dims\n\n        u = np.zeros([N, N, len(tlist)], dtype=complex)\n\n        for n in range(0, N):\n            psi0 = basis(N, n)\n            rho0 = Qobj(vec2mat(psi0.full()))\n            output = mesolve(H, rho0, tlist, [], [], args, options)\n            for k, t in enumerate(tlist):\n                u[:, n, k] = mat2vec(output.states[k].full()).T\n\n    else:\n        # calculate the propagator for the vector representation of the\n        # density matrix (a superoperator propagator)\n\n        N = H0.shape[0]\n        dims = [H0.dims, H0.dims]\n\n        u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)\n\n        if sparse:\n            for n in range(N * N):\n                psi0 = basis(N * N, n)\n                psi0.dims = [dims[0], 1]\n                rho0 = vector_to_operator(psi0)\n                output = mesolve(H, rho0, tlist, c_op_list, [], args, options)\n                for k, t in enumerate(tlist):\n                    u[:, n, k] = operator_to_vector(\n                        output.states[k]).full(squeeze=True)\n\n        else:\n            for n in range(N * N):\n                psi0 = basis(N * N, n)\n                rho0 = Qobj(vec2mat(psi0.full()))\n                output = mesolve(H, rho0, tlist, c_op_list, [], args, options)\n                for k, t in enumerate(tlist):\n                    u[:, n, k] = mat2vec(output.states[k].full()).T\n\n    if len(tlist) == 2:\n        return Qobj(u[:, :, 1], dims=dims)\n    else:\n        return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]\n\n\ndef _get_min_and_index(lst):\n    \"\"\"\n    Private function for obtaining min and max indicies.\n    \"\"\"\n    minval, minidx = lst[0], 0\n    for i, v in enumerate(lst[1:]):\n        if v < minval:\n            minval, minidx = v, i + 1\n    return minval, minidx\n\n\ndef propagator_steadystate(U):\n    \"\"\"Find the steady state for successive applications of the propagator\n    :math:`U`.\n\n    Parameters\n    ----------\n    U : qobj\n        Operator representing the propagator.\n\n    Returns\n    -------\n    a : qobj\n        Instance representing the steady-state density matrix.\n\n    \"\"\"\n\n    evals, evecs = la.eig(U.full())\n\n    ev_min, ev_idx = _get_min_and_index(abs(evals - 1.0))\n\n    evecs = evecs.T\n    rho = Qobj(vec2mat(evecs[ev_idx]), dims=U.dims[0])\n    rho = rho * (1.0 / rho.tr())\n    rho = 0.5 * (rho + rho.dag())  # make sure rho is herm\n    return rho\n", "path": "qutip/propagator.py"}], "after_files": [{"content": "# This file is part of QuTiP: Quantum Toolbox in Python.\n#\n#    Copyright (c) 2011 and later, Paul D. Nation and Robert J. Johansson.\n#    All rights reserved.\n#\n#    Redistribution and use in source and binary forms, with or without\n#    modification, are permitted provided that the following conditions are\n#    met:\n#\n#    1. Redistributions of source code must retain the above copyright notice,\n#       this list of conditions and the following disclaimer.\n#\n#    2. Redistributions in binary form must reproduce the above copyright\n#       notice, this list of conditions and the following disclaimer in the\n#       documentation and/or other materials provided with the distribution.\n#\n#    3. Neither the name of the QuTiP: Quantum Toolbox in Python nor the names\n#       of its contributors may be used to endorse or promote products derived\n#       from this software without specific prior written permission.\n#\n#    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n#    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n#    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n#    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n#    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n#    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n#    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n#    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n#    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n#    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n#    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n###############################################################################\n\n__all__ = ['propagator', 'propagator_steadystate']\n\nimport types\nimport numpy as np\nimport scipy.linalg as la\nimport functools\n\nfrom qutip.qobj import Qobj\nfrom qutip.rhs_generate import rhs_clear\nfrom qutip.superoperator import (vec2mat, mat2vec,\n                                 vector_to_operator, operator_to_vector)\nfrom qutip.mesolve import mesolve\nfrom qutip.sesolve import sesolve\nfrom qutip.states import basis\nfrom qutip.solver import Options\nfrom qutip.ui.progressbar import BaseProgressBar, TextProgressBar\n\ndef propagator(H, t, c_op_list, args=None, options=None, sparse=False,\n               progress_bar=None):\n    \"\"\"\n    Calculate the propagator U(t) for the density matrix or wave function such\n    that :math:`\\psi(t) = U(t)\\psi(0)` or\n    :math:`\\\\rho_{\\mathrm vec}(t) = U(t) \\\\rho_{\\mathrm vec}(0)`\n    where :math:`\\\\rho_{\\mathrm vec}` is the vector representation of the\n    density matrix.\n\n    Parameters\n    ----------\n    H : qobj or list\n        Hamiltonian as a Qobj instance of a nested list of Qobjs and\n        coefficients in the list-string or list-function format for\n        time-dependent Hamiltonians (see description in :func:`qutip.mesolve`).\n\n    t : float or array-like\n        Time or list of times for which to evaluate the propagator.\n\n    c_op_list : list\n        List of qobj collapse operators.\n\n    args : list/array/dictionary\n        Parameters to callback functions for time-dependent Hamiltonians and\n        collapse operators.\n\n    options : :class:`qutip.Options`\n        with options for the ODE solver.\n\n    progress_bar: BaseProgressBar\n        Optional instance of BaseProgressBar, or a subclass thereof, for\n        showing the progress of the simulation. By default no progress bar\n        is used, and if set to True a TextProgressBar will be used.\n\n    Returns\n    -------\n     a : qobj\n        Instance representing the propagator :math:`U(t)`.\n\n    \"\"\"\n\n    if progress_bar is None:\n        progress_bar = BaseProgressBar()\n    elif progress_bar is True:\n        progress_bar = TextProgressBar()\n\n    if options is None:\n        options = Options()\n        options.rhs_reuse = True\n        rhs_clear()\n\n    if isinstance(t, (int, float, np.integer, np.floating)):\n        tlist = [0, t]\n    else:\n        tlist = t\n\n    if isinstance(H, (types.FunctionType, types.BuiltinFunctionType,\n                      functools.partial)):\n        H0 = H(0.0, args)\n    elif isinstance(H, list):\n        H0 = H[0][0] if isinstance(H[0], list) else H[0]\n    else:\n        H0 = H\n\n    if len(c_op_list) == 0 and H0.isoper:\n        # calculate propagator for the wave function\n\n        N = H0.shape[0]\n        dims = H0.dims\n        u = np.zeros([N, N, len(tlist)], dtype=complex)\n\n        progress_bar.start(N)\n        for n in range(0, N):\n            progress_bar.update(n)\n            psi0 = basis(N, n)\n            output = sesolve(H, psi0, tlist, [], args, options)\n            for k, t in enumerate(tlist):\n                u[:, n, k] = output.states[k].full().T\n        progress_bar.finished()\n\n        # todo: evolving a batch of wave functions:\n        # psi_0_list = [basis(N, n) for n in range(N)]\n        # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options)\n        # for n in range(0, N):\n        #    u[:,n] = psi_t_list[n][1].full().T\n\n    elif len(c_op_list) == 0 and H0.issuper:\n        # calculate the propagator for the vector representation of the\n        # density matrix (a superoperator propagator)\n\n        N = H0.shape[0]\n        dims = H0.dims\n\n        u = np.zeros([N, N, len(tlist)], dtype=complex)\n\n        progress_bar.start(N)\n        for n in range(0, N):\n            progress_bar.update(n)\n            psi0 = basis(N, n)\n            rho0 = Qobj(vec2mat(psi0.full()))\n            output = mesolve(H, rho0, tlist, [], [], args, options)\n            for k, t in enumerate(tlist):\n                u[:, n, k] = mat2vec(output.states[k].full()).T\n        progress_bar.finished()\n\n    else:\n        # calculate the propagator for the vector representation of the\n        # density matrix (a superoperator propagator)\n\n        N = H0.shape[0]\n        dims = [H0.dims, H0.dims]\n\n        u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)\n\n        if sparse:\n            progress_bar.start(N * N)\n            for n in range(N * N):\n                progress_bar.update(n)\n                psi0 = basis(N * N, n)\n                psi0.dims = [dims[0], 1]\n                rho0 = vector_to_operator(psi0)\n                output = mesolve(H, rho0, tlist, c_op_list, [], args, options)\n                for k, t in enumerate(tlist):\n                    u[:, n, k] = operator_to_vector(\n                        output.states[k]).full(squeeze=True)\n            progress_bar.finished()\n\n        else:\n            progress_bar.start(N * N)\n            for n in range(N * N):\n                progress_bar.update(n)\n                psi0 = basis(N * N, n)\n                rho0 = Qobj(vec2mat(psi0.full()))\n                output = mesolve(H, rho0, tlist, c_op_list, [], args, options)\n                for k, t in enumerate(tlist):\n                    u[:, n, k] = mat2vec(output.states[k].full()).T\n            progress_bar.finished()\n\n    if len(tlist) == 2:\n        return Qobj(u[:, :, 1], dims=dims)\n    else:\n        return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]\n\n\ndef _get_min_and_index(lst):\n    \"\"\"\n    Private function for obtaining min and max indicies.\n    \"\"\"\n    minval, minidx = lst[0], 0\n    for i, v in enumerate(lst[1:]):\n        if v < minval:\n            minval, minidx = v, i + 1\n    return minval, minidx\n\n\ndef propagator_steadystate(U):\n    \"\"\"Find the steady state for successive applications of the propagator\n    :math:`U`.\n\n    Parameters\n    ----------\n    U : qobj\n        Operator representing the propagator.\n\n    Returns\n    -------\n    a : qobj\n        Instance representing the steady-state density matrix.\n\n    \"\"\"\n\n    evals, evecs = la.eig(U.full())\n\n    ev_min, ev_idx = _get_min_and_index(abs(evals - 1.0))\n\n    evecs = evecs.T\n    rho = Qobj(vec2mat(evecs[ev_idx]), dims=U.dims[0])\n    rho = rho * (1.0 / rho.tr())\n    rho = 0.5 * (rho + rho.dag())  # make sure rho is herm\n    return rho\n", "path": "qutip/propagator.py"}]}