diff --git a/docs/tutorials/Lindblad_dynamics_simulation.rst b/docs/tutorials/Lindblad_dynamics_simulation.rst index 34bcd4925..1d17caf88 100644 --- a/docs/tutorials/Lindblad_dynamics_simulation.rst +++ b/docs/tutorials/Lindblad_dynamics_simulation.rst @@ -14,7 +14,7 @@ In the sections below we define a model, solve the dynamics and plot some observables using the following steps: 1. Define the number of qubits and precompute some matrix operators. -2. Define all relevant parameters and setup a ``Solver`` instance with the model of the system, +2. Define all relevant parameters and setup a :class:`Solver` instance with the model of the system, consisting of the Hamiltonian and the jump operators of the Lindblad dissipator. 3. Define the initial state and other parameters for the initial value problem, and evolve the system state. @@ -110,7 +110,7 @@ used in the rest of this tutorial. 2. Setup the solver ------------------- -In this section we setup a ``Solver`` class that stores and manipulates +In this section we setup a :class:`Solver` class that stores and manipulates the model to be solved. In the following, we will set :math:`\hbar=1` and set the driving amplitude to be :math:`\nu_x \equiv 1`. This sets the time units, with the other frequency @@ -119,7 +119,7 @@ these free parameters, and then create the Hamiltonian matrix and the list of dissipator operators. We build the full Hamiltonian matrix by summing all single-qubit and two-qubit terms. Since there are no time-dependent terms, and we do not plan to take partial derivatives of -parameters, we do not use the ``Signal`` class in this tutorial. See the other tutorials for various +parameters, we do not use the :class:`Signal` class in this tutorial. See the other tutorials for various generalizations of this approach supported with ``qiskit-dynamics``. .. jupyter-execute:: diff --git a/docs/tutorials/Rabi_oscillations.rst b/docs/tutorials/Rabi_oscillations.rst index 7c38b956d..6346b444e 100644 --- a/docs/tutorials/Rabi_oscillations.rst +++ b/docs/tutorials/Rabi_oscillations.rst @@ -10,8 +10,7 @@ decoherence terms modeled by using a Lindblad master equation. In the sections below we define a model, solve the dynamics and plot the qubit oscillations using the following steps: -1. Define all relevant parameters and setup a ``Solver`` instance with the Hamiltonian model of - the system. +1. Setup a :class:`.Solver` with the Hamiltonian model 2. Define the initial state and simulation times, and evolve the system state. 3. Plot the qubit state as a function of time and discuss the results. 4. Solve again the the model with jump operators for the Lindblad dissipator, and plot the results. @@ -20,7 +19,9 @@ In the first step below, we model the time evolution of a qubit’s state taken as a two-level system, using the Schrödinger equation with a Hamiltonian containing a diagonal term of frequency :math:`\nu_z` and a transverse term of amplitude :math:`\nu_x` and harmonic driving -frequency :math:`\nu_d`, +frequency :math:`\nu_d` (see how the Hamiltonians are derived on +`Qiskit Textbook page on Introduction to Transmon Physics +`_), .. math:: H = \frac{1}{2} \times 2 \pi \nu_z {Z} + 2 \pi \nu_x \cos(2 \pi \nu_d t){X}, @@ -33,8 +34,8 @@ where :math:`\{X,Y,Z\}` are the Pauli matrices (also written as In the following, we will set :math:`\hbar=1` and fix some arbitrary time units, with all frequency parameters scaled accordingly. Below, we first set a few values for these frequency parameters, and then setup the -``Solver`` class instance that stores and manipulates the model to be -solved, using matrices and ``Signal`` instances. For the +:class:`.Solver` class instance that stores and manipulates the model to be +solved, using matrices and :class:`.Signal` instances. For the time-independent :math:`z` term we set the signal to a constant, while for the trasverse driving term we setup a harmonic signal. @@ -144,8 +145,8 @@ particular this is a realization of the :math:`X` gate. plot_qubit_dynamics(sol, t_eval, X, Y, Z) -4. Redefine the model with damping and decoherence. ---------------------------------------------------- +4. Redefine the model with damping and decoherence +-------------------------------------------------- Now we add to our simulation an environment modeled as a memory-less (Markovian) bath, solving the Lindblad master equation with the same diff --git a/docs/tutorials/qiskit_pulse.rst b/docs/tutorials/qiskit_pulse.rst index 07f009937..77b214327 100644 --- a/docs/tutorials/qiskit_pulse.rst +++ b/docs/tutorials/qiskit_pulse.rst @@ -25,7 +25,7 @@ ground state we expect that this second pulse will not have any effect on the qubit. This situation is simulated with the following steps: 1. Create the pulse schedule -2. Converting pulse schedules to Signals +2. Converting pulse schedules to a :class:`.Signal` 3. Create the system model, configured to simulate pulse schedules 4. Simulate the pulse schedule using the model @@ -66,12 +66,12 @@ First, we use the pulse module in Qiskit to create a pulse schedule. xp.draw() -2. Convert the pulse schedule to a ``Signal`` ---------------------------------------------- +2. Convert the pulse schedule to a :class:`.Signal` +--------------------------------------------------- Qiskit Dynamics has functionality for converting pulse schedule to instances -of ``Signal``. This is done using the pulse instruction to signal -converter ``InstructionToSignals``. This converter needs to know the +of :class:`.Signal`. This is done using the pulse instruction to signal +converter :class:`.InstructionToSignals`. This converter needs to know the sample rate of the arbitrary waveform generators creating the signals, i.e. ``dt``, as well as the carrier frequency of the signals, i.e. ``w``. The plot below shows the envelopes and the signals resulting @@ -101,7 +101,7 @@ virtual ``Z`` gate is applied. 3. Create the system model -------------------------- -We now setup a ``Solver`` instance with the desired Hamiltonian information, +We now setup a :class:`.Solver` instance with the desired Hamiltonian information, and configure it to simulate pulse schedules. This requires specifying which channels act on which operators, channel carrier frequencies, and sample width ``dt``. Additionally, we setup this solver in the rotating frame and perform the diff --git a/docs/userguide/how_to_configure_simulations.rst b/docs/userguide/how_to_configure_simulations.rst index d1c072c5f..64b0babb6 100644 --- a/docs/userguide/how_to_configure_simulations.rst +++ b/docs/userguide/how_to_configure_simulations.rst @@ -20,7 +20,7 @@ Here we walk through some of these options, covering: rotating frame to preserve sparsity -Throughout this guide we work at the level of the ``Solver`` interface, +Throughout this guide we work at the level of the :class:`.Solver` interface, and consider Hamiltonian dynamics for simplicity, however all of the considerations have their analogs for Lindblad dynamics. @@ -28,7 +28,7 @@ considerations have their analogs for Lindblad dynamics. ----------------------------------------------------------------------------- Here we show how to perform a simulation in a rotating frame by setting the -optional ``rotating_frame`` argument when instantiating a ``Solver``, and demonstrate how a +optional ``rotating_frame`` argument when instantiating a :class:`.Solver`, and demonstrate how a well-chosen frame operator :math:`F = -iH_0` can reduce solving time. See the :ref:`Rotating frames section of the Models API documentation ` for details on rotating frames. @@ -74,7 +74,7 @@ First, construct the components of the model: # total simulation time T = 1. / r -Construct a ``Solver`` for the model as stated, without entering a rotating frame, and solve, +Construct a :class:`.Solver` for the model as stated, without entering a rotating frame, and solve, timing the solver. .. jupyter-execute:: @@ -87,7 +87,7 @@ timing the solver. y0 = np.eye(dim, dtype=complex) %time results = solver.solve(t_span=[0., T], y0=y0, signals=[drive_signal], atol=1e-10, rtol=1e-10) -Next, define a ``Solver`` in the rotating frame of the static +Next, define a :class:`.Solver` in the rotating frame of the static Hamiltonian by setting the ``rotating_frame`` kwarg, and solve, again timing the solver. .. jupyter-execute:: @@ -151,7 +151,7 @@ reducing the number of RHS calls required to solve with a given accuracy. --------------------------------------------------------------------------- Next we show how to perform a simulation with the rotating wave approximation (RWA) -by setting the ``rwa_cutoff_freq`` argument at ``Solver`` instantiation, and show +by setting the ``rwa_cutoff_freq`` argument at :class:`.Solver` instantiation, and show how it results in further speed ups at the expense of solution accuracy. See the API documentation for the :meth:`~qiskit_dynamics.models.rotating_wave_approximation` function for specific details about the RWA. @@ -201,7 +201,7 @@ with extra emphasis on the following: :ref:`evaluation modes 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 ``Solver`` instantiation. + ``rotating_frame`` kwarg of :class:`.Solver` instantiation. For this section we use JAX as it is more performant. See the :ref:`userguide on using JAX ` for a more detailed diff --git a/docs/userguide/how_to_use_jax.rst b/docs/userguide/how_to_use_jax.rst index 5aadb7205..905013e0a 100644 --- a/docs/userguide/how_to_use_jax.rst +++ b/docs/userguide/how_to_use_jax.rst @@ -5,7 +5,7 @@ How-to use JAX with ``qiskit-dynamics`` JAX enables just-in-time compilation, automatic differentation, and GPU execution. JAX is integrated into ``qiskit-dynamics`` via the -``Array`` class, which allows most parts of the package to be +:class:`.Array` class, which allows most parts of the package to be executed with either ``numpy`` or ``jax.numpy``. This guide addresses the following topics: @@ -20,7 +20,7 @@ This guide addresses the following topics: 1. How do I configure dynamics to run with JAX? ----------------------------------------------- -The ``Array`` class provides a means of controlling whether array +The :class:`.Array` class provides a means of controlling whether array operations are performed using ``numpy`` or ``jax.numpy``. In many cases, the “default backend” is used to determine which of the two options is used. @@ -50,8 +50,8 @@ The default backend can be observed via: The ``Array`` class wraps both ``numpy`` and ``jax.numpy`` arrays. The particular type is indicated by the ``backend`` property, -and ``numpy`` functions called on an ``Array`` will automatically be -dispatched to ``numpy`` or ``jax.numpy`` based on the ``Array``\ ’s +and ``numpy`` functions called on an :class:`.Array` will automatically be +dispatched to ``numpy`` or ``jax.numpy`` based on the :class:`.Array`\ ’s backend. See the API documentation for ``qiskit_dynamics.array`` for details. @@ -67,7 +67,7 @@ JAX-transformable functions must be: - Pure, in the sense that they have no side-effects. The previous section shows how to handle the first two points using -``Array``. The last point further restricts the type of +:class:`.Array`. The last point further restricts the type of code that can be safely transformed. Qiskit Dynamics uses various objects which can be updated by setting properties (models, solvers). If a function to be transformed requires updating an already-constructed object of this @@ -90,7 +90,7 @@ functions built using Qiskit Dynamics can be just-in-time compiled, resulting in faster simulation times. For convenience, the ``wrap`` function can be used to transform -``jax.jit`` to also work on functions that have ``Array`` objects as +``jax.jit`` to also work on functions that have :class:`.Array` objects as inputs and outputs. .. jupyter-execute:: @@ -99,7 +99,7 @@ inputs and outputs. jit = wrap(jax.jit, decorator=True) -Construct a ``Solver`` instance with a model that will be used to solve. +Construct a :class:`.Solver` instance with a model that will be used to solve. .. jupyter-execute:: @@ -234,8 +234,8 @@ To get dynamics to run with JAX, it is necessary to configure dynamics to run with JAX *before* building any objects or running any functions. The internal behaviour of some objects is modified by what the default backend is *at the time of instantiation*. For example, at instantiation -the operators in a model or ``Solver`` instance will be wrapped in an -``Array`` whose backend is the current default backend, and changing the +the operators in a model or :class:`.Solver` instance will be wrapped in an +:class:`.Array` whose backend is the current default backend, and changing the default backend after building the object won’t change this. 4.2 Running Dynamics with JAX on CPU vs GPU diff --git a/docs/userguide/perturbative_solvers.rst b/docs/userguide/perturbative_solvers.rst index f8d082e29..df9c15417 100644 --- a/docs/userguide/perturbative_solvers.rst +++ b/docs/userguide/perturbative_solvers.rst @@ -126,7 +126,7 @@ along with the structure of the differential equation: - To compute the truncated perturbative expansion, the signal envelopes are approximated as a linear combination of Chebyshev polynomials. - The order of the Chebyshev approximations, along with central carrier frequencies - for defining the “envelope” of each ``Signal``, must be provided at instantiation. + for defining the “envelope” of each :class:`.Signal`, must be provided at instantiation. See the :class:`.DysonSolver` API docs for more details.