From cf16ef7418937b4c247de94524576ba708fe7d63 Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 08:07:27 -0800 Subject: [PATCH 1/7] initial passover/cleanup of code docs --- qiskit_dynamics/models/generator_model.py | 4 ++-- qiskit_dynamics/models/lindblad_model.py | 10 +++++----- qiskit_dynamics/models/model_utils.py | 2 +- qiskit_dynamics/models/operator_collections.py | 13 +------------ qiskit_dynamics/models/rotating_frame.py | 4 ++-- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/qiskit_dynamics/models/generator_model.py b/qiskit_dynamics/models/generator_model.py index 891159e6d..3f65a8a5e 100644 --- a/qiskit_dynamics/models/generator_model.py +++ b/qiskit_dynamics/models/generator_model.py @@ -91,7 +91,7 @@ def __call__(self, time: float, y: Optional[ArrayLike] = None) -> ArrayLike: y: Optional state. Returns: - Array: Either the evaluated model, or the RHS for the given y. + ArrayLike: Either the evaluated model, or the RHS for the given y. """ return self.evaluate(time) if y is None else self.evaluate_rhs(time, y) @@ -254,7 +254,7 @@ def evaluate(self, time: float) -> ArrayLike: time: The time to evaluate the model at. Returns: - Array: The evaluated model as a matrix. + ArrayLike: The evaluated model as a matrix. Raises: QiskitError: If model cannot be evaluated. diff --git a/qiskit_dynamics/models/lindblad_model.py b/qiskit_dynamics/models/lindblad_model.py index c76a71a66..672a485fa 100644 --- a/qiskit_dynamics/models/lindblad_model.py +++ b/qiskit_dynamics/models/lindblad_model.py @@ -417,7 +417,7 @@ def evaluate_hamiltonian(self, time: float) -> ArrayLike: time: The time at which to evaluate the Hamiltonian. Returns: - Array: Hamiltonian matrix. + ArrayLike: Hamiltonian matrix. """ hamiltonian_sig_vals = None @@ -443,7 +443,7 @@ def evaluate(self, time: float) -> ArrayLike: time: The time to evaluate the model at. Returns: - Array: The evaluated model as an anti-Hermitian matrix. + ArrayLike: The evaluated model as an anti-Hermitian matrix. Raises: QiskitError: If model cannot be evaluated. @@ -482,11 +482,11 @@ def evaluate_rhs(self, time: float, y: ArrayLike) -> ArrayLike: Args: time: The time at which the model should be evaluated. - y: Density matrix as an (n,n) Array if not using a vectorized evaluation_mode, or an - (n^2) Array if using vectorized evaluation. + y: Density matrix as an (n,n) Array if not vectorized, or an (n^2) Array if using + vectorized evaluation. Returns: - Array: Either the evaluated generator or the state. + ArrayLike: Either the evaluated generator or the state. Raises: QiskitError: If signals not sufficiently specified. diff --git a/qiskit_dynamics/models/model_utils.py b/qiskit_dynamics/models/model_utils.py index 14bfec411..1f6924553 100644 --- a/qiskit_dynamics/models/model_utils.py +++ b/qiskit_dynamics/models/model_utils.py @@ -50,7 +50,7 @@ def vec_commutator( list of sparse matrices. Returns: - Array: vectorized version of the map. + ArrayLike: Vectorized version of the map. """ if issparse(A): diff --git a/qiskit_dynamics/models/operator_collections.py b/qiskit_dynamics/models/operator_collections.py index b847211ad..3a30f608f 100644 --- a/qiskit_dynamics/models/operator_collections.py +++ b/qiskit_dynamics/models/operator_collections.py @@ -852,18 +852,7 @@ class VectorizedLindbladCollection: """Vectorized Lindblad collection class. The vectorized Lindblad equation represents the Lindblad master equation in the structure - of a linear matrix differential equation in standard form. Hence, this class inherits - from both ``BaseLindbladOperatorCollection`` and ``BaseOperatorCollection``. - - This class manages the general property handling of converting operators in a Lindblad - collection to the correct type, constructing vectorized versions, and combining for use in a - BaseOperatorCollection. Requires implementation of: - - - ``convert_to_internal_type``: Convert operators to the required internal type, - e.g. csr or Array. - - ``evaluation_class``: Class property that returns the subclass of BaseOperatorCollection - to be used when evaluating the model, e.g. DenseOperatorCollection or - SparseOperatorCollection. + of a linear matrix differential equation in standard form. This class works for ``array_library in ["numpy", "jax", "jax_sparse"]``. """ diff --git a/qiskit_dynamics/models/rotating_frame.py b/qiskit_dynamics/models/rotating_frame.py index b70f087f2..070056777 100644 --- a/qiskit_dynamics/models/rotating_frame.py +++ b/qiskit_dynamics/models/rotating_frame.py @@ -158,7 +158,7 @@ def state_out_of_frame_basis(self, y: ArrayLike) -> ArrayLike: y: The state. Returns: - Array: The state in the frame basis. + ArrayLike: The state in the frame basis. """ y = unp.asarray(y) if self.frame_basis is None: @@ -181,7 +181,7 @@ def operator_into_frame_basis( ``op`` is a handled input type. Returns: - Array: The operator in the frame basis. + ArrayLike: The operator in the frame basis. """ if convert_type: op = unp.asarray(op) From 01b8a63f36515d73c1eb144978c2a36267e63304 Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 08:17:00 -0800 Subject: [PATCH 2/7] refactoring handling of array_library property in models --- qiskit_dynamics/models/generator_model.py | 14 +++++++------- qiskit_dynamics/models/lindblad_model.py | 8 ++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/qiskit_dynamics/models/generator_model.py b/qiskit_dynamics/models/generator_model.py index 3f65a8a5e..c19a1493a 100644 --- a/qiskit_dynamics/models/generator_model.py +++ b/qiskit_dynamics/models/generator_model.py @@ -45,6 +45,10 @@ class BaseGeneratorModel(ABC): map :math:`\Lambda(t, \cdot)`. """ + def __init__(self, array_library: Optional[str] = None): + """Set up general information used by all subclasses.""" + self._array_library = array_library + @property @abstractmethod def dim(self) -> int: @@ -61,9 +65,9 @@ def in_frame_basis(self) -> bool: """Whether or not the model is evaluated in the basis in which the frame is diagonalized.""" @property - @abstractmethod def array_library(self) -> Union[None, str]: """Array library used to store the operators in the model.""" + return self._array_library @abstractmethod def evaluate(self, time: float) -> ArrayLike: @@ -144,7 +148,6 @@ def __init__( "be specified at construction." ) - self._array_library = array_library self._rotating_frame = RotatingFrame(rotating_frame) self._in_frame_basis = in_frame_basis @@ -166,6 +169,8 @@ def __init__( self._signals = None self.signals = signals + super().__init__(array_library=array_library) + @property def dim(self) -> int: """The matrix dimension.""" @@ -185,11 +190,6 @@ def in_frame_basis(self) -> bool: def in_frame_basis(self, in_frame_basis: bool): self._in_frame_basis = in_frame_basis - @property - def array_library(self) -> Union[None, str]: - """Array library used to store the operators in the model.""" - return self._array_library - @property def static_operator(self) -> Union[ArrayLike, None]: """The static operator.""" diff --git a/qiskit_dynamics/models/lindblad_model.py b/qiskit_dynamics/models/lindblad_model.py index 672a485fa..2327ff1a7 100644 --- a/qiskit_dynamics/models/lindblad_model.py +++ b/qiskit_dynamics/models/lindblad_model.py @@ -159,7 +159,6 @@ def __init__( ): raise QiskitError("""LindbladModel hamiltonian_operators must be Hermitian.""") - self._array_library = array_library self._vectorized = vectorized self._rotating_frame = RotatingFrame(rotating_frame) self._in_frame_basis = in_frame_basis @@ -209,6 +208,8 @@ def __init__( self.signals = (hamiltonian_signals, dissipator_signals) + super().__init__(array_library=array_library) + @classmethod def from_hamiltonian( cls, @@ -395,11 +396,6 @@ def dissipator_operators(self) -> ArrayLike: self._operator_collection.dissipator_operators ) - @property - def array_library(self) -> Union[None, str]: - """Array library used to store the operators in the model.""" - return self._array_library - @property def vectorized(self) -> bool: """Whether or not the Lindblad equation is vectorized.""" From d516c98c5c656db4bade9ff31afd19320c4d0bde Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 08:49:04 -0800 Subject: [PATCH 3/7] editting model API docs --- qiskit_dynamics/models/__init__.py | 25 ++++++++++----------- qiskit_dynamics/models/generator_model.py | 14 ++++++++---- qiskit_dynamics/models/hamiltonian_model.py | 8 +++---- qiskit_dynamics/models/lindblad_model.py | 7 +++--- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/qiskit_dynamics/models/__init__.py b/qiskit_dynamics/models/__init__.py index 7f18e3ba3..4163c3ff8 100644 --- a/qiskit_dynamics/models/__init__.py +++ b/qiskit_dynamics/models/__init__.py @@ -92,19 +92,18 @@ .. _evaluation modes: -Numerical methods and evaluation modes -====================================== - -All model classes offer different underlying numerical implementations that a user can choose using -the ``evaluation_mode`` property. For example, :class:`~qiskit_dynamics.models.HamiltonianModel` can -internally use either sparse or dense arrays to compute :math:`H(t)` or a product :math:`-iH(t)y`. -The default is dense arrays, and a model can be set to use sparse arrays via: - -.. code-block:: python - - model.evaluation_mode = "sparse" - -See the ``evaluation_mode`` property for each model class for available modes. +Controlling model evaluation: array libraries and vectorization +=============================================================== + +The underlying array library used by any model class can be controlled via the ``array_library`` +instantiation argument. The model will store the underlying arrays using the specified library, and +use this library to evaluate the model. See the :mod:`.arraylias` submodule API documentation for a +list of ``array_library`` options. If unspecified, the model will use the general dispatching rules +of the configured aliases in :mod:`.arraylias` to determine which library to use based on how the +operators are specified. + +Additionally, the :class:`.LindbladModel` class can be set to store and evaluate the Lindblad +equation in a matrix-vector vectorized format using the ``vectorized`` instatiation argument. .. note:: diff --git a/qiskit_dynamics/models/generator_model.py b/qiskit_dynamics/models/generator_model.py index c19a1493a..46cbc2458 100644 --- a/qiskit_dynamics/models/generator_model.py +++ b/qiskit_dynamics/models/generator_model.py @@ -66,7 +66,12 @@ def in_frame_basis(self) -> bool: @property def array_library(self) -> Union[None, str]: - """Array library used to store the operators in the model.""" + """Array library with which to represent the operators in the model, and to evaluate the + model. + + See the list of supported array libraries in the :mod:`.arraylias` submodule API + documentation. + """ return self._array_library @abstractmethod @@ -136,9 +141,10 @@ def __init__( rotating_frame: Rotating frame operator. in_frame_basis: Whether to represent the model in the basis in which the rotating frame operator is diagonalized. - array_library: Array library for storing the operators in the model. Supported options - are ``'numpy'``, ``'jax'``, ``'jax_sparse'``, and ``'scipy_sparse'``. If ``None``, - the arrays will be handled by general dispatching rules. + array_library: Array library with which to represent the operators in the model, and to + evaluate the model. See the list of supported array libraries in the + :mod:`.arraylias` submodule API documentation. If ``None``, the arrays will be + handled by general dispatching rules. Raises: QiskitError: If model not sufficiently specified. """ diff --git a/qiskit_dynamics/models/hamiltonian_model.py b/qiskit_dynamics/models/hamiltonian_model.py index 8eb0495bb..3300b7850 100644 --- a/qiskit_dynamics/models/hamiltonian_model.py +++ b/qiskit_dynamics/models/hamiltonian_model.py @@ -82,10 +82,10 @@ def __init__( F = -iH. in_frame_basis: Whether to represent the model in the basis in which the rotating frame operator is diagonalized. - array_library: Array library for storing the operators in the model. Supported options - are ``'numpy'``, ``'jax'``, ``'jax_sparse'``, and ``'scipy_sparse'``. If ``None``, - the arrays will be handled by general dispatching rules. Call - ``help(GeneratorModel.array_library)`` for more details. + array_library: Array library with which to represent the operators in the model, and to + evaluate the model. See the list of supported array libraries in the + :mod:`.arraylias` submodule API documentation. If ``None``, the arrays will be + handled by general dispatching rules. validate: If ``True`` check input operators are Hermitian. Note that this is incompatible with JAX transformations. diff --git a/qiskit_dynamics/models/lindblad_model.py b/qiskit_dynamics/models/lindblad_model.py index 2327ff1a7..c5020fdb8 100644 --- a/qiskit_dynamics/models/lindblad_model.py +++ b/qiskit_dynamics/models/lindblad_model.py @@ -125,9 +125,10 @@ def __init__( assumed that all operators were already in the frame basis. in_frame_basis: Whether to represent the model in the basis in which the rotating frame operator is diagonalized. - array_library: Array library for storing the operators in the model. Supported options - are ``'numpy'``, ``'jax'``, ``'jax_sparse'``, and ``'scipy_sparse'``. If ``None``, - the arrays will be handled by general dispatching rules. + array_library: Array library with which to represent the operators in the model, and to + evaluate the model. See the list of supported array libraries in the + :mod:`.arraylias` submodule API documentation. If ``None``, the arrays will be + handled by general dispatching rules. vectorized: Whether or not to setup the Lindblad equation in vectorized mode. If ``True``, the operators in the model are stored as :math:`(dim^2,dim^2)` matrices that act on vectorized density matrices by left-multiplication. Setting this to From 8f82c6ebb240f584d6c7e10f60ce139d7e97573e Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 08:56:44 -0800 Subject: [PATCH 4/7] linting --- qiskit_dynamics/models/generator_model.py | 6 +++--- qiskit_dynamics/models/hamiltonian_model.py | 4 ++-- qiskit_dynamics/models/lindblad_model.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/qiskit_dynamics/models/generator_model.py b/qiskit_dynamics/models/generator_model.py index 46cbc2458..a9e1ff44b 100644 --- a/qiskit_dynamics/models/generator_model.py +++ b/qiskit_dynamics/models/generator_model.py @@ -68,7 +68,7 @@ def in_frame_basis(self) -> bool: def array_library(self) -> Union[None, str]: """Array library with which to represent the operators in the model, and to evaluate the model. - + See the list of supported array libraries in the :mod:`.arraylias` submodule API documentation. """ @@ -141,8 +141,8 @@ def __init__( rotating_frame: Rotating frame operator. in_frame_basis: Whether to represent the model in the basis in which the rotating frame operator is diagonalized. - array_library: Array library with which to represent the operators in the model, and to - evaluate the model. See the list of supported array libraries in the + array_library: Array library with which to represent the operators in the model, and to + evaluate the model. See the list of supported array libraries in the :mod:`.arraylias` submodule API documentation. If ``None``, the arrays will be handled by general dispatching rules. Raises: diff --git a/qiskit_dynamics/models/hamiltonian_model.py b/qiskit_dynamics/models/hamiltonian_model.py index 3300b7850..cbc56fbeb 100644 --- a/qiskit_dynamics/models/hamiltonian_model.py +++ b/qiskit_dynamics/models/hamiltonian_model.py @@ -82,8 +82,8 @@ def __init__( F = -iH. in_frame_basis: Whether to represent the model in the basis in which the rotating frame operator is diagonalized. - array_library: Array library with which to represent the operators in the model, and to - evaluate the model. See the list of supported array libraries in the + array_library: Array library with which to represent the operators in the model, and to + evaluate the model. See the list of supported array libraries in the :mod:`.arraylias` submodule API documentation. If ``None``, the arrays will be handled by general dispatching rules. validate: If ``True`` check input operators are Hermitian. Note that this is diff --git a/qiskit_dynamics/models/lindblad_model.py b/qiskit_dynamics/models/lindblad_model.py index c5020fdb8..9008bac4c 100644 --- a/qiskit_dynamics/models/lindblad_model.py +++ b/qiskit_dynamics/models/lindblad_model.py @@ -125,8 +125,8 @@ def __init__( assumed that all operators were already in the frame basis. in_frame_basis: Whether to represent the model in the basis in which the rotating frame operator is diagonalized. - array_library: Array library with which to represent the operators in the model, and to - evaluate the model. See the list of supported array libraries in the + array_library: Array library with which to represent the operators in the model, and to + evaluate the model. See the list of supported array libraries in the :mod:`.arraylias` submodule API documentation. If ``None``, the arrays will be handled by general dispatching rules. vectorized: Whether or not to setup the Lindblad equation in vectorized mode. From bb6da9a26c3da21c79145ffd603ea7123a6b9d04 Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 09:28:28 -0800 Subject: [PATCH 5/7] removing old use of copy --- .../models/rotating_wave_approximation.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/qiskit_dynamics/models/rotating_wave_approximation.py b/qiskit_dynamics/models/rotating_wave_approximation.py index 02e1549fd..eeabc8b60 100644 --- a/qiskit_dynamics/models/rotating_wave_approximation.py +++ b/qiskit_dynamics/models/rotating_wave_approximation.py @@ -75,18 +75,19 @@ def function_with_rwa(t): .. code-block:: python - rwa_model, signal_map = rotating_wave_approximation(model, - cutoff_freq, - return_signal_map=True) + rwa_model, signal_map = rotating_wave_approximation( + model, + cutoff_freq, + return_signal_map=True + ) The following function **is** JAX-transformable: .. code-block:: python def jax_transformable_func(t): - rwa_model_copy = rwa_model.copy() - rwa_model_copy.signals = signal_map(new_signals) - return rwa_model_copy(t) + rwa_model.signals = signal_map(new_signals) + return rwa_model(t) In this way, the outputs of ``rotating_wave_approximation`` can be used in JAX-transformable functions, however ``rotating_wave_approximation`` itself cannot. From dc96faf11a994a7e6c3b277973f177989f2a26a0 Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 10:58:12 -0800 Subject: [PATCH 6/7] updating link name --- docs/userguide/how_to_configure_simulations.rst | 2 +- qiskit_dynamics/models/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/userguide/how_to_configure_simulations.rst b/docs/userguide/how_to_configure_simulations.rst index 69e953dcf..9f6537b3a 100644 --- a/docs/userguide/how_to_configure_simulations.rst +++ b/docs/userguide/how_to_configure_simulations.rst @@ -204,7 +204,7 @@ with extra emphasis on the following: .. note:: As stated in the - :ref:`evaluation modes section of the Models API documentation `, + :ref:`model evaluation section of the Models API documentation `, when using a sparse evaluation mode, to preserve sparsity, it is recommended to only use *diagonal* rotating frames, which can be specified as a 1d array to the ``rotating_frame`` kwarg of :class:`.Solver` instantiation. diff --git a/qiskit_dynamics/models/__init__.py b/qiskit_dynamics/models/__init__.py index 4163c3ff8..a943c43ad 100644 --- a/qiskit_dynamics/models/__init__.py +++ b/qiskit_dynamics/models/__init__.py @@ -90,7 +90,7 @@ transformation is implemented in :meth:`~qiskit_dynamics.models.rotating_wave_approximation`, see its documentation for details. -.. _evaluation modes: +.. _model evaluation: Controlling model evaluation: array libraries and vectorization =============================================================== From c56f60738aaad8dac50f07462aa91f655959854c Mon Sep 17 00:00:00 2001 From: DanPuzzuoli Date: Wed, 28 Feb 2024 12:20:50 -0800 Subject: [PATCH 7/7] adding link to model array_library description in DynamicsBackend.from_backend --- qiskit_dynamics/backend/dynamics_backend.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qiskit_dynamics/backend/dynamics_backend.py b/qiskit_dynamics/backend/dynamics_backend.py index d9021304b..04d1e6faf 100644 --- a/qiskit_dynamics/backend/dynamics_backend.py +++ b/qiskit_dynamics/backend/dynamics_backend.py @@ -673,6 +673,9 @@ def from_backend( rotating_frame: Rotating frame argument for the internal :class:`.Solver`. Defaults to ``"auto"``, allowing this method to pick a rotating frame. array_library: Array library with which to store the operators in the :class:`.Solver`. + See the + :ref:`model evaluation section of the Models API documentation ` + for a more detailed description of this argument. vectorized: If a Lindblad terms are present, whether or not to build the :class:`.Solver` in a vectorized mode. rwa_cutoff_freq: Rotating wave approximation argument for the internal :class:`.Solver`.