We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
QuTiP 4.7.4: incompatibility with the latest scipy (1.12.0)
https://github.com/qutip/qutip/blob/f5149616a4071a273e7e48a63d956836739c4569/qutip/parallel.py#L7

When the latest scipy version is used (1.12.0), QuTiP (4.7.4) cannot be imported since `from scipy import array` is no longer supported in scipy.

Code to reproduce the bug: 
`import qutip`

Output:
```
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Cell In[1], line 1
----> 1 import qutip

File ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/__init__.py:133
    131 # graphics
    132 from qutip.bloch import *
--> 133 from qutip.visualization import *
    134 from qutip.orbital import *
    135 from qutip.bloch3d import *

File ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/visualization.py:24
     22 from qutip.qobj import Qobj, isket
     23 from qutip.states import ket2dm
---> 24 from qutip.wigner import wigner
     25 from qutip.tensor import tensor
     26 from qutip.matplotlib_utilities import complex_phase_cmap

File ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/wigner.py:19
     17 import qutip
     18 from qutip import Qobj, ket2dm, jmat
---> 19 from qutip.parallel import parfor
     20 from qutip.cy.sparse_utils import _csr_get_diag
     21 from qutip.sparse import eigh

File ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/parallel.py:7
      1 """
      2 This function provides functions for parallel execution of loops and function
      3 mappings, using the builtin Python module multiprocessing.
      4 """
      5 __all__ = ['parfor', 'parallel_map', 'serial_map']
----> 7 from scipy import array
      8 import multiprocessing
      9 from functools import partial

ImportError: cannot import name 'array' from 'scipy' (/Users/konstantin/anaconda3/envs/test/lib/python3.11/site-packages/scipy/__init__.py)
```


