qutip-cuquantum 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. qutip_cuquantum-0.1.0/LICENSE +28 -0
  2. qutip_cuquantum-0.1.0/MANIFEST.in +5 -0
  3. qutip_cuquantum-0.1.0/PKG-INFO +101 -0
  4. qutip_cuquantum-0.1.0/README.md +43 -0
  5. qutip_cuquantum-0.1.0/VERSION +1 -0
  6. qutip_cuquantum-0.1.0/pyproject.toml +57 -0
  7. qutip_cuquantum-0.1.0/setup.cfg +4 -0
  8. qutip_cuquantum-0.1.0/setup.py +122 -0
  9. qutip_cuquantum-0.1.0/src/qutip_cuquantum/__init__.py +108 -0
  10. qutip_cuquantum-0.1.0/src/qutip_cuquantum/callable.py +118 -0
  11. qutip_cuquantum-0.1.0/src/qutip_cuquantum/family.py +8 -0
  12. qutip_cuquantum-0.1.0/src/qutip_cuquantum/ode.py +92 -0
  13. qutip_cuquantum-0.1.0/src/qutip_cuquantum/operator.py +761 -0
  14. qutip_cuquantum-0.1.0/src/qutip_cuquantum/qobjevo.cpp +37193 -0
  15. qutip_cuquantum-0.1.0/src/qutip_cuquantum/state.py +279 -0
  16. qutip_cuquantum-0.1.0/src/qutip_cuquantum/utils.py +119 -0
  17. qutip_cuquantum-0.1.0/src/qutip_cuquantum/version.py +4 -0
  18. qutip_cuquantum-0.1.0/src/qutip_cuquantum.egg-info/PKG-INFO +101 -0
  19. qutip_cuquantum-0.1.0/src/qutip_cuquantum.egg-info/SOURCES.txt +25 -0
  20. qutip_cuquantum-0.1.0/src/qutip_cuquantum.egg-info/dependency_links.txt +1 -0
  21. qutip_cuquantum-0.1.0/src/qutip_cuquantum.egg-info/entry_points.txt +2 -0
  22. qutip_cuquantum-0.1.0/src/qutip_cuquantum.egg-info/requires.txt +12 -0
  23. qutip_cuquantum-0.1.0/src/qutip_cuquantum.egg-info/top_level.txt +1 -0
  24. qutip_cuquantum-0.1.0/tests/test_family.py +12 -0
  25. qutip_cuquantum-0.1.0/tests/test_operator.py +359 -0
  26. qutip_cuquantum-0.1.0/tests/test_solver.py +155 -0
  27. qutip_cuquantum-0.1.0/tests/test_state.py +184 -0
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, QuTiP
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,5 @@
1
+ include VERSION
2
+ # pyproject.toml is automatically included in setuptools>=43.0, but we can
3
+ # support back to 36.6 (which added PEP 517 builds) if we're explicit.
4
+ include pyproject.toml
5
+ recursive-include tests *.py
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: qutip-cuquantum
3
+ Version: 0.1.0
4
+ Summary: cuQuantum backend for QuTiP
5
+ Author-email: Eric Giguère <qutip-admin@googlegroups.com>
6
+ License: BSD 3-Clause License
7
+
8
+ Copyright (c) 2025, QuTiP
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+
13
+ 1. Redistributions of source code must retain the above copyright notice, this
14
+ list of conditions and the following disclaimer.
15
+
16
+ 2. Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+
20
+ 3. Neither the name of the copyright holder nor the names of its
21
+ contributors may be used to endorse or promote products derived from
22
+ this software without specific prior written permission.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ Project-URL: Homepage, https://qutip.org
36
+ Project-URL: Bug Tracker, https://github.com/qutip/qutip-cuquantum/issues
37
+ Project-URL: Documentation, https://qutip-cuquantum.readthedocs.io/en/latest/
38
+ Keywords: quantum,physics,dynamics,gpu,linear-algebra
39
+ Classifier: Development Status :: 2 - Pre-Alpha
40
+ Classifier: Intended Audience :: Science/Research
41
+ Classifier: Programming Language :: Python
42
+ Classifier: Programming Language :: Python :: 3
43
+ Classifier: Topic :: Scientific/Engineering
44
+ Classifier: Operating System :: Unix
45
+ Requires-Python: >=3.11
46
+ Description-Content-Type: text/markdown
47
+ License-File: LICENSE
48
+ Requires-Dist: qutip>=5.2.1
49
+ Provides-Extra: cuda11
50
+ Requires-Dist: cupy-cuda11x; extra == "cuda11"
51
+ Requires-Dist: cuquantum-python-cu11; extra == "cuda11"
52
+ Provides-Extra: cuda12
53
+ Requires-Dist: cupy-cuda12x; extra == "cuda12"
54
+ Requires-Dist: cuquantum-python-cu12; extra == "cuda12"
55
+ Provides-Extra: tests
56
+ Requires-Dist: pytest>=6.0; extra == "tests"
57
+ Dynamic: license-file
58
+
59
+ # qutip-cuquantum
60
+
61
+ Provide cuQuantum's cuDensityMat as a backend for QuTiP.
62
+
63
+ This backend is specifically designed for simulating **large, composite quantum systems** by performing tensor network contractions on the GPU.
64
+
65
+ ## Installation
66
+
67
+ qutip-cuquantum is available on pypi.
68
+
69
+ ```
70
+ pip install -U qutip>=5.2.1
71
+ pip install qutip-cuquantum
72
+ ```
73
+
74
+
75
+ It require cuquantum to be installed at runtime.
76
+ If you have cuda already installed, you can install dependencies with:
77
+
78
+ ```
79
+ pip install qutip-cuquantum[cuda11]
80
+ ```
81
+ or
82
+ ```
83
+ pip install qutip-cuquantum[cuda12]
84
+ ```
85
+
86
+ If it does not work, you may need to install cuQuantum yourself,
87
+ see [nvidia's documentation](https://docs.nvidia.com/cuda/cuquantum/latest/getting-started/index.html#installing-cuquantum) for installation instruction.
88
+
89
+ ## Usage
90
+
91
+ In simple case, simply calling `set_as_default` before a qutip script should be sufficient to use the backend common solver:
92
+
93
+ ```
94
+ import qutip_cuquantum
95
+ from cuquantum.densitymat import WorkStream
96
+
97
+ qutip_cuquantum.set_as_default(WorkStream())
98
+ ```
99
+
100
+ qutip-cuquantum work well to speed-up large simulation using `mesolve` or `sesolve`.
101
+ However this backend is not compatible with advanced qutip solvers (brmesolve, HEOM) and other various feature.
@@ -0,0 +1,43 @@
1
+ # qutip-cuquantum
2
+
3
+ Provide cuQuantum's cuDensityMat as a backend for QuTiP.
4
+
5
+ This backend is specifically designed for simulating **large, composite quantum systems** by performing tensor network contractions on the GPU.
6
+
7
+ ## Installation
8
+
9
+ qutip-cuquantum is available on pypi.
10
+
11
+ ```
12
+ pip install -U qutip>=5.2.1
13
+ pip install qutip-cuquantum
14
+ ```
15
+
16
+
17
+ It require cuquantum to be installed at runtime.
18
+ If you have cuda already installed, you can install dependencies with:
19
+
20
+ ```
21
+ pip install qutip-cuquantum[cuda11]
22
+ ```
23
+ or
24
+ ```
25
+ pip install qutip-cuquantum[cuda12]
26
+ ```
27
+
28
+ If it does not work, you may need to install cuQuantum yourself,
29
+ see [nvidia's documentation](https://docs.nvidia.com/cuda/cuquantum/latest/getting-started/index.html#installing-cuquantum) for installation instruction.
30
+
31
+ ## Usage
32
+
33
+ In simple case, simply calling `set_as_default` before a qutip script should be sufficient to use the backend common solver:
34
+
35
+ ```
36
+ import qutip_cuquantum
37
+ from cuquantum.densitymat import WorkStream
38
+
39
+ qutip_cuquantum.set_as_default(WorkStream())
40
+ ```
41
+
42
+ qutip-cuquantum work well to speed-up large simulation using `mesolve` or `sesolve`.
43
+ However this backend is not compatible with advanced qutip solvers (brmesolve, HEOM) and other various feature.
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools",
4
+ "packaging",
5
+ "wheel",
6
+ "Cython",
7
+ "qutip>=5.2.1",
8
+ "numpy",
9
+ ]
10
+ build-backend = "setuptools.build_meta"
11
+
12
+ [project]
13
+ name = "qutip-cuquantum"
14
+ dynamic = ["version"]
15
+ description = "cuQuantum backend for QuTiP"
16
+ readme = "README.md"
17
+ requires-python = ">=3.11"
18
+ license = { file = "LICENSE" }
19
+ keywords = ["quantum", "physics", "dynamics", "gpu", "linear-algebra"]
20
+ authors = [
21
+ {name = "Eric Giguère", email = "qutip-admin@googlegroups.com"}
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 2 - Pre-Alpha",
25
+ "Intended Audience :: Science/Research",
26
+ "Programming Language :: Python",
27
+ "Programming Language :: Python :: 3",
28
+ "Topic :: Scientific/Engineering",
29
+ "Operating System :: Unix",
30
+ ]
31
+ dependencies = [
32
+ "qutip>=5.2.1",
33
+ ]
34
+
35
+ # URLs for your project
36
+ [project.urls]
37
+ Homepage = "https://qutip.org"
38
+ "Bug Tracker" = "https://github.com/qutip/qutip-cuquantum/issues"
39
+ Documentation = "https://qutip-cuquantum.readthedocs.io/en/latest/"
40
+
41
+ [project.optional-dependencies]
42
+ cuda11 = ["cupy-cuda11x", "cuquantum-python-cu11"]
43
+ cuda12 = ["cupy-cuda12x", "cuquantum-python-cu12"]
44
+ tests = ["pytest>=6.0"]
45
+
46
+ [project.entry-points."qutip.family"]
47
+ qutip_cuquantum = "qutip_cuquantum.family"
48
+
49
+ [tool.setuptools]
50
+ packages = { find = { where = ["src"] } }
51
+ package-dir = { "" = "src" }
52
+
53
+ [tool.pytest.ini_options]
54
+ addopts = "-Werror --strict-config --strict-markers -W ignore::DeprecationWarning"
55
+ testpaths = [
56
+ "tests",
57
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env python
2
+
3
+ import os
4
+ import subprocess
5
+ import sys
6
+
7
+ # Required third-party imports, must be specified in pyproject.toml.
8
+ import packaging.version
9
+ import setuptools
10
+ from Cython.Build import cythonize
11
+ import qutip
12
+ import numpy
13
+
14
+
15
+ def process_options():
16
+ """
17
+ Determine all runtime options, returning a dictionary of the results. The
18
+ keys are:
19
+ 'rootdir': str
20
+ The root directory of the setup. Almost certainly the directory
21
+ that this setup.py file is contained in.
22
+ 'release': bool
23
+ Is this a release build (True) or a local development build (False)
24
+ """
25
+ options = {}
26
+ options["rootdir"] = os.path.dirname(os.path.abspath(__file__))
27
+ options = _determine_version(options)
28
+ return options
29
+
30
+
31
+ def _determine_version(options):
32
+ """
33
+ Adds the 'short_version', 'version' and 'release' options.
34
+
35
+ Read from the VERSION file to discover the version. This should be a
36
+ single line file containing valid Python package public identifier (see PEP
37
+ 440), for example
38
+ 4.5.2rc2
39
+ 5.0.0
40
+ 5.1.1a1
41
+ We do that here rather than in setup.cfg so we can apply the local
42
+ versioning number as well.
43
+ """
44
+ version_filename = os.path.join(options["rootdir"], "VERSION")
45
+ with open(version_filename, "r") as version_file:
46
+ version_string = version_file.read().strip()
47
+ version = packaging.version.Version(version_string)
48
+ options["short_version"] = str(version.public)
49
+ options["release"] = not version.is_devrelease
50
+ if not options["release"]:
51
+ # Put the version string into canonical form, if it wasn't already.
52
+ version_string = str(version)
53
+ version_string += "+"
54
+ try:
55
+ git_out = subprocess.run(
56
+ ("git", "rev-parse", "--verify", "--short=7", "HEAD"),
57
+ check=True,
58
+ stdout=subprocess.PIPE,
59
+ stderr=subprocess.PIPE,
60
+ )
61
+ git_hash = git_out.stdout.decode(sys.stdout.encoding).strip()
62
+ version_string += git_hash or "nogit"
63
+ # CalledProcessError is for if the git command fails for internal
64
+ # reasons (e.g. we're not in a git repository), OSError is for if
65
+ # something goes wrong when trying to run git (e.g. it's not installed,
66
+ # or a permission error).
67
+ except (subprocess.CalledProcessError, OSError):
68
+ version_string += "nogit"
69
+ options["version"] = version_string
70
+ return options
71
+
72
+
73
+ def create_version_py_file(options):
74
+ """
75
+ Generate and write out the file version.py, which is used to produce the
76
+ '__version__' information for the module. This function will overwrite an
77
+ existing file at that location.
78
+ """
79
+ filename = os.path.join(options["rootdir"], "src", "qutip_cuquantum", "version.py")
80
+ content = "\n".join(
81
+ [
82
+ "# This file is automatically generated during package setup.",
83
+ f"short_version = '{options['short_version']}'",
84
+ f"version = '{options['version']}'",
85
+ f"release = {options['release']}",
86
+ ]
87
+ )
88
+ with open(filename, "w") as file:
89
+ print(content, file=file)
90
+
91
+
92
+
93
+ def get_ext_modules(options):
94
+ pyx_file = os.path.join("src", "qutip_cuquantum", "qobjevo.pyx")
95
+ include_dirs = [
96
+ numpy.get_include(),
97
+ os.path.abspath(os.path.join(qutip.core.data.__file__, os.pardir))
98
+ ]
99
+ print("*********************************************************************************")
100
+ print(include_dirs)
101
+ print(pyx_file)
102
+ print("*********************************************************************************")
103
+ ext = setuptools.Extension(
104
+ name="qutip_cuquantum.qobjevo",
105
+ sources=[pyx_file],
106
+ include_dirs=include_dirs,
107
+ language="c++",
108
+ )
109
+
110
+ return cythonize(ext)
111
+
112
+
113
+ if __name__ == "__main__":
114
+ options = process_options()
115
+ create_version_py_file(options)
116
+ # Most of the kwargs to setup are defined in setup.cfg; the only ones we
117
+ # keep here are ones that we have done some compile-time processing on.
118
+
119
+ setuptools.setup(
120
+ version = options["version"],
121
+ ext_modules = get_ext_modules(options),
122
+ )
@@ -0,0 +1,108 @@
1
+ try:
2
+ import cupy
3
+ except ImportError as err:
4
+ raise ImportError("\n".join([
5
+ "CuPy is not installed or could not be imported.",
6
+ "Please install the appropriate version for your CUDA toolkit manually.",
7
+ "For example, for CUDA 12.x, run:",
8
+ " pip install cupy-cuda12x",
9
+ "For other versions, please see the CuPy installation guide",
10
+ "https://docs.cupy.dev/en/stable/install.html",
11
+ ])) from err
12
+
13
+ try:
14
+ import cuquantum.densitymat
15
+ except ImportError as err:
16
+ raise ImportError("\n".join([
17
+ "cuQuantum.densitymat is not installed or could not be imported.",
18
+ "Please install the appropriate version for your CUDA toolkit manually.",
19
+ "For example, for CUDA 12.x, run:",
20
+ " pip install cuquantum-python-cu12",
21
+ "For other versions, please see the cuQuantum installation guide:",
22
+ "https://docs.nvidia.com/cuda/cuquantum/latest/getting-started/index.html",
23
+ ])) from err
24
+
25
+
26
+ import qutip
27
+ from qutip.core.options import QutipOptions
28
+ from .operator import CuOperator
29
+ from .state import CuState
30
+
31
+
32
+ # TODO: The split per density is not great
33
+ # Add an operator / state split in qutip?
34
+ qutip.core.data.to.register_group(
35
+ ['cuDensity'],
36
+ dense=qutip.core.data.Dense,
37
+ sparse=CuOperator,
38
+ diagonal=CuOperator
39
+ )
40
+
41
+ try:
42
+ from qutip_cupy import CuPyDense
43
+
44
+ def CuOperator_from_CuDense(mat):
45
+ return CuOperator(mat)
46
+
47
+ def CuPyDense_from_CuState(mat):
48
+ return CuPyDense(mat.to_cupy())
49
+
50
+ def CuState_from_CuPyDense(mat):
51
+ return CuState(mat)
52
+
53
+ qutip.core.data.to.add_conversions([
54
+ (CuState, CuPyDense, CuState_from_CuPyDense),
55
+ (CuPyDense, CuState, CuPyDense_from_CuState),
56
+ (CuOperator, CuPyDense, CuOperator_from_CuDense),
57
+ ])
58
+
59
+ except ImportError:
60
+ pass
61
+
62
+
63
+ from .qobjevo import CuQobjEvo
64
+ from .ode import Result, CuMCIntegrator
65
+
66
+
67
+ class cuDensityOption(QutipOptions):
68
+ _options = {"ctx": None}
69
+ _settings_name = "cuDensity"
70
+ _properties = {}
71
+
72
+
73
+ cuDensityOption_instance = cuDensityOption()
74
+ cuDensityOption_instance._set_as_global_default()
75
+
76
+
77
+ def set_as_default(ctx: cuquantum.densitymat.WorkStream):
78
+ """
79
+ Update qutip's default to use cuQuantum as a backend.
80
+
81
+ Parameters
82
+ ----------
83
+ ctx: WorkStream
84
+ A WorkStream instance from cuquantum.density.
85
+ It can be set with mpi support for multi-gpu simulations.
86
+ """
87
+ qutip.settings.cuDensity["ctx"] = ctx
88
+ qutip.settings.core["default_dtype"] = "cuDensity"
89
+ qutip.settings.core['numpy_backend'] = cupy
90
+
91
+ if True: # if mpi, how to check from ctx?
92
+ qutip.settings.core["auto_real_casting"] = False
93
+
94
+ qutip.SESolver.solver_options['method'] = "CuVern7"
95
+ qutip.MESolver.solver_options['method'] = "CuVern7"
96
+ qutip.MCSolver.solver_options['method'] = "CuVern7"
97
+
98
+ qutip.SESolver._resultclass = Result
99
+ qutip.MESolver._resultclass = Result
100
+ qutip.MCSolver._trajectory_resultclass = Result
101
+ qutip.MCSolver._mc_integrator_class = CuMCIntegrator
102
+
103
+
104
+
105
+ # Cleaning the namespace
106
+ # del Result
107
+ # del QutipOptions
108
+ # del qutip
@@ -0,0 +1,118 @@
1
+ from functools import partial
2
+ from cuquantum.densitymat import CPUCallback, DenseOperator
3
+
4
+ from qutip.core.tensor import _reverse_partial_tensor, tensor
5
+ from qutip.core.superoperator import spre, spost
6
+ from qutip.core.cy._element import _BaseElement, _FuncElement, _MapElement, _ProdElement, _EvoElement, _ConstantElement
7
+ from qutip.core.data import Dia
8
+ from qutip.core import coefficient, Qobj
9
+
10
+ from . import CuOperator
11
+
12
+
13
+ def _hilbert_from_dims(dims):
14
+ if isinstance(dims[0], list):
15
+ return dims[0]
16
+ return dims
17
+
18
+
19
+ def wrap_coeff(coeff):
20
+ return CPUCallback(lambda t, _: coeff(t))
21
+
22
+
23
+ def _wrap_callable(func):
24
+ sample = func(0)
25
+ shape = sample._dims._get_tensor_shape()
26
+ perm = sample._dims._get_tensor_perm()
27
+ num_mode = len(shape) // 2
28
+
29
+ if sample.dtype is Dia and num_mode == 1:
30
+ dia_matrix = sample.as_scipy()
31
+ offsets = list(dia_matrix.offsets)
32
+
33
+ def wrapped(t, _=None):
34
+ # TODO: Should we make this a class for pickling?
35
+ dia_matrix = func(t).as_scipy()
36
+ arr_shape = (dia_matrix.shape[0], len(offsets))
37
+ data = np.zeros(arr_shape, dtype=complex)
38
+
39
+ for i, offset in enumerate(offsets):
40
+ end = None if offset == 0 else -abs(offset)
41
+ data[:end, i] = dia_matrix.diagonal(offset)
42
+
43
+ return data
44
+
45
+ out = MultidiagonalOperator(wrapped(0), offsets, callback=CPUCallback(wrapped))
46
+
47
+ else:
48
+ if sample.dtype is Dia:
49
+ print("Callable QobjEvo converted to dense!")
50
+
51
+ def wrapped(t, _=None):
52
+ # TODO: Should we make this a class for pickling?
53
+ arr = func(t).full()
54
+ arr = arr.reshape(*shape)
55
+ return arr.transpose(*perm)
56
+
57
+ out = DenseOperator(wrapped(0), CPUCallback(wrapped))
58
+
59
+ return out, num_mode
60
+
61
+
62
+ def wrap_funcelement(element, args, dual, hilbert_dims, anti=False):
63
+ if not isinstance(element, _BaseElement):
64
+ element = _FuncElement(element, args)
65
+
66
+ if isinstance(element, _FuncElement):
67
+ oper, num_mode = _wrap_callable(element.qobj)
68
+ out = tensor_product((oper, tuple(range(num_mode)) ), dtype="complex128")
69
+
70
+ elif isinstance(element, _MapElement):
71
+ oper, num_mode = _wrap_callable(element._base.qobj)
72
+ as_qobj = Qobj( CuOperator(oper), dims=element._base.qobj(0)._dims )
73
+ for transform in element._transform:
74
+ as_qobj = transform(as_qobj)
75
+ if as_qobj.dtype is not CuOperator:
76
+ oper, num_mode = _wrap_callable(element.qobj)
77
+ out = tensor_product((oper, tuple(range(num_mode)) ), dtype="complex128")
78
+ else:
79
+ coeff = conj(element._coeff) if anti else element._coeff
80
+ out = as_qobj.data.to_OperatorTerm(dual, hilbert_dims=hilbert_dims) * coeff
81
+
82
+ elif isinstance(element, _ProdElement):
83
+ dims_left = element._left.qobj(0).dims
84
+ hilbert_left = _hilbert_from_dims(dims_left)
85
+ left = CuOperator(
86
+ wrap_funcelement(element._left, None, dual, hilbert_left, element._conj != anti),
87
+ hilbert_dims=hilbert_left,
88
+ )
89
+ dims_right = element._right.qobj(0).dims
90
+ hilbert_right = _hilbert_from_dims(dims_right)
91
+ right = CuOperator(
92
+ wrap_funcelement(element._right, None, dual, hilbert_right, element._conj != anti),
93
+ hilbert_dims=hilbert_right,
94
+ )
95
+ as_qobj = Qobj(left @ right, [dims_left[0], dims_right[1]])
96
+ for transform in element._transform:
97
+ as_qobj = transform(as_qobj)
98
+
99
+ if as_qobj.dtype is not CuOperator:
100
+ oper, num_mode = _wrap_callable(element.qobj)
101
+ coeff = make_CPUcall( coefficient(element.coeff).conj() ) if anti else make_CPUcall(element.coeff)
102
+ out = tensor_product((oper, tuple(range(num_mode)) ), dtype="complex128") * coeff
103
+ else:
104
+ out = as_qobj.data.to_OperatorTerm(dual, hilbert_dims=hilbert_dims)
105
+
106
+ elif isinstance(element, _EvoElement):
107
+ qobj = element._qobj
108
+ coeff = make_CPUcall(element._coefficient.conj()) if anti else make_CPUcall(element._coefficient)
109
+ out = qobj.data.to_OperatorTerm(dual, hilbert_dims=hilbert_dims) * coeff
110
+
111
+ elif isinstance(element, _ConstantElement):
112
+ qobj = element._qobj
113
+ out = qobj.data.to_OperatorTerm(dual, hilbert_dims=hilbert_dims)
114
+
115
+ else:
116
+ raise NotImplementedError(type(element))
117
+
118
+ return out
@@ -0,0 +1,8 @@
1
+ """QuTiP family package entry point."""
2
+
3
+ from .version import version as full_version
4
+
5
+
6
+ def version():
7
+ """Return information to include in qutip.about()."""
8
+ return "qutip-cuquantum", full_version