--- 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/parallel.py`
Content:
```
1 """
2 This function provides functions for parallel execution of loops and function
3 mappings, using the builtin Python module multiprocessing.
4 """
5 __all__ = ['parfor', 'parallel_map', 'serial_map']
6 
7 from scipy import array
8 import multiprocessing
9 from functools import partial
10 import os
11 import sys
12 import signal
13 import qutip.settings as qset
14 from qutip.ui.progressbar import BaseProgressBar, TextProgressBar
15 
16 
17 if sys.platform == 'darwin':
18     Pool = multiprocessing.get_context('fork').Pool
19 else:
20     Pool = multiprocessing.Pool
21 
22 
23 def _task_wrapper(args):
24     try:
25         return args[0](*args[1])
26     except KeyboardInterrupt:
27         os.kill(args[2], signal.SIGINT)
28         sys.exit(1)
29 
30 
31 def _task_wrapper_with_args(args, user_args):
32     try:
33         return args[0](*args[1], **user_args)
34     except KeyboardInterrupt:
35         os.kill(args[2], signal.SIGINT)
36         sys.exit(1)
37 
38 
39 def parfor(func, *args, **kwargs):
40     """Executes a multi-variable function in parallel on the local machine.
41 
42     Parallel execution of a for-loop over function `func` for multiple input
43     arguments and keyword arguments.
44 
45     .. note::
46 
47         From QuTiP 3.1, we recommend to use :func:`qutip.parallel.parallel_map`
48         instead of this function.
49 
50     Parameters
51     ----------
52     func : function_type
53         A function to run in parallel on the local machine. The function 'func'
54         accepts a series of arguments that are passed to the function as
55         variables. In general, the function can have multiple input variables,
56         and these arguments must be passed in the same order as they are
57         defined in the function definition.  In addition, the user can pass
58         multiple keyword arguments to the function.
59 
60     The following keyword argument is reserved:
61 
62     num_cpus : int
63         Number of CPU's to use.  Default uses maximum number of CPU's.
64         Performance degrades if num_cpus is larger than the physical CPU
65         count of your machine.
66 
67     Returns
68     -------
69     result : list
70         A ``list`` with length equal to number of input parameters
71         containing the output from `func`.
72 
73     """
74     os.environ['QUTIP_IN_PARALLEL'] = 'TRUE'
75     kw = _default_kwargs()
76     if 'num_cpus' in kwargs.keys():
77         kw['num_cpus'] = kwargs['num_cpus']
78         del kwargs['num_cpus']
79     if len(kwargs) != 0:
80         task_func = partial(_task_wrapper_with_args, user_args=kwargs)
81     else:
82         task_func = _task_wrapper
83 
84     if kw['num_cpus'] > qset.num_cpus:
85         print("Requested number of CPUs (%s) " % kw['num_cpus'] +
86               "is larger than physical number (%s)." % qset.num_cpus)
87         print("Reduce 'num_cpus' for greater performance.")
88 
89     pool = Pool(processes=kw['num_cpus'])
90     args = [list(arg) for arg in args]
91     var = [[args[j][i] for j in range(len(args))]
92            for i in range(len(list(args[0])))]
93     try:
94         map_args = ((func, v, os.getpid()) for v in var)
95         par_return = list(pool.map(task_func, map_args))
96 
97         pool.terminate()
98         pool.join()
99         os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'
100         if isinstance(par_return[0], tuple):
101             par_return = [elem for elem in par_return]
102             num_elems = len(par_return[0])
103             dt = [type(ii) for ii in par_return[0]]
104             return [array([elem[ii] for elem in par_return], dtype=dt[ii])
105                     for ii in range(num_elems)]
106         else:
107             return par_return
108 
109     except KeyboardInterrupt:
110         os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'
111         pool.terminate()
112 
113 
114 def serial_map(task, values, task_args=tuple(), task_kwargs={}, **kwargs):
115     """
116     Serial mapping function with the same call signature as parallel_map, for
117     easy switching between serial and parallel execution. This
118     is functionally equivalent to::
119 
120         result = [task(value, *task_args, **task_kwargs) for value in values]
121 
122     This function work as a drop-in replacement of
123     :func:`qutip.parallel.parallel_map`.
124 
125     Parameters
126     ----------
127     task : a Python function
128         The function that is to be called for each value in ``task_vec``.
129     values : array / list
130         The list or array of values for which the ``task`` function is to be
131         evaluated.
132     task_args : list / dictionary
133         The optional additional argument to the ``task`` function.
134     task_kwargs : list / dictionary
135         The optional additional keyword argument to the ``task`` function.
136     progress_bar : ProgressBar
137         Progress bar class instance for showing progress.
138 
139     Returns
140     --------
141     result : list
142         The result list contains the value of
143         ``task(value, *task_args, **task_kwargs)`` for each
144         value in ``values``.
145 
146     """
147     try:
148         progress_bar = kwargs['progress_bar']
149         if progress_bar is True:
150             progress_bar = TextProgressBar()
151     except:
152         progress_bar = BaseProgressBar()
153 
154     progress_bar.start(len(values))
155     results = []
156     for n, value in enumerate(values):
157         progress_bar.update(n)
158         result = task(value, *task_args, **task_kwargs)
159         results.append(result)
160     progress_bar.finished()
161 
162     return results
163 
164 
165 def parallel_map(task, values, task_args=tuple(), task_kwargs={}, **kwargs):
166     """
167     Parallel execution of a mapping of `values` to the function `task`. This
168     is functionally equivalent to::
169 
170         result = [task(value, *task_args, **task_kwargs) for value in values]
171 
172     Parameters
173     ----------
174     task : a Python function
175         The function that is to be called for each value in ``task_vec``.
176     values : array / list
177         The list or array of values for which the ``task`` function is to be
178         evaluated.
179     task_args : list / dictionary
180         The optional additional argument to the ``task`` function.
181     task_kwargs : list / dictionary
182         The optional additional keyword argument to the ``task`` function.
183     progress_bar : ProgressBar
184         Progress bar class instance for showing progress.
185 
186     Returns
187     --------
188     result : list
189         The result list contains the value of
190         ``task(value, *task_args, **task_kwargs)`` for
191         each value in ``values``.
192 
193     """
194     os.environ['QUTIP_IN_PARALLEL'] = 'TRUE'
195     kw = _default_kwargs()
196     if 'num_cpus' in kwargs:
197         kw['num_cpus'] = kwargs['num_cpus']
198 
199     try:
200         progress_bar = kwargs['progress_bar']
201         if progress_bar is True:
202             progress_bar = TextProgressBar()
203     except:
204         progress_bar = BaseProgressBar()
205 
206     progress_bar.start(len(values))
207     nfinished = [0]
208 
209     def _update_progress_bar(x):
210         nfinished[0] += 1
211         progress_bar.update(nfinished[0])
212 
213     try:
214         pool = Pool(processes=kw['num_cpus'])
215 
216         async_res = [pool.apply_async(task, (value,) + task_args, task_kwargs,
217                                       _update_progress_bar)
218                      for value in values]
219 
220         while not all([ar.ready() for ar in async_res]):
221             for ar in async_res:
222                 ar.wait(timeout=0.1)
223 
224         pool.terminate()
225         pool.join()
226 
227     except KeyboardInterrupt as e:
228         os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'
229         pool.terminate()
230         pool.join()
231         raise e
232 
233     progress_bar.finished()
234     os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'
235     return [ar.get() for ar in async_res]
236 
237 
238 def _default_kwargs():
239     settings = {'num_cpus': qset.num_cpus}
240     return settings
241
```
--- 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/parallel.py b/qutip/parallel.py
--- a/qutip/parallel.py
+++ b/qutip/parallel.py
@@ -4,7 +4,7 @@
 """
 __all__ = ['parfor', 'parallel_map', 'serial_map']
 
-from scipy import array
+from numpy import array
 import multiprocessing
 from functools import partial
 import os

{"golden_diff": "diff --git a/qutip/parallel.py b/qutip/parallel.py\n--- a/qutip/parallel.py\n+++ b/qutip/parallel.py\n@@ -4,7 +4,7 @@\n \"\"\"\n __all__ = ['parfor', 'parallel_map', 'serial_map']\n \n-from scipy import array\n+from numpy import array\n import multiprocessing\n from functools import partial\n import os\n", "issue": "QuTiP 4.7.4: incompatibility with the latest scipy (1.12.0)\nhttps://github.com/qutip/qutip/blob/f5149616a4071a273e7e48a63d956836739c4569/qutip/parallel.py#L7\r\n\r\nWhen the latest scipy version is used (1.12.0), QuTiP (4.7.4) cannot be imported since `from scipy import array` is no longer supported in scipy.\r\n\r\nCode to reproduce the bug: \r\n`import qutip`\r\n\r\nOutput:\r\n```\r\n---------------------------------------------------------------------------\r\nImportError                               Traceback (most recent call last)\r\nCell In[1], line 1\r\n----> 1 import qutip\r\n\r\nFile ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/__init__.py:133\r\n    131 # graphics\r\n    132 from qutip.bloch import *\r\n--> 133 from qutip.visualization import *\r\n    134 from qutip.orbital import *\r\n    135 from qutip.bloch3d import *\r\n\r\nFile ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/visualization.py:24\r\n     22 from qutip.qobj import Qobj, isket\r\n     23 from qutip.states import ket2dm\r\n---> 24 from qutip.wigner import wigner\r\n     25 from qutip.tensor import tensor\r\n     26 from qutip.matplotlib_utilities import complex_phase_cmap\r\n\r\nFile ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/wigner.py:19\r\n     17 import qutip\r\n     18 from qutip import Qobj, ket2dm, jmat\r\n---> 19 from qutip.parallel import parfor\r\n     20 from qutip.cy.sparse_utils import _csr_get_diag\r\n     21 from qutip.sparse import eigh\r\n\r\nFile ~/anaconda3/envs/test/lib/python3.11/site-packages/qutip/parallel.py:7\r\n      1 \"\"\"\r\n      2 This function provides functions for parallel execution of loops and function\r\n      3 mappings, using the builtin Python module multiprocessing.\r\n      4 \"\"\"\r\n      5 __all__ = ['parfor', 'parallel_map', 'serial_map']\r\n----> 7 from scipy import array\r\n      8 import multiprocessing\r\n      9 from functools import partial\r\n\r\nImportError: cannot import name 'array' from 'scipy' (/Users/konstantin/anaconda3/envs/test/lib/python3.11/site-packages/scipy/__init__.py)\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\nThis function provides functions for parallel execution of loops and function\nmappings, using the builtin Python module multiprocessing.\n\"\"\"\n__all__ = ['parfor', 'parallel_map', 'serial_map']\n\nfrom scipy import array\nimport multiprocessing\nfrom functools import partial\nimport os\nimport sys\nimport signal\nimport qutip.settings as qset\nfrom qutip.ui.progressbar import BaseProgressBar, TextProgressBar\n\n\nif sys.platform == 'darwin':\n    Pool = multiprocessing.get_context('fork').Pool\nelse:\n    Pool = multiprocessing.Pool\n\n\ndef _task_wrapper(args):\n    try:\n        return args[0](*args[1])\n    except KeyboardInterrupt:\n        os.kill(args[2], signal.SIGINT)\n        sys.exit(1)\n\n\ndef _task_wrapper_with_args(args, user_args):\n    try:\n        return args[0](*args[1], **user_args)\n    except KeyboardInterrupt:\n        os.kill(args[2], signal.SIGINT)\n        sys.exit(1)\n\n\ndef parfor(func, *args, **kwargs):\n    \"\"\"Executes a multi-variable function in parallel on the local machine.\n\n    Parallel execution of a for-loop over function `func` for multiple input\n    arguments and keyword arguments.\n\n    .. note::\n\n        From QuTiP 3.1, we recommend to use :func:`qutip.parallel.parallel_map`\n        instead of this function.\n\n    Parameters\n    ----------\n    func : function_type\n        A function to run in parallel on the local machine. The function 'func'\n        accepts a series of arguments that are passed to the function as\n        variables. In general, the function can have multiple input variables,\n        and these arguments must be passed in the same order as they are\n        defined in the function definition.  In addition, the user can pass\n        multiple keyword arguments to the function.\n\n    The following keyword argument is reserved:\n\n    num_cpus : int\n        Number of CPU's to use.  Default uses maximum number of CPU's.\n        Performance degrades if num_cpus is larger than the physical CPU\n        count of your machine.\n\n    Returns\n    -------\n    result : list\n        A ``list`` with length equal to number of input parameters\n        containing the output from `func`.\n\n    \"\"\"\n    os.environ['QUTIP_IN_PARALLEL'] = 'TRUE'\n    kw = _default_kwargs()\n    if 'num_cpus' in kwargs.keys():\n        kw['num_cpus'] = kwargs['num_cpus']\n        del kwargs['num_cpus']\n    if len(kwargs) != 0:\n        task_func = partial(_task_wrapper_with_args, user_args=kwargs)\n    else:\n        task_func = _task_wrapper\n\n    if kw['num_cpus'] > qset.num_cpus:\n        print(\"Requested number of CPUs (%s) \" % kw['num_cpus'] +\n              \"is larger than physical number (%s).\" % qset.num_cpus)\n        print(\"Reduce 'num_cpus' for greater performance.\")\n\n    pool = Pool(processes=kw['num_cpus'])\n    args = [list(arg) for arg in args]\n    var = [[args[j][i] for j in range(len(args))]\n           for i in range(len(list(args[0])))]\n    try:\n        map_args = ((func, v, os.getpid()) for v in var)\n        par_return = list(pool.map(task_func, map_args))\n\n        pool.terminate()\n        pool.join()\n        os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n        if isinstance(par_return[0], tuple):\n            par_return = [elem for elem in par_return]\n            num_elems = len(par_return[0])\n            dt = [type(ii) for ii in par_return[0]]\n            return [array([elem[ii] for elem in par_return], dtype=dt[ii])\n                    for ii in range(num_elems)]\n        else:\n            return par_return\n\n    except KeyboardInterrupt:\n        os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n        pool.terminate()\n\n\ndef serial_map(task, values, task_args=tuple(), task_kwargs={}, **kwargs):\n    \"\"\"\n    Serial mapping function with the same call signature as parallel_map, for\n    easy switching between serial and parallel execution. This\n    is functionally equivalent to::\n\n        result = [task(value, *task_args, **task_kwargs) for value in values]\n\n    This function work as a drop-in replacement of\n    :func:`qutip.parallel.parallel_map`.\n\n    Parameters\n    ----------\n    task : a Python function\n        The function that is to be called for each value in ``task_vec``.\n    values : array / list\n        The list or array of values for which the ``task`` function is to be\n        evaluated.\n    task_args : list / dictionary\n        The optional additional argument to the ``task`` function.\n    task_kwargs : list / dictionary\n        The optional additional keyword argument to the ``task`` function.\n    progress_bar : ProgressBar\n        Progress bar class instance for showing progress.\n\n    Returns\n    --------\n    result : list\n        The result list contains the value of\n        ``task(value, *task_args, **task_kwargs)`` for each\n        value in ``values``.\n\n    \"\"\"\n    try:\n        progress_bar = kwargs['progress_bar']\n        if progress_bar is True:\n            progress_bar = TextProgressBar()\n    except:\n        progress_bar = BaseProgressBar()\n\n    progress_bar.start(len(values))\n    results = []\n    for n, value in enumerate(values):\n        progress_bar.update(n)\n        result = task(value, *task_args, **task_kwargs)\n        results.append(result)\n    progress_bar.finished()\n\n    return results\n\n\ndef parallel_map(task, values, task_args=tuple(), task_kwargs={}, **kwargs):\n    \"\"\"\n    Parallel execution of a mapping of `values` to the function `task`. This\n    is functionally equivalent to::\n\n        result = [task(value, *task_args, **task_kwargs) for value in values]\n\n    Parameters\n    ----------\n    task : a Python function\n        The function that is to be called for each value in ``task_vec``.\n    values : array / list\n        The list or array of values for which the ``task`` function is to be\n        evaluated.\n    task_args : list / dictionary\n        The optional additional argument to the ``task`` function.\n    task_kwargs : list / dictionary\n        The optional additional keyword argument to the ``task`` function.\n    progress_bar : ProgressBar\n        Progress bar class instance for showing progress.\n\n    Returns\n    --------\n    result : list\n        The result list contains the value of\n        ``task(value, *task_args, **task_kwargs)`` for\n        each value in ``values``.\n\n    \"\"\"\n    os.environ['QUTIP_IN_PARALLEL'] = 'TRUE'\n    kw = _default_kwargs()\n    if 'num_cpus' in kwargs:\n        kw['num_cpus'] = kwargs['num_cpus']\n\n    try:\n        progress_bar = kwargs['progress_bar']\n        if progress_bar is True:\n            progress_bar = TextProgressBar()\n    except:\n        progress_bar = BaseProgressBar()\n\n    progress_bar.start(len(values))\n    nfinished = [0]\n\n    def _update_progress_bar(x):\n        nfinished[0] += 1\n        progress_bar.update(nfinished[0])\n\n    try:\n        pool = Pool(processes=kw['num_cpus'])\n\n        async_res = [pool.apply_async(task, (value,) + task_args, task_kwargs,\n                                      _update_progress_bar)\n                     for value in values]\n\n        while not all([ar.ready() for ar in async_res]):\n            for ar in async_res:\n                ar.wait(timeout=0.1)\n\n        pool.terminate()\n        pool.join()\n\n    except KeyboardInterrupt as e:\n        os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n        pool.terminate()\n        pool.join()\n        raise e\n\n    progress_bar.finished()\n    os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n    return [ar.get() for ar in async_res]\n\n\ndef _default_kwargs():\n    settings = {'num_cpus': qset.num_cpus}\n    return settings\n", "path": "qutip/parallel.py"}], "after_files": [{"content": "\"\"\"\nThis function provides functions for parallel execution of loops and function\nmappings, using the builtin Python module multiprocessing.\n\"\"\"\n__all__ = ['parfor', 'parallel_map', 'serial_map']\n\nfrom numpy import array\nimport multiprocessing\nfrom functools import partial\nimport os\nimport sys\nimport signal\nimport qutip.settings as qset\nfrom qutip.ui.progressbar import BaseProgressBar, TextProgressBar\n\n\nif sys.platform == 'darwin':\n    Pool = multiprocessing.get_context('fork').Pool\nelse:\n    Pool = multiprocessing.Pool\n\n\ndef _task_wrapper(args):\n    try:\n        return args[0](*args[1])\n    except KeyboardInterrupt:\n        os.kill(args[2], signal.SIGINT)\n        sys.exit(1)\n\n\ndef _task_wrapper_with_args(args, user_args):\n    try:\n        return args[0](*args[1], **user_args)\n    except KeyboardInterrupt:\n        os.kill(args[2], signal.SIGINT)\n        sys.exit(1)\n\n\ndef parfor(func, *args, **kwargs):\n    \"\"\"Executes a multi-variable function in parallel on the local machine.\n\n    Parallel execution of a for-loop over function `func` for multiple input\n    arguments and keyword arguments.\n\n    .. note::\n\n        From QuTiP 3.1, we recommend to use :func:`qutip.parallel.parallel_map`\n        instead of this function.\n\n    Parameters\n    ----------\n    func : function_type\n        A function to run in parallel on the local machine. The function 'func'\n        accepts a series of arguments that are passed to the function as\n        variables. In general, the function can have multiple input variables,\n        and these arguments must be passed in the same order as they are\n        defined in the function definition.  In addition, the user can pass\n        multiple keyword arguments to the function.\n\n    The following keyword argument is reserved:\n\n    num_cpus : int\n        Number of CPU's to use.  Default uses maximum number of CPU's.\n        Performance degrades if num_cpus is larger than the physical CPU\n        count of your machine.\n\n    Returns\n    -------\n    result : list\n        A ``list`` with length equal to number of input parameters\n        containing the output from `func`.\n\n    \"\"\"\n    os.environ['QUTIP_IN_PARALLEL'] = 'TRUE'\n    kw = _default_kwargs()\n    if 'num_cpus' in kwargs.keys():\n        kw['num_cpus'] = kwargs['num_cpus']\n        del kwargs['num_cpus']\n    if len(kwargs) != 0:\n        task_func = partial(_task_wrapper_with_args, user_args=kwargs)\n    else:\n        task_func = _task_wrapper\n\n    if kw['num_cpus'] > qset.num_cpus:\n        print(\"Requested number of CPUs (%s) \" % kw['num_cpus'] +\n              \"is larger than physical number (%s).\" % qset.num_cpus)\n        print(\"Reduce 'num_cpus' for greater performance.\")\n\n    pool = Pool(processes=kw['num_cpus'])\n    args = [list(arg) for arg in args]\n    var = [[args[j][i] for j in range(len(args))]\n           for i in range(len(list(args[0])))]\n    try:\n        map_args = ((func, v, os.getpid()) for v in var)\n        par_return = list(pool.map(task_func, map_args))\n\n        pool.terminate()\n        pool.join()\n        os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n        if isinstance(par_return[0], tuple):\n            par_return = [elem for elem in par_return]\n            num_elems = len(par_return[0])\n            dt = [type(ii) for ii in par_return[0]]\n            return [array([elem[ii] for elem in par_return], dtype=dt[ii])\n                    for ii in range(num_elems)]\n        else:\n            return par_return\n\n    except KeyboardInterrupt:\n        os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n        pool.terminate()\n\n\ndef serial_map(task, values, task_args=tuple(), task_kwargs={}, **kwargs):\n    \"\"\"\n    Serial mapping function with the same call signature as parallel_map, for\n    easy switching between serial and parallel execution. This\n    is functionally equivalent to::\n\n        result = [task(value, *task_args, **task_kwargs) for value in values]\n\n    This function work as a drop-in replacement of\n    :func:`qutip.parallel.parallel_map`.\n\n    Parameters\n    ----------\n    task : a Python function\n        The function that is to be called for each value in ``task_vec``.\n    values : array / list\n        The list or array of values for which the ``task`` function is to be\n        evaluated.\n    task_args : list / dictionary\n        The optional additional argument to the ``task`` function.\n    task_kwargs : list / dictionary\n        The optional additional keyword argument to the ``task`` function.\n    progress_bar : ProgressBar\n        Progress bar class instance for showing progress.\n\n    Returns\n    --------\n    result : list\n        The result list contains the value of\n        ``task(value, *task_args, **task_kwargs)`` for each\n        value in ``values``.\n\n    \"\"\"\n    try:\n        progress_bar = kwargs['progress_bar']\n        if progress_bar is True:\n            progress_bar = TextProgressBar()\n    except:\n        progress_bar = BaseProgressBar()\n\n    progress_bar.start(len(values))\n    results = []\n    for n, value in enumerate(values):\n        progress_bar.update(n)\n        result = task(value, *task_args, **task_kwargs)\n        results.append(result)\n    progress_bar.finished()\n\n    return results\n\n\ndef parallel_map(task, values, task_args=tuple(), task_kwargs={}, **kwargs):\n    \"\"\"\n    Parallel execution of a mapping of `values` to the function `task`. This\n    is functionally equivalent to::\n\n        result = [task(value, *task_args, **task_kwargs) for value in values]\n\n    Parameters\n    ----------\n    task : a Python function\n        The function that is to be called for each value in ``task_vec``.\n    values : array / list\n        The list or array of values for which the ``task`` function is to be\n        evaluated.\n    task_args : list / dictionary\n        The optional additional argument to the ``task`` function.\n    task_kwargs : list / dictionary\n        The optional additional keyword argument to the ``task`` function.\n    progress_bar : ProgressBar\n        Progress bar class instance for showing progress.\n\n    Returns\n    --------\n    result : list\n        The result list contains the value of\n        ``task(value, *task_args, **task_kwargs)`` for\n        each value in ``values``.\n\n    \"\"\"\n    os.environ['QUTIP_IN_PARALLEL'] = 'TRUE'\n    kw = _default_kwargs()\n    if 'num_cpus' in kwargs:\n        kw['num_cpus'] = kwargs['num_cpus']\n\n    try:\n        progress_bar = kwargs['progress_bar']\n        if progress_bar is True:\n            progress_bar = TextProgressBar()\n    except:\n        progress_bar = BaseProgressBar()\n\n    progress_bar.start(len(values))\n    nfinished = [0]\n\n    def _update_progress_bar(x):\n        nfinished[0] += 1\n        progress_bar.update(nfinished[0])\n\n    try:\n        pool = Pool(processes=kw['num_cpus'])\n\n        async_res = [pool.apply_async(task, (value,) + task_args, task_kwargs,\n                                      _update_progress_bar)\n                     for value in values]\n\n        while not all([ar.ready() for ar in async_res]):\n            for ar in async_res:\n                ar.wait(timeout=0.1)\n\n        pool.terminate()\n        pool.join()\n\n    except KeyboardInterrupt as e:\n        os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n        pool.terminate()\n        pool.join()\n        raise e\n\n    progress_bar.finished()\n    os.environ['QUTIP_IN_PARALLEL'] = 'FALSE'\n    return [ar.get() for ar in async_res]\n\n\ndef _default_kwargs():\n    settings = {'num_cpus': qset.num_cpus}\n    return settings\n", "path": "qutip/parallel.py"}]}