diff --git a/docs/source/acknowledgments.rst b/docs/source/acknowledgments.rst index e7607c3..95e5aad 100644 --- a/docs/source/acknowledgments.rst +++ b/docs/source/acknowledgments.rst @@ -8,9 +8,9 @@ Funding ******* We gratefully acknowledge financial support for the continued development of the scqubits library by the Air Force -Office for Scientific Research under grant no. FA9550-20-1-0271. The scqubits library was additionally supported +Office of Scientific Research under grant no. FA9550-20-1-0271. The scqubits library was additionally supported by the Army Research Office under grant nos. W911NF-1510421, W911NF-1910016, by the DOE under grant -nos. DE-SC0012704, DE-AC02-07CH113, and by the Northwestern-Fermilab Center for Applied Physics and Superconducting +nos. DE-SC0012704, DE-AC02-07CH11359, and by the Northwestern-Fermilab Center for Applied Physics and Superconducting Technologies (CAPST). .. table:: diff --git a/docs/source/api-doc/for_developer.rst b/docs/source/api-doc/for_developer.rst index 263e458..5b02efb 100644 --- a/docs/source/api-doc/for_developer.rst +++ b/docs/source/api-doc/for_developer.rst @@ -42,6 +42,8 @@ CentralDispatch and related classes CentralDispatch --------------- +.. toctree:: + _autosummary/scqubits.core.central_dispatch.CentralDispatch.rst .. _classes-dispatchclient: @@ -49,6 +51,8 @@ CentralDispatch DispatchClient --------------- +.. toctree:: + _autosummary/scqubits.core.central_dispatch.DispatchClient.rst @@ -61,6 +65,8 @@ Descriptor classes WatchedProperty --------------- +.. toctree:: + _autosummary/scqubits.core.descriptors.WatchedProperty.rst .. _classes-readonly: @@ -68,4 +74,6 @@ WatchedProperty ReadOnlyProperty ---------------- +.. toctree:: + _autosummary/scqubits.core.descriptors.ReadOnlyProperty.rst \ No newline at end of file diff --git a/docs/source/bibliography.rst b/docs/source/bibliography.rst index 053477b..9b5384d 100644 --- a/docs/source/bibliography.rst +++ b/docs/source/bibliography.rst @@ -8,15 +8,15 @@ Refs **** .. [Brooks2013] Brooks et al., Phys. Rev. A 87, 052306 (2013), https://link.aps.org/doi/10.1103/PhysRevA.87.052306 -.. [Catelani2011] Catelani et al., Phys. Rev. B, 84, 064517 (2011), https://journals.aps.org/prb/abstract/10.1103/PhysRevB.84.064517 +.. [Catelani2011] Catelani et al., Phys. Rev. B 84, 064517 (2011), https://journals.aps.org/prb/abstract/10.1103/PhysRevB.84.064517 .. [Dempster2014] Dempster et al., Phys. Rev. B 90, 094518 (2014), https://link.aps.org/doi/10.1103/PhysRevB.90.094518 .. [Groszkowski2018] Groszkowski et al., New J. Phys. 20, 043053 (2018), https://doi.org/10.1088/1367-2630/aab7cd .. [Ithier2005] Ithier et al., Phys. Rev. B 72 134519 (2005), https://journals.aps.org/prb/abstract/10.1103/PhysRevB.72.134519 .. [Koch2007] Koch et al., Phys. Rev. A 76, 042319 (2007), https://link.aps.org/doi/10.1103/PhysRevA.76.042319 .. [Manucharyan2009] Manucharyan et al., Science 326, 113-116 (2009), https://doi.org/10.1126/science.1175552 -.. [Nguyen2019] Nguyen et al., Phys. Rev. X 041041 (2019), https://journals.aps.org/prx/abstract/10.1103/PhysRevX.9.041041 +.. [Nguyen2019] Nguyen et al., Phys. Rev. X 9, 041041 (2019), https://journals.aps.org/prx/abstract/10.1103/PhysRevX.9.041041 .. [Orlando1999] Orlando et al., Phys. Rev. B 60, 15398 (1999), https://link.aps.org/doi/10.1103/PhysRevB.60.15398 -.. [Pop2014] Pop et al., Nature, 508 (7496) (2014), https://www.nature.com/articles/nature13017/ +.. [Pop2014] Pop et al., Nature 508 (7496) (2014), https://www.nature.com/articles/nature13017/ .. [Schoelkopf2003] Schoelkopf et al., Quantum noise in mesoscopic physics, pp. 175-203. (2003), https://link.springer.com/chapter/10.1007/978-94-010-0089-5_9 .. [Smith2020] Smith et al., npj Quantum Information 6.1 (2020), https://www.nature.com/articles/s41534-019-0231-2 .. [Zhu2013] Zhu et al., PRB 87, 024510 (2013), https://link.aps.org/doi/10.1103/PhysRevB.87.024510 diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 29ef137..9c1b8a8 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -192,7 +192,7 @@ Version 4.3 make sure this is secure. - Fix parameter functions for parametric driving in the Circuit module. - Fix configure method in `SymbolicCircuit`, now does not reset the instance when run with no arguments. - - Fix bugs #193 and #209 related to`ParameterSweep`. + - Fix bugs #193 and #209 related to `ParameterSweep`. - Fix compatibility of `Circuit` module with `HilbertSpace`, bugs #253 and #254. - Fix #211, a bug that could occur when `op_in_dressed_eigenbasis` was called without prior lookup generation. - `SymbolicCircuit` instances now do not need to be re-initiated when their `configure` method fails (e.g., because of incorrect parameters). @@ -218,7 +218,7 @@ Version 4.2 **BUG FIXES** - - Fix prefactor for evaluations noise spectral density for quasiparticle noise - adds an additional factor of :math:`\hbar/e^2`. + - Fix prefactor for evaluation of noise spectral density for quasiparticle noise - adds an additional factor of :math:`\hbar/e^2`. - Fix error in symbolic Hamiltonian for multi-harmonic junctions. **UNDER THE HOOD** @@ -393,7 +393,7 @@ Version 3.0.3 **Under the hood** - - Initialization of a circuit instance now does not globally switch to latex output (avoids unnecessary slowdowns with regular, non-sympy, output. + - Initialization of a circuit instance now does not globally switch to latex output (avoids unnecessary slowdowns with regular, non-sympy, output). Version 3.0.2 @@ -415,7 +415,7 @@ Version 3.0.2 **Under the hood** - All numerical diagonalization is now delayed until explicitly required. Changing circuit parameters thus does not incur a repeated runtime cost anymore. - - When hierarchical diagonalization is used, the bare eigensystems for each subsystems are now stored and reused for calculations, and only replaced by a new set when necessary. This dramatically improves the performance of wavefunction plotting, identity wrapping, etc. + - When hierarchical diagonalization is used, the bare eigensystems for each subsystem are now stored and reused for calculations, and only replaced by a new set when necessary. This dramatically improves the performance of wavefunction plotting, identity wrapping, etc. - If the circuit parameters are not updated, successive diagonalizations are skipped for all subsystems. - Implemented `eigsh_safe` (wrapper for scipy.sparse.linalg.eigsh) that orthogonalizes the eigenvectors when degenerate eigenvalues are detected. In rare cases of actual degeneracies in the spectrum, sparse matrix methods could have given incorrect results because `scipy.sparse.linalg.eigsh` does not guarantee orthogonality of eigenvectors in degenerate subspaces. @@ -498,8 +498,8 @@ Version 2.2.2 overlap)^2 instead of (state overlap) for thresholding. **Under the Hood** - typing_extensions is new dependency (used for enhanced typing annotations such as - `@overload` and `Literal` + typing_extensions is a new dependency (used for enhanced typing annotations such as + `@overload` and `Literal`) Version 2.2 @@ -508,7 +508,7 @@ Version 2.2 **Bug Fixes** - Use of `.plot_transitions` could previously lead to a spurious switch of `["evals"]` to transition energies. - - Include the :math:`/frac{1}{1}hbar` omega term when diagonalizing fluxonium in the harmonic + - Include the :math:`\frac{1}{2}\hbar\omega` term when diagonalizing fluxonium in the harmonic osc. basis. The omission of this only affected absolute energies, not the energy differences which are the relevant quantities in most cases. However, wavefunction plots for fluxonium were previously incorrectly positioned relative to the potential energy. @@ -534,7 +534,7 @@ Version 2.2 - `supported_noise_channels` and `effective_noise_channels` are now `@classmethods` and can be called either directly through a class, or through a class instance. - `t1_charge_impedance` is no longer returned by `effective_noise_channels` in the - case of a `TunableTransmon` and `Transmon` qubits + case of `TunableTransmon` and `Transmon` qubits - Added about function that shows basic information about scqubits as well as versions of some of the most important libraries that scqubits relies on. - Extended `pytests` for enhanced coverage. @@ -684,7 +684,7 @@ Version 1.1.0 +++++++++++++ - new class ``InteractionTerm`` works in tandem with ``HilbertSpace`` to ease setup of composite systems with pairwise interactions - - new ``ParameterSweep`` class efficiently generates spectral data for performing a scan of a ``HilbertSpace`` object over an external parameters + - new ``ParameterSweep`` class efficiently generates spectral data for performing a scan of a ``HilbertSpace`` object over external parameters - new ``Explorer`` class introduces interactive plots (see docs and demo ipynb) - cleaned up implementation of file Serializable operations diff --git a/docs/source/contents.rst b/docs/source/contents.rst index ff93bda..641c6b8 100644 --- a/docs/source/contents.rst +++ b/docs/source/contents.rst @@ -2,7 +2,7 @@ Copyright (C) 2019, Jens Koch & Peter Groszkowski -scQubits documentation +scqubits documentation ====================== scqubits is an open-source Python library for simulating superconducting qubits. diff --git a/docs/source/example-notebooks.rst b/docs/source/example-notebooks.rst index c3068b1..4e284b3 100644 --- a/docs/source/example-notebooks.rst +++ b/docs/source/example-notebooks.rst @@ -14,7 +14,7 @@ Users can easily clone it to their local file system by executing:: git clone https://github.com/scqubits/scqubits-examples -The full contents of `scqubits-examples` can also be explored in a live jupyter +The full contents of `scqubits-examples` can also be explored in a live Jupyter notebook via Binder: .. image:: https://mybinder.org/badge_logo.svg diff --git a/docs/source/guide/basics/basics-spectra.ipynb b/docs/source/guide/basics/basics-spectra.ipynb index 9b02484..d9a4ab4 100644 --- a/docs/source/guide/basics/basics-spectra.ipynb +++ b/docs/source/guide/basics/basics-spectra.ipynb @@ -1249,12 +1249,7 @@ "name": "#%% md\n" } }, - "source": [ - "### Plotting energy dispersion\n", - "The sensitivity of energy levels (or, more specifically, transition energies) to changes in an external parameter like the offset charge are important for qubit's dephasing time. Plots of the energy dispersion, can be obtained easily:\n", - "\n", - "* either for individual energy levels:" - ] + "source": "### Plotting energy dispersion\nThe sensitivity of energy levels (or, more specifically, transition energies) to changes in an external parameter like the offset charge is important for the qubit's dephasing time. Plots of the energy dispersion can be obtained easily:\n\n* either for individual energy levels:" }, { "cell_type": "code", @@ -4979,4 +4974,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/basics/basics-wavefunctions.ipynb b/docs/source/guide/basics/basics-wavefunctions.ipynb index f579fcb..5a4e00f 100644 --- a/docs/source/guide/basics/basics-wavefunctions.ipynb +++ b/docs/source/guide/basics/basics-wavefunctions.ipynb @@ -43,9 +43,7 @@ "name": "#%% md\n" } }, - "source": [ - "For a qubit as simple as the transmon, wavefunctions are one-dimensional and can be plotted easily. The first option, is to employ the discrete charge basis (`n`):" - ] + "source": "For a qubit as simple as the transmon, wavefunctions are one-dimensional and can be plotted easily. The first option is to employ the discrete charge basis (`n`):" }, { "cell_type": "code", @@ -4977,4 +4975,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_bases.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_bases.ipynb index 9d3a828..651a927 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_bases.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_bases.ipynb @@ -48,19 +48,7 @@ "name": "#%% md\n" } }, - "source": [ - "### Basis choices\n", - "\n", - "For **periodic degrees of freedom** scqubits employs the discrete charge basis.\n", - "\n", - "For **extended degrees of freedom** two choices are available:\n", - "- `ext_basis = \"discretized\"` (default)
Discretizes the variables for extended degrees of freedom.\n", - "- `ext_basis = \"harmonic\"`
Employs the harmonic-oscillator basis for th extended degrees of freedom (taking the potential to be the one arising from the geometric inductance).\n", - "\n", - "For instance, the following would switch the treatment of the extended degrees of freedom to using harmonic-oscillator basis:\n", - "\n", - "`zero_pi = scq.Circuit.from_yaml_string(zp_yaml, ext_basis=\"harmonic\")`" - ] + "source": "### Basis choices\n\nFor **periodic degrees of freedom** scqubits employs the discrete charge basis.\n\nFor **extended degrees of freedom** two choices are available:\n- `ext_basis = \"discretized\"` (default)
Discretizes the variables for extended degrees of freedom.\n- `ext_basis = \"harmonic\"`
Employs the harmonic-oscillator basis for the extended degrees of freedom (taking the potential to be the one arising from the geometric inductance).\n\nFor instance, the following would switch the treatment of the extended degrees of freedom to using harmonic-oscillator basis:\n\n`zero_pi = scq.Circuit.from_yaml_string(zp_yaml, ext_basis=\"harmonic\")`" }, { "cell_type": "markdown", @@ -110,18 +98,7 @@ "name": "#%% md\n" } }, - "source": [ - "These cutoffs must be varied by the user to ensure convergence. \n", - "We distinguish two cutoff types:\n", - "\n", - "#### Cutoffs for periodic degrees of freedom:\n", - "- `cutoff_n_` - use all the integer charge states in the range `[-cutoff_n_, cutoff_n_]` for the periodic degree of freedom $i$.\n", - "\n", - "#### Cutoffs for extended degrees of freedom:\n", - "- `cutoff_ext_` - the meaning of this cutoff differs according to the choice of basis, specified via `ext_basis` upon initialization of the `Circuit` instance.\n", - " - `ext_basis = \"discretized\"`:
For discretization of $\\theta_i$, `cutoff_ext_` sets the number of points used to in the \"spatial\" range given by the attribute `discretized_phi_range`.\n", - " - `ext_basis = \"harmonic\"`:
When using the harmonic oscillator basis, `cutoff_ext_` sets the number of harmonic oscillator states admitted to the basis set for the extended degree of freedom $i$." - ] + "source": "These cutoffs must be varied by the user to ensure convergence. \nWe distinguish two cutoff types:\n\n#### Cutoffs for periodic degrees of freedom:\n- `cutoff_n_` - use all the integer charge states in the range `[-cutoff_n_, cutoff_n_]` for the periodic degree of freedom $i$.\n\n#### Cutoffs for extended degrees of freedom:\n- `cutoff_ext_` - the meaning of this cutoff differs according to the choice of basis, specified via `ext_basis` upon initialization of the `Circuit` instance.\n - `ext_basis = \"discretized\"`:
For discretization of $\\theta_i$, `cutoff_ext_` sets the number of points used in the \"spatial\" range given by the attribute `discretized_phi_range`.\n - `ext_basis = \"harmonic\"`:
When using the harmonic oscillator basis, `cutoff_ext_` sets the number of harmonic oscillator states admitted to the basis set for the extended degree of freedom $i$." }, { "cell_type": "code", @@ -262,11 +239,7 @@ "name": "#%% md\n" } }, - "source": [ - "## Choosing basis states for each of the subsystems\n", - "It is also possible to chose a basis states for each of the subsystems independently.\n", - "We start with defining a particular circuit" - ] + "source": "## Choosing basis states for each of the subsystems\nIt is also possible to choose basis states for each of the subsystems independently.\nWe start with defining a particular circuit" }, { "cell_type": "code", @@ -505,4 +478,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_coherence_estimates.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_coherence_estimates.ipynb index 96075b2..64256c5 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_coherence_estimates.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_coherence_estimates.ipynb @@ -62,28 +62,12 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "There two important arguments that are passed to `Circuit` constructor which determine if and how noise can calculated:\n", - "\n", - "`generate_noise_methods`: A boolean argument that determines whether methods for estimating coherences are generated for this object. \n", - "\n", - "`use_dynamic_flux_grouping`: A boolean argument that determines if a flux-grouping based on this [You at al. PRB(2019)](https://journals.aps.org/prb/abstract/10.1103/PhysRevB.99.174512) (or [arXiv](https://arxiv.org/abs/1902.04734)) paper is generated. This grouping approach is recommended any time flux is assumed to have time-dependence (due to noise, or otherwise) as it aims to group flux among different branches in a way that would not require a term proportional to the flux-derivative. \n", - "\n", - "\n", - ".. warning::\n", - "If `generate_noise_methods` is not set to `True` when building a `Circuit` object, none of the coherence methods will be generated. Users can however, choose to generate them at a later time by executing `circ.configure(generate_noise_methods=True)`. \n", - "\n", - ".. warning::\n", - "If `use_dynamic_flux_grouping` is not set to `True` when estimating coherence times, to obtain results related to flux noise, `scqubits` will utilize a more arbitrary grouping, and not the one proposed by [You at al. PRB(2019)](https://journals.aps.org/prb/abstract/10.1103/PhysRevB.99.174512). \n" - ] + "source": "There are two important arguments that are passed to the `Circuit` constructor, which determine whether and how noise can be calculated:\n\n`generate_noise_methods`: A boolean argument that determines whether methods for estimating coherences are generated for this object. \n\n`use_dynamic_flux_grouping`: A boolean argument that determines if a flux-grouping based on this [You et al. PRB(2019)](https://journals.aps.org/prb/abstract/10.1103/PhysRevB.99.174512) (or [arXiv](https://arxiv.org/abs/1902.04734)) paper is generated. This grouping approach is recommended any time flux is assumed to have time-dependence (due to noise, or otherwise) as it aims to group flux among different branches in a way that would not require a term proportional to the flux-derivative. \n\n\n.. warning::\nIf `generate_noise_methods` is not set to `True` when building a `Circuit` object, none of the coherence methods will be generated. Users can however, choose to generate them at a later time by executing `circ.configure(generate_noise_methods=True)`. \n\n.. warning::\nIf `use_dynamic_flux_grouping` is not set to `True` when estimating coherence times, to obtain results related to flux noise, `scqubits` will utilize a more arbitrary grouping, and not the one proposed by [You et al. PRB(2019)](https://journals.aps.org/prb/abstract/10.1103/PhysRevB.99.174512). " }, { "cell_type": "markdown", "metadata": {}, - "source": [ - "### Auto-generated `supported channels`\n", - "The `circ` object now contains a variety of `supported_noise_methods` which can be explicitly listed with:" - ] + "source": "### Auto-generated `supported channels`\nThe `circ` object now contains a variety of `supported_noise_channels` which can be explicitly listed with:" }, { "cell_type": "code", @@ -180,9 +164,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "and look at the depolarization $T_1$ time, at temperature of 0.1 mK, due to the capacitor between nodes 0 and 3 (i.e., of branch 4), but only including contributions from the downward rate between levels 2 and 1:" - ] + "source": "and look at the depolarization $T_1$ time, at a temperature of 0.1 K, due to the capacitor between nodes 0 and 3 (i.e., of branch 4), but only including contributions from the downward rate between levels 2 and 1:" }, { "cell_type": "code", @@ -2986,4 +2968,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_define_more.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_define_more.ipynb index 576da63..57f1e5b 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_define_more.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_define_more.ipynb @@ -156,19 +156,7 @@ "cell_type": "markdown", "id": "c3ff9245", "metadata": {}, - "source": [ - "A `Circuit` instance can also be initiated with a symbolic Hamiltonian. The Hamiltonian can be written using `sympy.parse_expr`. The returned symbolic expression can be used with the Circuit module. \n", - "\n", - "The expression should adhere to the following rules:\n", - "\n", - "- Each extended degree of freedom uses the conjugate variables $\\theta_i$ and $Q_i$.\n", - "- Each periodic degree of freedom uses the conjugate variables $\\theta_i$ and $n_i$.\n", - " - if $\\theta_i$ is periodic, the variable should not appear outside a trigonometric function. \n", - "- The offset charge is represented by $n_{gi}$ and external flux by $\\Phi_i$. The external flux variables are in the units of flux quantum $\\Phi_0$.\n", - "- Any symbolic parameters used, should be defined with its initial value in the dictionary `symbolic_params_dict`.\n", - "\n", - "Here is an example demonstrating the use of symbolic Hamiltonian:" - ] + "source": "A `Circuit` instance can also be initiated with a symbolic Hamiltonian. The Hamiltonian can be written using `sympy.parse_expr`. The returned symbolic expression can be used with the Circuit module. \n\nThe expression should adhere to the following rules:\n\n- Each extended degree of freedom uses the conjugate variables $\\theta_i$ and $Q_i$.\n- Each periodic degree of freedom uses the conjugate variables $\\theta_i$ and $n_i$.\n - if $\\theta_i$ is periodic, the variable should not appear outside a trigonometric function. \n- The offset charge is represented by $n_{gi}$ and external flux by $\\Phi_i$. The external flux variables are in the units of flux quantum $\\Phi_0$.\n- Any symbolic parameters used should be defined with their initial values in the dictionary `symbolic_param_dict`.\n\nHere is an example demonstrating the use of symbolic Hamiltonian:" }, { "cell_type": "code", @@ -280,4 +268,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_extra.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_extra.ipynb index 046003b..4a1e5dd 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_extra.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_extra.ipynb @@ -135,9 +135,7 @@ "cell_type": "markdown", "id": "1ffe885b", "metadata": {}, - "source": [ - "Note that external flux for loops including a capacitor are also included. The external flux in the capacitive loops will not effect the eigenvalue calculation as fluxes are considered to be static. When fluxes are dynamic, it is important to choose the loops and the corresponding external fluxes carefully by setting the closure branches (which sets the appropriate spanning tree) using the `configure` method." - ] + "source": "Note that external flux for loops including a capacitor are also included. The external flux in the capacitive loops will not affect the eigenvalue calculation, as fluxes are considered to be static. When fluxes are dynamic, it is important to choose the loops and the corresponding external fluxes carefully by setting the closure branches (which sets the appropriate spanning tree) using the `configure` method." }, { "cell_type": "markdown", @@ -400,4 +398,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_hd.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_hd.ipynb index 7d57d35..d57b3bd 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_hd.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_hd.ipynb @@ -8,19 +8,7 @@ "name": "#%% md\n" } }, - "source": [ - "## Hierarchical diagonalization\n", - "\n", - "For a large circuit with many degrees of freedoms, a possibly efficient way of obtaining low-lying eigenenergies and eigenstates is to partition the system into several subsystems, and to use the low-lying energy eigenstates of each subsystems as basis states to diagonalize the full system Hamiltonian. The schematic diagram below illustrates how hierarchical diagonalization is performed:\n", - "\n", - "![HD](./custom_circuit_HD.svg)\n", - "\n", - "For the example of the zero-pi qubit, the expression from `sym_hamiltonian` shows that $\\theta_2$ corresponds to the harmonic zeta mode of the zero-pi qubit. The remaining variables $\\theta_1$ and $\\theta_3$ form the primary qubit degrees of freedom and may be considered a \"separate\", weakly coupled subsystem. \n", - "\n", - "\n", - "### System hierarchy\n", - "This idea of a **subsystem hierarchy is made explicit by grouping circuit variable indices in a nested list**:" - ] + "source": "## Hierarchical diagonalization\n\nFor a large circuit with many degrees of freedom, a possibly efficient way of obtaining low-lying eigenenergies and eigenstates is to partition the system into several subsystems, and to use the low-lying energy eigenstates of each subsystem as basis states to diagonalize the full system Hamiltonian. The schematic diagram below illustrates how hierarchical diagonalization is performed:\n\n![HD](./custom_circuit_HD.svg)\n\nFor the example of the zero-pi qubit, the expression from `sym_hamiltonian` shows that $\\theta_2$ corresponds to the harmonic zeta mode of the zero-pi qubit. The remaining variables $\\theta_1$ and $\\theta_3$ form the primary qubit degrees of freedom and may be considered a \"separate\", weakly coupled subsystem. \n\n\n### System hierarchy\nThis idea of a **subsystem hierarchy is made explicit by grouping circuit variable indices in a nested list**:" }, { "cell_type": "code", @@ -294,4 +282,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_offsets.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_offsets.ipynb index aeb5228..a24d532 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_offsets.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_offsets.ipynb @@ -94,9 +94,7 @@ "name": "#%% md\n" } }, - "source": [ - "External fluxes (in unit of $2\\pi$) and offset charges can be adjusted via:" - ] + "source": "External fluxes (in units of the flux quantum $\\Phi_0$) and offset charges can be adjusted via:" }, { "cell_type": "code", @@ -141,4 +139,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_parametric_driving.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_parametric_driving.ipynb index 7649017..ffd06e9 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_parametric_driving.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_parametric_driving.ipynb @@ -1378,14 +1378,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "## Time dependent drives\n", - "We need to decide on the parameters we would want to modulate with time. In the above instance, let us try driving the fluxonium with both charge and flux drives. For flux driving a fluxonium, `use_dynamic_flux_grouping` should be set to `True` (refer to [Hierarchical diagonalization](./custom_circuit_hd.ipynb)). For flux driving, let us choose the parameter $\\Phi_1$.\n", - "\n", - "Note that for charge driving the fluxonium, there are no terms in the Hamiltonian of the form $ng*Q_1$, where $ng$ is offset charge and $Q_1$ is the charge operator. Therefore, we will use the option `extra_terms` in the method `hamiltonian_for_qutip_dynamics` to add the term $Q1*ng1$ and use the variable $ng1$ to simulate an external charge drive. \n", - "\n", - "We can now define the time dependent functions which give the value of the above parameters at a given time. Do note, that the values set to the corresponding attributes of the `Circuit` module (in this case the attribute $\\Phi_1$) will not be used. " - ] + "source": "## Time dependent drives\nWe need to decide on the parameters we would want to modulate with time. In the above instance, let us try driving the fluxonium with both charge and flux drives. For flux driving a fluxonium, `use_dynamic_flux_grouping` should be set to `True` (refer to [Time dependent flux grouping](./custom_circuit_extra.ipynb)). For flux driving, let us choose the parameter $\\Phi_1$.\n\nNote that for charge driving the fluxonium, there are no terms in the Hamiltonian of the form $ng*Q_1$, where $ng$ is offset charge and $Q_1$ is the charge operator. Therefore, we will use the option `extra_terms` in the method `hamiltonian_for_qutip_dynamics` to add the term $Q1*ng1$ and use the variable $ng1$ to simulate an external charge drive. \n\nWe can now define the time dependent functions which give the value of the above parameters at a given time. Do note, that the values set to the corresponding attributes of the `Circuit` module (in this case the attribute $\\Phi_1$) will not be used. " }, { "cell_type": "code", @@ -3857,4 +3850,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/circuit/ipynb/custom_circuit_visualization.ipynb b/docs/source/guide/circuit/ipynb/custom_circuit_visualization.ipynb index 26fae18..fb549bc 100644 --- a/docs/source/guide/circuit/ipynb/custom_circuit_visualization.ipynb +++ b/docs/source/guide/circuit/ipynb/custom_circuit_visualization.ipynb @@ -1075,11 +1075,7 @@ "name": "#%% md\n" } }, - "source": [ - "The potential can be visualized using `plot_potential`.\n", - "\n", - "For the zero-pi example, there are three degrees of freedoms $(\\theta_1, \\theta_2, \\theta_3)$. We can either fix all but two, or all but one variable. This produces either a contour plot of the potential within the selected 2d region, " - ] + "source": "The potential can be visualized using `plot_potential`.\n\nFor the zero-pi example, there are three degrees of freedom $(\\theta_1, \\theta_2, \\theta_3)$. We can either fix all but two, or all but one variable. This produces either a contour plot of the potential within the selected 2d region, " }, { "cell_type": "code", @@ -12339,14 +12335,7 @@ "name": "#%% md\n" } }, - "source": [ - "### Plotting the wavefunction\n", - "Visualization of the wavefunction are obtained with `plot_wavefunction`. The argument `which` specifies the energy eigenstate for which the wavefunction is plotted; `var_indices` specifies the variable axis along which the wavefunction is plotted; `mode` specifies how the wavefunction amplitude is processed for visualization, options are `real`, `image`, `abs`, and `abs-sqr` as introduced in [Wavefunctions](../../basics/basics-wavefunctions.ipynb).\n", - "\n", - "Depending on the argument provided for `var_indices` and degrees of freedom that a system possess, different sets of options for `mode` are available.\n", - "\n", - "- If `var_indices` includes all the degrees of freedom in the system, all four options of the mode are supported." - ] + "source": "### Plotting the wavefunction\nVisualization of the wavefunction are obtained with `plot_wavefunction`. The argument `which` specifies the energy eigenstate for which the wavefunction is plotted; `var_indices` specifies the variable axis along which the wavefunction is plotted; `mode` specifies how the wavefunction amplitude is processed for visualization, options are `real`, `imag`, `abs`, and `abs-sqr` as introduced in [Wavefunctions](../../basics/basics-wavefunctions.ipynb).\n\nDepending on the argument provided for `var_indices` and the degrees of freedom that a system possesses, different sets of options for `mode` are available.\n\n- If `var_indices` includes all the degrees of freedom in the system, all four options of the mode are supported." }, { "cell_type": "markdown", @@ -14734,9 +14723,7 @@ "cell_type": "markdown", "id": "f77515e4", "metadata": {}, - "source": [ - "- If `var_indices` does not includes all the degrees of freedom in the system, the wavefunction can only be visualized in the `abs-sqr` mode. The probability density (i.e. the absolute square of the wavefunction) is integrated over the non-specified variable indices, which produces a marginal probability density function." - ] + "source": "- If `var_indices` does not include all the degrees of freedom in the system, the wavefunction can only be visualized in the `abs-sqr` mode. The probability density (i.e. the absolute square of the wavefunction) is integrated over the non-specified variable indices, which produces a marginal probability density function." }, { "cell_type": "code", @@ -14822,4 +14809,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/docs/source/guide/convergence/guide-convergence.rst b/docs/source/guide/convergence/guide-convergence.rst new file mode 100644 index 0000000..cf91cac --- /dev/null +++ b/docs/source/guide/convergence/guide-convergence.rst @@ -0,0 +1,993 @@ +.. scqubits + Copyright (C) 2019, Jens Koch & Peter Groszkowski + +.. _guide_convergence: + +************************** +Convergence Diagnostics +************************** + +Every qubit in scqubits is modeled by a Hamiltonian that, in general, acts on an +infinite-dimensional Hilbert space; scqubits represents it numerically as a finite +matrix by truncating the basis it is expressed in. The transmon, for example, is +represented in a finite charge basis controlled by ``ncut``; fluxonium in a +harmonic-oscillator basis controlled by ``cutoff``; the grid-based qubits +discretize a flux coordinate on a finite box. The numbers scqubits returns -- +energies, wavefunctions, matrix elements, coherence times -- are only as accurate +as that truncated representation allows. If the cutoff is too small, results are +silently wrong; if it is far too large, calculations are needlessly slow. + +The convergence-diagnostics framework answers a single practical question: *for +the cutoff I have chosen, is there any reason to distrust the result, and what +should I do if there is?* + +**A convergence test can only ever dismiss convergence.** This is the central +idea, and it shapes every verdict the framework returns. A test refines the +cutoff and looks for the spectrum still moving, for an eigenstate spilling over +the basis boundary, for a refinement series that refuses to contract. When it +finds one of these, it has *caught a clearly-wrong result* -- a strong, useful, +negative statement. When it finds none of them, all it can honestly say is *"I +failed to dismiss this"*; that is never a proof that the true error is small. A +more rigorous mode simply applies sharper dismissal tests, so a result that +survives it has survived more. The most actionable signal the framework can give +you is therefore a ``distrust`` verdict: it means a check actively caught a +result you should not rely on at the current cutoff. + +.. note:: + + Convergence diagnostics are available for :class:`.Transmon`, + :class:`.TunableTransmon`, :class:`.Fluxonium`, :class:`.FluxQubit`, + :class:`.ZeroPi`, :class:`.FullZeroPi`, and :class:`.Cos2PhiQubit`, covering the + energy spectrum and -- on request -- the wavefunctions, matrix elements, and + coherence rates. Coupled :class:`.HilbertSpace` systems are supported as well + (see :ref:`guide_convergence_composite`), as are custom :class:`.Circuit` + instances, including hierarchically diagonalized ones (see + :ref:`guide_convergence_circuit`), and precomputed :class:`.ParameterSweep` + grids (see :ref:`guide_convergence_paramvals`). Calling the top-level + ``scq.check_convergence(obj)`` on anything else raises :class:`TypeError`. + + +Quick start +=========== + +The shortest path to "is my qubit converged?" is the :func:`scqubits.csc` +convenience (**c**\ onvergence **s**\ anity **c**\ heck), which picks sensible +defaults and returns a pretty-printable verdict with no further input:: + + >>> import scqubits as scq + >>> q = scq.Transmon(EJ=20.0, EC=0.3, ng=0.0, ncut=31, truncated_dim=4) + >>> print(scq.csc(q)) + +prints a header, a one-line ``VERDICT:``, a plain-English explanation, an +optional next-step tip, and the full underlying +:class:`~scqubits.core.convergence_report.ConvergenceReport`. If the verdict +is anything but a clean pass, the recommendations name *which* cutoff to grow. + +**Calling** ``csc`` **on the same object twice escalates the check from** +``mode="moderate"`` **to** ``mode="strict"`` -- if you doubt the first +answer, just ask again. The default precision target (``1e-4`` GHz, i.e. +0.1 MHz) and the auto-chosen ``n_levels`` cap are tunable as +``settings.CSC_DEFAULT_TARGET_ABS_GHZ`` and +``settings.CSC_DEFAULT_NLEVELS_CAP``; see :ref:`settings-params` for the full +list of scqubits settings. + +``csc`` is a zero-input wrapper around the full +:meth:`~scqubits.core.convergence.ConvergenceCheckable.check_convergence` +API documented below; use the full API when you need to control ``n_levels``, +``target_abs_GHz``, ``mode``, ``scope``, derived quantities, or +parameter-sweep checks. + + +The verdicts +============ + +Every level is assigned one of five verdicts, ordered from best (left) to worst +(right):: + + likely_converged > maybe_converged > marginal > unverified > distrust + +``likely_converged`` + Passed the ``strict`` two-step ratio/asymptoticity test -- the strongest + statement the framework makes, and still not an outright guarantee. + +``maybe_converged`` + Passed the ``moderate`` one-step refinement check: a larger cutoff was tried + and the spectrum did not move appreciably. + +``marginal`` + The estimated error sits close to the requested target -- a borderline + result that may or may not meet your needs. + +``unverified`` + Neither dismissed nor verified: a ``cheap`` pass, or a level that could not + be assessed (for example, no target was supplied). + +``distrust`` + A test *actively dismissed* convergence. The result is not trustworthy at + this cutoff. This includes the strict-mode ratio test failing + (:math:`R \ge 1`), a kept eigenstate reaching the basis boundary, and a + charge-basis energy that *rises* under refinement (a variational-monotonicity + violation -- see :ref:`guide_convergence_monotonicity`). + +Read these the right way round. ``likely_converged`` and ``maybe_converged`` +both mean *"we failed to dismiss this level"*, with the former having survived a +harder test; neither is a certificate. ``distrust`` is the one verdict that +states a fact with confidence -- we caught a result you should not use as is. + +The verdict name carries the confidence directly. To see *why* a level earned +its verdict -- which falsification tests ran and how they fared -- read its +structured ``checks`` record together with the ``estimator_method`` and any +``warnings`` (see :ref:`guide_convergence_checks`); there is no separate +evidence-tier field. + + +The basic workflow +================== + +Reaching a trustworthy result is a short loop: estimate, read the verdict, and -- +if necessary -- increase the cutoff and repeat. + +1. **Build the qubit** at an initial cutoff:: + + import scqubits as scq + + tmon = scq.Transmon(EJ=20.0, EC=0.3, ng=0.0, ncut=31, truncated_dim=6) + +2. **Check convergence** for the levels you care about. You either call the + method on the qubit or use the top-level shim; they are equivalent:: + + report = tmon.check_convergence(n_levels=5, target_abs_GHz=1e-4) + # identical to: + report = scq.check_convergence(tmon, n_levels=5, target_abs_GHz=1e-4) + +3. **Read the verdict.** The report prints itself:: + + print(report) # human-readable summary of every level + print(report.aggregate_status) # e.g. 'maybe_converged' + worst = report.level(report.worst_level) # the driving level's verdict + + For the ``ncut=31`` transmon above, ``print(report)`` produces:: + + aggregate: maybe_converged (worst: level 0) + + lvl status channel err (GHz) via + 0 maybe_converged charge_tail 7.11e-15 one_step + 1 maybe_converged charge_tail 1.85e-13 one_step + 2 maybe_converged charge_tail 2.47e-13 one_step + 3 maybe_converged charge_tail 4.97e-14 one_step + 4 maybe_converged charge_tail 4.44e-14 one_step + + error by channel (GHz): charge_tail=2.47e-13 + + Every estimated error sits far below the ``1e-4`` GHz target and the default + moderate refinement found no movement, so each level is ``maybe_converged``: + ``ncut=31`` was not dismissed for these parameters. (Exact digits depend on + the platform and diagonalization backend; a passing level prints no per-check + line -- those appear only under a dismissed or borderline level.) + +4. **Act on the recommendation.** When a level is dismissed, the printed report + ends with a plain-language fix for each problem channel. For an under-resolved + transmon it reads:: + + recommendation: charge-basis tail dominates: increase ncut from 6 to at least 10 (charge cutoff) and re-run + + The same lines are also available as a list of strings in + ``report.recommendations``. Apply the suggested change and repeat from step 2; + a typical loop settles in one or two iterations. + +The default mode (``mode='moderate'``) performs one extra diagonalization at a +larger cutoff and compares the two spectra level by level. It is the recommended +setting: cheap enough for routine use, and it actually tries a larger cutoff +rather than reasoning about one. + + +Notation +======== + +Let :math:`N` be the cutoff parameter and :math:`E_{k,N}` the :math:`k`-th +computed eigenvalue. The (unknown) true error of a level is +:math:`\Delta E_{k,N} = |E_{k,N} - E_k|`; every diagnostic reports an *estimate* +:math:`\widehat{\mathrm{err}}_{k,N} \approx \Delta E_{k,N}`, never the true error +itself. A refinement bumps the cutoff to :math:`N_1 > N_0` (and, in strict mode, +a second :math:`N_2 > N_1`); the per-level refinement differences are + +.. math:: + + d_{0,k} = |E_{k,N_1} - E_{k,N_0}|, \qquad + d_{1,k} = |E_{k,N_2} - E_{k,N_1}|. + +A safety factor :math:`S` (default :math:`2`, ``settings.CONVERGENCE_SAFETY_FACTOR``) +multiplies one-step estimates. + + +Setting a target +================ + +A convergence verdict only means something relative to a target accuracy. In the +default **absolute** scope you say how accurate you need the energies to be, in +GHz, via ``target_abs_GHz`` :math:`\equiv \Delta_\star`. With +:math:`\widehat{\mathrm{err}}_{k}` the per-level estimate, before the mode +ceiling is applied (see below), the verdict is + +.. math:: + + \begin{aligned} + \widehat{\mathrm{err}}_{k} < \Delta_\star &\;\Rightarrow\; \texttt{(pass)}, \\ + \Delta_\star \le \widehat{\mathrm{err}}_{k} < 10\,\Delta_\star &\;\Rightarrow\; \texttt{marginal}, \\ + \widehat{\mathrm{err}}_{k} \ge 10\,\Delta_\star &\;\Rightarrow\; \texttt{distrust}. + \end{aligned} + +A pass is then capped at the best verdict the mode is entitled to claim -- +``maybe_converged`` for moderate, ``likely_converged`` for strict (see +:ref:`guide_convergence_modes`). A ``marginal`` or ``distrust`` dismissal is +never softened or raised. + +If you omit ``target_abs_GHz``, scqubits still computes and reports the per-level +estimate ``abs_err_est_GHz``, but it does not convert that into a pass/fail +verdict -- the verdict is ``unverified`` and a recommendation reminds you to +supply a target. + +If you care about error *relative to the qubit's own spectrum* rather than an +absolute energy, choose the observed-gap scope:: + + report = tmon.check_convergence( + n_levels=5, scope="observed_gap_scale", target_gap_rel=1e-3 + ) + +Here the per-level error is divided by the local isolation gap + +.. math:: + + g_{\rm iso}(k) = + \begin{cases} + E_{1,N}-E_{0,N}, & k=0,\\ + \min\{E_{k,N}-E_{k-1,N},\, E_{k+1,N}-E_{k,N}\}, & 0 < k < n_{\rm levels}-1, + \end{cases} + +floored at ``g_floor_GHz`` (default :math:`10^{-3}` GHz = 1 MHz) to avoid +dividing by an accidentally tiny gap, giving +:math:`\widetilde\epsilon_{{\rm gap},k} = \widehat{\mathrm{err}}_{k}/\max\{g_{\rm iso}(k), g_{\rm floor}\}`. +The same ``< target`` / ``< 10\,target`` thresholds apply, with a default +relative target :math:`10^{-3}`. One eigenvalue beyond the requested levels is +computed automatically (in the same diagonalization) so the highest requested +level still has an upper neighbor for the gap; if it is unavailable the level +carries an ``upper_gap_unavailable`` warning. + +.. note:: + + The observed-gap scope normalizes by an *observed* spectral gap, never by a + basis-set frequency scale. A basis parameter such as the fluxonium LC + frequency is useful internally but is not a physical low-energy scale, so it + is deliberately not used as a reporting denominator. + + +.. _guide_convergence_modes: + +Choosing a mode +=============== + +The ``mode`` argument trades cost for the rigor of the dismissal test. Because a +test can only dismiss convergence -- never prove it -- each mode also **caps** the +best verdict it can return: a stronger claim demands more work. The next section +gives the estimator equations behind each. + +``mode='cheap'`` + Cheap per-level diagnostics with **no extra diagonalization**, computed from + the eigenvectors you already have (the charge finite-tail estimate for charge + bases, the harmonic-oscillator finite-window estimate for fluxonium). It can + still *dismiss* a level -- a kept state reaching the basis boundary is caught + here -- but a level it fails to dismiss earns at best ``unverified``: cheap + mode makes no verification claim. Use it for rapid feedback while exploring + parameters. + +``mode='moderate'`` (default) + One refinement diagonalization at a larger cutoff, compared against the + current one -- an actual measurement of how much the spectrum is still + moving. A level it fails to dismiss caps at ``maybe_converged``. + +``mode='strict'`` + Two refinement diagonalizations, used to run an asymptoticity test (a + geometric ratio test, or Richardson extrapolation for finite-difference + grids) before trusting a tail-extrapolated error estimate. A level that + passes caps at ``likely_converged`` -- the strongest verdict available; a + level whose refinement differences are not shrinking (:math:`R \ge 1`) is + dismissed to ``distrust`` rather than softened to ``marginal``. + +:: + + cheap = tmon.check_convergence(n_levels=5, mode="cheap") + moderate = tmon.check_convergence(n_levels=5, mode="moderate", + target_abs_GHz=1e-4) + strict = tmon.check_convergence(n_levels=5, mode="strict", + target_abs_GHz=1e-4) + + +How each check works +==================== + +This section gives the estimator used by each mode and truncation channel, +together with its equation. Every estimate is empirical or perturbative; none is +a theorem-level bound, and a passing estimate is always a failure to dismiss +rather than a guarantee. + +Refinement estimators (energies) +-------------------------------- + +**One-step (moderate mode).** The estimate is the safety-scaled one-step +refinement difference, + +.. math:: + + \widehat{\mathrm{err}}_{k} = S\, d_{0,k}, + +a direct measurement of how the spectrum responds to a larger cutoff, scaled by +the conservative safety factor :math:`S`. This is an observed refinement +difference, not a proof that the sequence has reached its asymptotic regime -- +for that, use ``mode='strict'``, which adds a second refinement and tests whether +the refinement differences are contracting. + +**Two-step geometric ratio test (strict mode, charge / HO channels).** With both +refinement differences available, the per-level ratio and geometric-tail estimate are + +.. math:: + + R_k = \frac{d_{1,k}}{d_{0,k}}, \qquad + \widehat{\mathrm{err}}_{k} = \frac{S\,d_{0,k}}{1 - R_k}\quad (R_k < 1). + +A cluster with :math:`R_k < 1` is in the asymptotic regime and the geometric tail +is reported (capped at ``likely_converged`` for a passing level). If +:math:`R_k \ge 1` on a non-negligible refinement difference the series is not +contracting: the level is dismissed to ``distrust`` rather than ``marginal``, and +carries a ``ratio_test_not_asymptotic`` warning. + +**Richardson extrapolation (strict mode, finite-difference stencil).** For an FD +grid the discretization error scales as :math:`h^p` with spacing +:math:`h \propto 1/(N-1)` at a fixed box, where :math:`p` is the stencil order +(``settings.STENCIL`` :math:`-\,1`; the default 7-point stencil gives +:math:`p=6`). With :math:`g_i = 1/(N_i-1)^p` the coarse-grid error and the +model-predicted refinement-difference ratio are + +.. math:: + + \widehat{\mathrm{err}}_{k} = \frac{d_{0,k}}{1 - g_1/g_0}, \qquad + \rho_{\rm expected} = \frac{g_1 - g_2}{g_0 - g_1}. + +The level is asymptotic when the observed ratio :math:`d_{1,k}/d_{0,k}` matches +:math:`\rho_{\rm expected}` to within a relative tolerance; otherwise it falls +back to the one-step estimate. + +.. note:: + + How well the :math:`h^p` regime is realized is parameter-, box-, and + grid-dependent. A lower-order stencil (e.g. 5-point, :math:`p=4`) tends to + realize its order over a wider usable grid range, whereas the higher-order + default reaches the round-off floor sooner. Where the regime is not realized + the asymptoticity test rejects and the engine falls back to the one-step + estimate -- a safe outcome (no false convergence). + +Cluster-safe matching +--------------------- + +Near degeneracies, matching levels by index is unreliable. Consecutive levels +whose internal gaps are small compared with the neighboring external gaps are +grouped into a *cluster*, compared as a sorted set, and assigned a common +error estimate plus a ``cluster_index_ambiguity`` warning. + +Here :math:`U_{N_0}` and :math:`U_{N_1}` are the **eigenvector blocks** spanning +that cluster at two cutoffs :math:`N_0` and :math:`N_1` -- the relevant columns +of the diagonalizing unitary (orthonormal, embedded in a common basis). Inside a +(near-)degenerate block the individual eigenvectors are not physically +well-defined -- they can rotate arbitrarily among themselves between cutoffs -- +so the diagnostic compares the *spans* of the blocks rather than vector-by-vector +overlaps. The subspace diagnostic is the sine of the largest principal angle +between those two spans, + +.. math:: + + \sin\Theta = \bigl\| (I - U_{N_0} U_{N_0}^\dagger)\, U_{N_1} \bigr\|_2, + +which is :math:`0` when the cluster's eigenspace is unchanged under refinement +and :math:`1` when it has rotated to a fully orthogonal direction. It is the +cluster-level analogue of one minus a wavefunction overlap, robust to eigenvector +rotations within the block. Being built from eigenvectors alone, it is +dimensionless and independent of the active energy unit +(:func:`~scqubits.set_units`); it is *not* one of the GHz-valued error estimates. + +.. _guide_convergence_monotonicity: + +Variational monotonicity +------------------------ + +For an *exactly nested* basis truncation, enlarging the basis cannot raise an +ordered eigenvalue (the Rayleigh--Ritz min--max theorem): +:math:`E_{k,N_1} \le E_{k,N_0}` for :math:`N_1 > N_0`. In scqubits this holds for +the **charge basis** -- growing ``ncut`` borders the kept block with additional +charge states, so the smaller Hamiltonian is an exact principal submatrix of the +larger. Every refinement therefore carries a near-free falsification test: a +charge-basis energy that *rises* by more than the eigensolver noise floor +violates the variational bound, and the level is dismissed to ``distrust`` in any +mode -- such a rise signals an operator-construction or backend problem rather +than mere truncation. The check is silent on healthy results and is restricted to +the charge basis: harmonic-oscillator bases build the potential from matrix +functions of the *truncated* quadratures (so the truncation is not nested), and +finite-difference grids are non-variational, so a rise there is legitimate and +those channels are excluded. + +Cheap estimators (cheap mode) +----------------------------- + +**Charge finite tail (Transmon and TunableTransmon).** For the transmon's +nearest-neighbor (single-cosine) Josephson Hamiltonian -- tridiagonal in the +charge basis -- the dropped charge states couple to the kept space only through +the two boundary charges, so a second-order (resolvent) estimate uses the boundary +amplitudes :math:`c_{R,k}=\langle n_{\rm cut}|u_k\rangle`, +:math:`c_{L,k}=\langle -n_{\rm cut}|u_k\rangle`, + +.. math:: + + \widehat{\mathrm{err}}^{\rm ch}_{k} + = \left| \frac{E_J^2}{4}\Bigl( |c_{R,k}|^2\, G_R + |c_{L,k}|^2\, G_L \Bigr) \right|, + \qquad G_{R/L} = \bigl[(T^{(d)}_{R/L} - E_{k} I)^{-1}\bigr]_{11}, + +where :math:`T^{(d)}` is the depth-:math:`d` tridiagonal block of the dropped +tail (diagonal :math:`4E_C(n-n_g)^2`, hopping :math:`-E_J/2`); :math:`d` is grown +until the estimate stabilizes. At :math:`d=1` this reduces to the familiar +boundary-denominator estimate with denominators +:math:`4E_C(n_{\rm cut}+1\mp n_g)^2 - E_{k}`. It is reliable only when the tail +is perturbative: if a tail eigenvalue lies at or below :math:`E_k` the level is +``unverified``, and if the boundary probability :math:`|c_{R,k}|^2+|c_{L,k}|^2` +is large the level is dismissed to ``distrust`` with a +``boundary_probability_large`` warning regardless of the estimate. A +multi-dimensional charge basis (such as :class:`.FluxQubit`, which has several +boundary faces and a coupling structure not captured by the 1D formula) does not +use this estimator; its cheap mode falls back to a boundary diagnostic and it is +moderate-recommended. + +**Harmonic-oscillator finite window (fluxonium).** The cosine is not banded in +the oscillator basis, so the dropped-space residual must use the full kept +vector. For a dropped window :math:`W=\{N,\dots,N+d-1\}`, + +.. math:: + + (r_W)_m = \sum_{j=0}^{N-1} \langle m|\hat H|j\rangle\, c_{j,k}, \qquad + \eta^{\rm HO}_{W,k} = \bigl| \langle r_W,\, (H_{WW} - E_k I)^{-1} r_W\rangle \bigr|, + +with the kept-to-dropped coupling :math:`\langle m|\hat H|j\rangle = -E_J\langle +m|\cos(\hat\varphi+\varphi_{\rm ext})|j\rangle` taken from the cosine on an +extended Fock basis (the LC term is diagonal and does not couple kept to +dropped). A further dropped band gives the omitted-residual norm +:math:`\rho_{\rm tail} = \sum_{m \ge N+d} |(r_W)_m|^2`; if it is not small +compared with :math:`\|r_W\|^2`, or a window eigenvalue lies at or below +:math:`E_k`, the estimate is flagged unreliable. The result is a perturbative +estimate with an omitted-tail diagnostic, **not a bound** -- a finite dropped +window omits both the far-dropped residual and the Schur self-energy of the rest +of the dropped space, so it is not sign-definite. If :math:`\rho_{\rm tail}` is +not small the level is reported ``unverified`` in cheap mode; moderate mode +remains authoritative. The dismissal-triggering boundary probability is a separate +quantity -- the occupation of the top few kept Fock states, the oscillator analog +of the charge-edge probability -- whose large value raises +``boundary_probability_large`` independently of the window estimate. + +Finite-difference grids: two channels +------------------------------------- + +A discretized (finite-difference) extended variable on a box :math:`[-L,L]` with +spacing :math:`h` has **two independent truncation channels** that require +different tests, and a check must verify both. + +* **Finite box** (``FD_box``). A small endpoint amplitude is not a bound on the + error from the wall at :math:`\pm L`. The cheap diagnostic is the edge-band + probability over :math:`q=\max\{5,\lceil w_{\rm edge}/h\rceil\}` points at each + end (with :math:`w_{\rm edge}` a few percent of the window -- at least a few + stencil half-widths -- and :math:`q` capped at half the grid), + + .. math:: + + P_{\rm edge}(k) = \sum_{i=0}^{q-1} |c_{i,k}|^2 + + \sum_{i=N_{\rm grid}-q}^{N_{\rm grid}-1} |c_{i,k}|^2 . + + A large :math:`P_{\rm edge}` is a reliable warning that the box is too small. + The box is verified by an expanded-box calculation at comparable spacing + (increase :math:`L`, hold :math:`h`); adding grid points at fixed :math:`L` + cannot fix a box error. + +* **Finite spacing** (``FD_stencil``). At fixed box, stencil error is tested by + grid refinement and the Richardson estimate above. + +For ZeroPi these are exposed as separate refinement axes (``grid_box`` widens the +window at fixed :math:`h`; ``grid_spacing`` adds points at a fixed window), +alongside the ``charge_tail`` of the theta basis. + +Multi-coordinate qubits (composite) +----------------------------------- + +When several truncation channels contribute, their absolute estimates are +combined by the triangle inequality, and the *sum* (not the maximum) sets the +verdict: + +.. math:: + + \widehat{\mathrm{err}}^{\rm total}_{k} \le \sum_c \widehat{\mathrm{err}}^{(c)}_{k}. + +The per-level ``truncation_channel`` is then the dominant physical channel, while +``channel_breakdown_GHz`` retains the per-channel contributions for display. + +Transition frequencies +---------------------- + +Each level verdict also carries ``transition_err_est_GHz``, the triangle-inequality +bound on a transition error, + +.. math:: + + \widehat{\Delta\omega}_{ij} \le \widehat{\mathrm{err}}_{i} + \widehat{\mathrm{err}}_{j}. + + +Reading the report +================== + +``check_convergence`` returns a :class:`.ConvergenceReport`. Printing it (or +calling :meth:`~.ConvergenceReport.summary`) gives a readable rundown; the fields +are also available programmatically: + +``aggregate_status`` + The overall verdict, equal to the worst per-level verdict: one of + ``likely_converged``, ``maybe_converged``, ``marginal``, ``unverified``, or + ``distrust``. + +``per_level`` / :meth:`~.ConvergenceReport.level` + A list of :class:`.LevelVerdict`, one per requested level; + ``report.level(k)`` looks one up by level index. A dismissed high-lying + level never hides the standing of the lower levels. + +``worst_level`` + The index of the level that determined the aggregate verdict; + ``report.level(report.worst_level)`` retrieves it. + +``channel_breakdown_GHz`` + The per-channel error contributions (in GHz). + +``recommendations`` + Channel-specific next steps (which cutoff to grow, whether to enlarge an FD + box rather than add points, flagged ``boundary_probability_large`` levels). + +``clusters`` + Groups of near-degenerate levels, compared as a set rather than by index. + +``implementation_audit`` + A record of exactly what was diagnosed: scqubits version, qubit class, basis, + diagonalization method, cutoff parameters, the requested and buffer level + counts, and the mode/refinement used. + +``derived`` + When derived quantities are requested, a mapping from each name to its own + :class:`.ConvergenceReport`; ``None`` otherwise. + +Each :class:`.LevelVerdict` carries a ``status`` (the verdict), a ``status_scope`` +(``absolute`` or ``observed_gap_scale``), an ``abs_err_est_GHz`` estimate, an +optional ``eps_gap_est``, the ``transition_err_est_GHz`` map, a +``truncation_channel`` (``charge_tail``, ``HO_tail``, ``FD_box``, ``FD_stencil``, +or ``composite_coupling``), an ``estimator_method`` (e.g. ``one_step``, +``ratio_test``, ``finite_tail_resolvent``), any ``warnings``, and a structured +``checks`` record (below). The verdict name itself records the confidence -- +there is no separate evidence-tier field. + + +.. _guide_convergence_checks: + +Which checks ran: the per-level ``checks`` record +------------------------------------------------- + +To make the verdict auditable, each :class:`.LevelVerdict` carries a ``checks`` +tuple of :class:`.CheckOutcome` (``name``, ``status``, ``detail``) recording the +falsification tests that applied to the level and how each fared. The status of a +check is ``pass`` (it ran and did not dismiss the level), ``fail`` (it ran and +dismissed the level), or ``not_applicable`` (it does not apply in the chosen mode +or for this channel). The tests recorded are: + +* ``asymptoticity`` -- the ``strict`` two-step ratio / Richardson test (recorded + ``not_applicable`` outside ``strict`` mode, or when the refinement sits at the + eigensolver noise floor); +* ``boundary`` -- the kept-state amplitude at the basis boundary, where a + boundary diagnostic exists (``detail`` reports the edge probability); +* ``monotonicity`` -- the charge-basis variational check (present only for a + charge axis); +* ``perturbative_tail`` -- the reliability of the ``cheap``-mode tail estimator. + +For example, the printed report shows the per-check line under each level:: + + level 1: distrust channel=charge_tail abs_err=1.65e-04 via ratio_test + checks: asymptoticity=pass boundary=pass(P_edge=5.4e-05) monotonicity=pass + +and ``report.level(1).checks`` exposes the same record programmatically. + +The ``checks`` are the *falsification tests*; they are distinct from the +estimate-vs-target grading. A level can therefore be ``distrust`` with **every +check passing** -- this means no test caught a structural problem, but the +estimated error still exceeded ``target_abs_GHz`` (or ``target_gap_rel``). In +that case the fix is simply a larger cutoff; ``abs_err_est_GHz`` and the target +tell you how far off you are. + + +Derived quantities +------------------ + +By default the report covers the energy spectrum. Pass ``include_derived=True`` +together with ``derived_quantities`` to additionally assess any of +``"wavefunctions"``, ``"matrix_elements"``, and ``"coherence"``; each comes back +as its own :class:`.ConvergenceReport` under ``report.derived`` and requires +``mode='moderate'`` or ``'strict'`` (a refinement comparison is needed):: + + report = tmon.check_convergence( + n_levels=5, mode="moderate", target_abs_GHz=1e-4, + include_derived=True, + derived_quantities=["wavefunctions", "matrix_elements", "coherence"], + ) + print(report.derived["wavefunctions"].aggregate_status) + +Eigenvectors and matrix elements generally converge no faster than -- and often +slower than -- eigenvalues: for an isolated level the eigenvector rotation scales +like :math:`\|r_k\|/\delta_k` (Davis--Kahan), linear in the residual, whereas the +eigenvalue error of a Ritz pair can scale like :math:`\|r_k\|^2/\delta_k` +(Kato--Temple) under an isolating-gap assumption. scqubits does not compute these +bounds; it measures the refinement change of each quantity directly. Each derived +sub-report stores the dimensionless +change of the quantity in ``rel_change_est``. + +**Wavefunctions** -- the overlap deficit :math:`1 - |\langle\psi_{N_0,k}| +\psi_{N_1,k}\rangle|` for an isolated level, or the cluster subspace angle +:math:`\sin\Theta` above for a near-degenerate block. + +**Matrix elements** -- per level, the worst relative change of that level's +matrix-element row and column, maximized over the operators named by +``get_operator_names``. Elements are compared by magnitude, since each +eigenvector's global phase is a gauge choice that can differ between cutoffs. + +**Coherence** -- one verdict per noise channel (those from +``effective_noise_channels``, plus aggregate :math:`T_1` and :math:`T_2`). Rates +are compared first (converted to Hz), + +.. math:: + + \frac{|\Gamma_{N_1} - \Gamma_{N_0}|}{\max\{|\Gamma_{N_1}|,\, \Gamma_{\rm floor}\}}, + +and a channel whose rate falls below ``CONVERGENCE_RATE_FLOOR_HZ`` carries a +``noise_floor`` warning instead of a lifetime claim. + + +.. _guide_convergence_paramvals: + +Convergence across a parameter sweep +==================================== + +A single report covers one parameter set. A plot such as +``plot_evals_vs_paramvals`` instead sweeps a parameter at a *fixed* cutoff, and +truncation convergence can vary across that range -- a cutoff that is comfortable +at one flux value can be marginal at another. Use +:meth:`~.ConvergenceCheckable.check_convergence_vs_paramvals` to check the +worst case:: + + import numpy as np + + fluxonium = scq.Fluxonium(EJ=10.0, EC=5.0, EL=1.0, flux=0.5, cutoff=35) + flux_vals = np.linspace(0.0, 0.5, 101) + sweep = fluxonium.check_convergence_vs_paramvals( + "flux", flux_vals, sample=5, n_levels=5, target_abs_GHz=1e-4 + ) + print(sweep) # per-point verdict, worst marked + print(sweep.worst_param_val()) # the value where the cutoff is least trusted + worst = sweep.worst_report() # the full ConvergenceReport there + +Here ``cutoff=35`` is comfortable near zero flux but degrades as the flux +approaches the half-flux point, so ``print(sweep)`` shows a verdict that varies +across the range:: + + convergence across sweep of (flux) (5 points): worst = marginal at flux=0.375 + flux=0: maybe_converged + flux=0.125: maybe_converged + flux=0.25: maybe_converged + flux=0.375: marginal <-- worst + flux=0.5: marginal + +``sweep.worst_param_val()`` then returns ``0.375`` and ``sweep.worst_report()`` +hands back the full :class:`.ConvergenceReport` at that point for a closer look. + +It runs the per-point check at ``sample`` values spread across the range (always +including both endpoints, the usual worst case; ``sample=None`` checks every +value), restores the swept parameter afterward, and returns a +:class:`.ParameterSweepConvergence` holding every per-point report and the worst case. + +For a precomputed :class:`.ParameterSweep` -- which sweeps a coupled +:class:`.HilbertSpace` over an N-dimensional grid through an +``update_hilbertspace`` callback -- call +:meth:`~.ParameterSweep.check_convergence` instead. It applies the callback at +sampled grid points (the grid corners first, then evenly-spread interior points up +to ``sample``; ``sample=None`` checks every point), runs the composite +:meth:`~.HilbertSpace.check_convergence` at each, restores the sweep, and +returns a :class:`.ParameterSweepConvergence`:: + + import numpy as np + + qbt = scq.TunableTransmon( + EJmax=30.0, EC=0.3, d=0.1, flux=0.0, ng=0.0, ncut=31, truncated_dim=5 + ) + osc = scq.Oscillator(E_osc=5.0, truncated_dim=5) + hs = scq.HilbertSpace([qbt, osc]) + hs.add_interaction(g=0.3, op1=qbt.n_operator, op2=osc.creation_operator, + add_hc=True) + + def update_hilbertspace(flux): + qbt.flux = flux + + sweep = scq.ParameterSweep( + hs, {"flux": np.linspace(0.0, 0.5, 21)}, update_hilbertspace + ) + result = sweep.check_convergence( + n_levels=4, mode="moderate", target_abs_GHz=1e-4 + ) + print(result) + +:: + + convergence across sweep of (flux) (8 points): worst = marginal at flux=0.375 + flux=0: maybe_converged + flux=0.5: maybe_converged + flux=0.25: maybe_converged + flux=0.175: maybe_converged + flux=0.325: maybe_converged + flux=0.125: maybe_converged + flux=0.375: marginal <-- worst + flux=0.1: maybe_converged + +Each point is a parameter-name-to-value mapping, so multi-parameter sweeps are +reported by their full coordinates; ``result.worst_point()`` and +``result.worst_report()`` give the least-trustworthy grid point and its full +report. Unlike the single-object helper above, this honors the sweep's +``update_hilbertspace`` callback (which may set several coupled parameters at once) +and handles grids over more than one parameter. + + +A complete example +================== + +Start with a deliberately small cutoff and let the loop guide you to a +trustworthy result:: + + import scqubits as scq + + tmon = scq.Transmon(EJ=20.0, EC=0.3, ng=0.0, ncut=6, truncated_dim=6) + + report = tmon.check_convergence(n_levels=5, target_abs_GHz=1e-6) + print(report) # the full diagnostic + +At ``ncut=6`` the moderate refinement catches the offending levels and spells out +the fix:: + + aggregate: distrust (worst: level 1) + + lvl status channel err (GHz) via + 0 marginal charge_tail 8.90e-06 one_step + checks 0: asymptoticity=n/a(strict mode only) boundary=pass(P_edge=3.2e-06) monotonicity=pass + 1 distrust charge_tail 1.65e-04 one_step + checks 1: asymptoticity=n/a(strict mode only) boundary=pass(P_edge=5.4e-05) monotonicity=pass + 2 distrust charge_tail 1.43e-03 one_step + checks 2: asymptoticity=n/a(strict mode only) boundary=pass(P_edge=0.00042) monotonicity=pass + 3 distrust charge_tail 7.78e-03 one_step [boundary_probability_large] + checks 3: asymptoticity=n/a(strict mode only) boundary=fail(P_edge=0.002) monotonicity=pass + 4 distrust charge_tail 2.92e-02 one_step [boundary_probability_large] + checks 4: asymptoticity=n/a(strict mode only) boundary=fail(P_edge=0.0068) monotonicity=pass + + error by channel (GHz): charge_tail=2.92e-02 + -> charge-basis tail dominates: increase ncut from 6 to at least 10 (charge cutoff) and re-run + -> levels [3, 4] carry the 'boundary_probability_large' warning: the kept state reaches the basis boundary, so the dropped tail is non-perturbative -- increase the cutoff aggressively + +The lowest level is only borderline (``marginal``); the higher levels reach the +basis boundary and are badly truncated, so they are dismissed to ``distrust``. +This is exactly the signal you want -- the framework caught a clearly-wrong +result. Follow the recommendation and re-run:: + + tmon.ncut = 31 # follow the recommendation + report = tmon.check_convergence(n_levels=5, target_abs_GHz=1e-6) + print(report.aggregate_status) + +The aggregate verdict is now:: + + maybe_converged + +Every level passes the moderate one-step check against the ``1e-6`` GHz target. +Note the verdict is ``maybe_converged``, not an unqualified guarantee: the +moderate refinement found no movement, which is the most this single check can +claim. + +For a fast scan while exploring parameters, drop the extra diagonalization:: + + report = tmon.check_convergence(n_levels=5, mode="cheap", target_abs_GHz=1e-6) + print(report.aggregate_status) + +which prints:: + + unverified + +Cheap mode skips the refinement diagonalization, so a level it does not dismiss +earns only ``unverified`` -- it can flag a clearly-wrong result, but it never +makes a verification claim. + +For the strongest available check, demand the asymptoticity test:: + + report = tmon.check_convergence( + n_levels=5, mode="strict", target_abs_GHz=1e-6 + ) + print(report.level(report.worst_level).status) + +which prints:: + + likely_converged + +The refinement series contracts and passes the ratio test, so the worst level +reaches ``likely_converged`` -- the strongest verdict the framework makes, and +still a failure to dismiss rather than a proof. + + +.. _guide_convergence_composite: + +Coupled subsystems (HilbertSpace) +================================= + +A :class:`.HilbertSpace` truncates in **two layers**, and +``hs.check_convergence(...)`` checks both: + +* **Layer 1 -- subsystem-internal.** Each subsystem carries its own basis cutoff + (``ncut``, ``cutoff``, a grid). Every capable subsystem is checked with its own + :meth:`~.ConvergenceCheckable.check_convergence` -- at ``truncated_dim`` plus + the refinement reach, so the extra levels a composite refinement pulls in are + themselves verified -- and the per-subsystem report is attached under + ``report.derived["subsystem:"]``. Oscillators have no internal cutoff and + are skipped. Pass ``assume_subsystems_converged=True`` to skip this layer when + subsystem convergence has been established separately. + +* **Layer 2 -- composite truncation.** Each subsystem's ``truncated_dim`` sets how + many of its levels enter the product space. This is verified by refining one + ``truncated_dim`` at a time, re-diagonalizing the *whole* composite, and + comparing cluster-matched spectra -- a single composite refinement that counts + subsystem and coupling leakage exactly once, rather than double-counting a + per-subsystem leakage plus a separate coupling term. The channel is + ``composite_coupling`` and the dominant subsystem is the one to grow. + +The ``aggregate_status`` is the worst of the composite verdict and every +subsystem verdict: the composite cannot be more converged than its parts. + +:: + + import scqubits as scq + + tmon = scq.Transmon(EJ=20.0, EC=0.3, ng=0.0, ncut=31, truncated_dim=3) + osc = scq.Oscillator(E_osc=5.0, truncated_dim=3) + hs = scq.HilbertSpace([tmon, osc]) + hs.add_interaction( + g=0.6, op1=tmon.n_operator, op2=osc.creation_operator, add_hc=True + ) + + report = hs.check_convergence(n_levels=3, mode="moderate", target_abs_GHz=1e-5) + print(report) + +With the resonator truncated to only three levels the composite is dismissed. The +report names the subsystem to grow, flags the near-resonance, and attaches the +(undismissed) subsystem report underneath:: + + aggregate: distrust (worst: level 0) + + lvl status channel err (GHz) via + 0 distrust composite_coupling 1.14e-04 one_step + checks 0: asymptoticity=n/a(strict mode only) + 1 distrust composite_coupling 4.86e-03 one_step + checks 1: asymptoticity=n/a(strict mode only) + 2 distrust composite_coupling 3.17e-03 one_step + checks 2: asymptoticity=n/a(strict mode only) + + error by channel (GHz): composite_coupling=6.43e-03 + -> composite truncation dominates: increase truncated_dim of 'Oscillator_1' from 3 to at least 5 and re-run (it sets how many of that subsystem's levels enter the product space) + -> hybridization screen: near-resonant coupling (eta ~= 1.1) between bare product states of 'Transmon_1' and 'Oscillator_1'; product-state labels are unreliable -- rely on cluster-safe matching and full composite refinement + derived [subsystem:Transmon_1]: + aggregate: maybe_converged (worst: level 0) + + lvl status channel err (GHz) via + 0 maybe_converged charge_tail 7.11e-15 one_step + 1 maybe_converged charge_tail 1.85e-13 one_step + 2 maybe_converged charge_tail 2.47e-13 one_step + 3 maybe_converged charge_tail 4.97e-14 one_step + 4 maybe_converged charge_tail 4.44e-14 one_step + + error by channel (GHz): charge_tail=2.47e-13 + +Raising the resonator (and transmon) ``truncated_dim`` -- here to 8 -- clears the +dismissal. + +**Hybridization screen.** When subsystems are coupled near resonance, the bare +product-state labels :math:`|a,b\rangle` mix strongly. For each two-body +interaction :math:`g\,A\otimes B` the report computes a dimensionless +hybridization parameter + +.. math:: + + \eta_{ab\to a'b'} = \frac{|g|\,|\langle a'|A|a\rangle|\,|\langle b'|B|b\rangle|} + {\max\{|(E_a+E_b)-(E_{a'}+E_{b'})|,\ g_{\rm floor}\}}, + +and warns when it is large (as above). A large :math:`\eta` means the product +labels are unreliable, so levels are matched as clusters rather than by index; it +is a labeling diagnostic, **not** a truncation-error estimate, and does not by +itself set ``distrust``. + +**Modes.** ``moderate`` and ``strict`` perform the full composite refinement and +are authoritative. ``cheap`` skips the composite re-diagonalization: it runs the +hybridization screen and each subsystem's own cheap check, and reports the +composite truncation as moderate-recommended (never a verification claim). + +**FullZeroPi.** The hierarchical :class:`.FullZeroPi` -- an interior +:class:`.ZeroPi` coupled to a zeta oscillator -- is checked the same two-layer +way. Layer 1 delegates to the interior ZeroPi's own check (its phi grid box/ +spacing and theta charge cutoff, with the FD diagnostics above), attached under +``report.derived["interior_zeropi"]``; layer 2 refines the coupling cutoffs +``zeropi_cutoff`` (how many 0-pi levels enter the coupling, channel +``composite_coupling``) and ``zeta_cutoff`` (the zeta Fock cutoff, channel +``HO_tail``). Pass ``assume_inner_converged=True`` to skip the interior check. + + +.. _guide_convergence_circuit: + +Custom circuits +=============== + +For a custom :class:`.Circuit` that is **not** hierarchically diagonalized, the +Hilbert space is a single product of the per-variable bases, and the refinement +axes are the variable cutoffs (``self.cutoff_names``): a periodic variable's charge +cutoff ``cutoff_n_`` (channel ``charge_tail``) and an extended variable's cutoff +``cutoff_ext_``. A discretized extended variable is a finite-difference grid +with the two truncation channels described above -- ``FD_box`` (the coordinate box +must be wide enough) and ``FD_stencil`` (the grid spacing, Richardson-extrapolated +in strict mode) -- while a harmonic extended variable uses ``HO_tail``. Each +cutoff is refined and the spectrum re-diagonalized; the dominant channel names the +cutoff to grow:: + + import scqubits as scq + + circ = scq.Circuit(yaml_string, from_file=False, ext_basis="discretized") + report = circ.check_convergence(n_levels=4, mode="moderate", target_abs_GHz=1e-4) + print(report) + +As for the other multi-coordinate qubits, cheap mode is moderate-recommended (a +coupled circuit basis has no clean cheap estimator). + +**Hierarchical diagonalization.** When the circuit is hierarchically diagonalized, +the check is two-layer, like :class:`.HilbertSpace`: layer 2 refines each top-level +subsystem's ``truncated_dim`` (channel ``composite_coupling``) and re-diagonalizes +the dressed spectrum; layer 1 delegates to each subsystem's own +``check_convergence`` (attached under ``report.derived["subsystem:"]``, and +skipped by ``assume_subsystems_converged=True``). The aggregate is the worse of the +two layers. A *nested* hierarchically diagonalized subsystem is recorded as +unchecked, to be verified separately. + +.. note:: + + A circuit returns at most ``truncated_dim`` eigenvalues, so ``n_levels`` (plus + one buffer level in the observed-gap scope) must not exceed ``truncated_dim``; + otherwise ``check_convergence`` raises :class:`ValueError`. + + +Settings +======== + +The defaults that control the diagnostics -- refinement step, cluster threshold, +safety factor :math:`S`, gap floor, rate floor, and default mode -- live in +:mod:`scqubits.settings` under the ``CONVERGENCE_*`` names and can be adjusted +globally; see the :ref:`guide-settings` section. + + +Worked example +============== + +A runnable companion notebook walks through the core workflow end to end: + +.. toctree:: + :maxdepth: 1 + + Convergence diagnostics: a worked example diff --git a/docs/source/guide/convergence/ipynb/convergence-workflow.ipynb b/docs/source/guide/convergence/ipynb/convergence-workflow.ipynb new file mode 100644 index 0000000..dcc0baa --- /dev/null +++ b/docs/source/guide/convergence/ipynb/convergence-workflow.ipynb @@ -0,0 +1,751 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1765b58a", + "metadata": {}, + "source": [ + "# Convergence diagnostics: a worked example\n", + "\n", + "This runnable notebook is the companion to the\n", + "[Convergence Diagnostics guide](../guide-convergence.rst) -- see the guide for the\n", + "concepts (the verdicts, modes, estimators, truncation channels, composite\n", + "systems, and sweeps). Here we run the core workflow end to end and inspect the\n", + "per-check record." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "5bc00350", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:08.990117Z", + "iopub.status.busy": "2026-05-27T20:44:08.988562Z", + "iopub.status.idle": "2026-05-27T20:44:13.537873Z", + "shell.execute_reply": "2026-05-27T20:44:13.535481Z" + } + }, + "outputs": [], + "source": [ + "import scqubits as scq" + ] + }, + { + "cell_type": "markdown", + "id": "f2c98ebe", + "metadata": {}, + "source": [ + "## Check convergence\n", + "\n", + "Build a qubit, then ask whether its lowest levels are converged to a target\n", + "accuracy (in GHz). The returned report prints itself." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "30da5b81", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:13.542967Z", + "iopub.status.busy": "2026-05-27T20:44:13.542967Z", + "iopub.status.idle": "2026-05-27T20:44:13.601377Z", + "shell.execute_reply": "2026-05-27T20:44:13.599249Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "aggregate: maybe_converged (worst: level 0)\n", + "\n", + " lvl status channel err (GHz) via\n", + " 0 maybe_converged charge_tail 7.11e-15 one_step\n", + " 1 maybe_converged charge_tail 1.85e-13 one_step\n", + " 2 maybe_converged charge_tail 2.47e-13 one_step\n", + " 3 maybe_converged charge_tail 4.97e-14 one_step\n", + " 4 maybe_converged charge_tail 4.44e-14 one_step\n", + "\n", + " error by channel (GHz): charge_tail=2.47e-13\n" + ] + } + ], + "source": [ + "tmon = scq.Transmon(EJ=20.0, EC=0.3, ng=0.0, ncut=31, truncated_dim=6)\n", + "report = tmon.check_convergence(n_levels=5, target_abs_GHz=1e-4)\n", + "print(report)" + ] + }, + { + "cell_type": "markdown", + "id": "a92df00f", + "metadata": {}, + "source": [ + "## A too-small cutoff is dismissed\n", + "\n", + "The actionable verdict is `distrust`: a check caught a clearly-wrong result and\n", + "spells out what to grow." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "7431b47d", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:13.608615Z", + "iopub.status.busy": "2026-05-27T20:44:13.608106Z", + "iopub.status.idle": "2026-05-27T20:44:13.632189Z", + "shell.execute_reply": "2026-05-27T20:44:13.629199Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "aggregate: distrust (worst: level 1)\n", + "\n", + " lvl status channel err (GHz) via\n", + " 0 marginal charge_tail 8.90e-06 one_step\n", + " checks 0: asymptoticity=n/a(strict mode only) boundary=pass(P_edge=3.2e-06) monotonicity=pass\n", + " 1 distrust charge_tail 1.65e-04 one_step\n", + " checks 1: asymptoticity=n/a(strict mode only) boundary=pass(P_edge=5.4e-05) monotonicity=pass\n", + " 2 distrust charge_tail 1.43e-03 one_step\n", + " checks 2: asymptoticity=n/a(strict mode only) boundary=pass(P_edge=0.00042) monotonicity=pass\n", + " 3 distrust charge_tail 7.78e-03 one_step [boundary_probability_large]\n", + " checks 3: asymptoticity=n/a(strict mode only) boundary=fail(P_edge=0.002) monotonicity=pass\n", + " 4 distrust charge_tail 2.92e-02 one_step [boundary_probability_large]\n", + " checks 4: asymptoticity=n/a(strict mode only) boundary=fail(P_edge=0.0068) monotonicity=pass\n", + "\n", + " error by channel (GHz): charge_tail=2.92e-02\n", + " -> charge-basis tail dominates: increase ncut from 6 to at least 10 (charge cutoff) and re-run\n", + " -> levels [3, 4] carry the 'boundary_probability_large' warning: the kept state reaches the basis boundary, so the dropped tail is non-perturbative -- increase the cutoff aggressively\n" + ] + } + ], + "source": [ + "small = scq.Transmon(EJ=20.0, EC=0.3, ng=0.0, ncut=6, truncated_dim=6)\n", + "print(small.check_convergence(n_levels=5, target_abs_GHz=1e-6))" + ] + }, + { + "cell_type": "markdown", + "id": "5ec19fa4", + "metadata": {}, + "source": [ + "## Follow the recommendation and re-check" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2e19aba8", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:13.638363Z", + "iopub.status.busy": "2026-05-27T20:44:13.636830Z", + "iopub.status.idle": "2026-05-27T20:44:13.664396Z", + "shell.execute_reply": "2026-05-27T20:44:13.660862Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "maybe_converged\n" + ] + } + ], + "source": [ + "small.ncut = 31\n", + "print(small.check_convergence(n_levels=5, target_abs_GHz=1e-6).aggregate_status)" + ] + }, + { + "cell_type": "markdown", + "id": "50995196", + "metadata": {}, + "source": [ + "## Modes trade cost for rigor\n", + "\n", + "`cheap` (no refinement) caps at `unverified`, `moderate` (one refinement) at\n", + "`maybe_converged`, and `strict` (two-step ratio test) at `likely_converged`." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c3df4de4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:13.670587Z", + "iopub.status.busy": "2026-05-27T20:44:13.670587Z", + "iopub.status.idle": "2026-05-27T20:44:13.712273Z", + "shell.execute_reply": "2026-05-27T20:44:13.709705Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cheap -> unverified\n", + "moderate -> maybe_converged\n", + "strict -> likely_converged\n" + ] + } + ], + "source": [ + "for mode in (\"cheap\", \"moderate\", \"strict\"):\n", + " r = tmon.check_convergence(n_levels=5, mode=mode, target_abs_GHz=1e-4)\n", + " print(f\"{mode:9s} -> {r.aggregate_status}\")" + ] + }, + { + "cell_type": "markdown", + "id": "2b582611", + "metadata": {}, + "source": [ + "## Read the report programmatically" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3b35e679", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:13.720017Z", + "iopub.status.busy": "2026-05-27T20:44:13.720017Z", + "iopub.status.idle": "2026-05-27T20:44:13.742434Z", + "shell.execute_reply": "2026-05-27T20:44:13.741406Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "aggregate : likely_converged\n", + "worst level : 0 -> likely_converged ( charge_tail )\n", + "channels : {'charge_tail': 2.469136006766348e-13}\n", + "recommendations: none\n" + ] + } + ], + "source": [ + "report = tmon.check_convergence(n_levels=5, mode=\"strict\", target_abs_GHz=1e-4)\n", + "print(\"aggregate :\", report.aggregate_status)\n", + "worst = report.level(report.worst_level)\n", + "print(\"worst level :\", report.worst_level, \"->\", worst.status,\n", + " \"(\", worst.truncation_channel, \")\")\n", + "print(\"channels :\", report.channel_breakdown_GHz)\n", + "print(\"recommendations:\", report.recommendations or \"none\")" + ] + }, + { + "cell_type": "markdown", + "id": "1ebdb092", + "metadata": {}, + "source": [ + "## Which checks ran\n", + "\n", + "The verdict name carries the confidence, but to see *why* a level earned it, read\n", + "its `checks` record: the falsification tests that applied, each `pass`, `fail`, or\n", + "`not_applicable`. These are distinct from the estimate-vs-target grading -- a\n", + "level can be `distrust` with every check passing, which means no test caught a\n", + "structural problem but the estimated error still exceeds the target (so the fix\n", + "is simply a larger cutoff)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7b5cfd13", + "metadata": { + "execution": { + "iopub.execute_input": "2026-05-27T20:44:13.750159Z", + "iopub.status.busy": "2026-05-27T20:44:13.750159Z", + "iopub.status.idle": "2026-05-27T20:44:13.774125Z", + "shell.execute_reply": "2026-05-27T20:44:13.772575Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "level 0 [likely_converged]: asymptoticity=not_applicable boundary=pass monotonicity=pass\n", + "level 1 [likely_converged]: asymptoticity=not_applicable boundary=pass monotonicity=pass\n", + "level 2 [likely_converged]: asymptoticity=not_applicable boundary=pass monotonicity=pass\n" + ] + } + ], + "source": [ + "report = tmon.check_convergence(n_levels=3, mode=\"strict\", target_abs_GHz=1e-4)\n", + "for verdict in report.per_level:\n", + " ran = \" \".join(f\"{check.name}={check.status}\" for check in verdict.checks)\n", + " print(f\"level {verdict.level_index} [{verdict.status}]: {ran}\")" + ] + }, + { + "cell_type": "markdown", + "id": "2d1a98e7", + "metadata": {}, + "source": [ + "That is the whole loop: estimate, read the verdict (and the per-check record),\n", + "grow the cutoff if it is dismissed, and repeat. For multi-coordinate qubits,\n", + "coupled `HilbertSpace` systems, the finite-difference channels, and parameter\n", + "sweeps, see the [guide](../guide-convergence.rst)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.15" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "13af7a6ab7494f5da035857ccc860bb8": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "265c1e18c27149af86cb93f1b2dcb75e": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.10.0", + "model_name": "ThemeColorsModel", + "state": { + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.10.0", + "_model_name": "ThemeColorsModel", + "_theme_name": "dark", + "_view_count": null, + "_view_module": null, + "_view_module_version": "^1.10.0", + "_view_name": null, + "accent": "#FF4081", + "anchor": null, + "error": "#FF5252", + "info": "#2196F3", + "primary": "#2196F3", + "secondary": "#424242", + "success": "#4CAF50", + "warning": "#FB8C00" + } + }, + "2f8175eaf4c54ba089876e11891e0efc": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.8.5", + "model_name": "ImgModel", + "state": { + "_dom_classes": [], + "_events": [], + "_jupyter_vue": "IPY_MODEL_a2bfa0a441db4fceb6b667c42fca2da9", + "_metadata": null, + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.8.5", + "_model_name": "ImgModel", + "_view_count": null, + "_view_module": "jupyter-vuetify", + "_view_module_version": "^1.8.5", + "_view_name": "VuetifyView", + "alt": null, + "aspect_ratio": null, + "attributes": {}, + "children": [], + "class_": null, + "contain": null, + "eager": null, + "gradient": null, + "height": null, + "layout": null, + "lazy_src": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "options": null, + "position": null, + "sizes": null, + "slot": null, + "src": "data:image/png;base64,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", + "srcset": null, + "style_": null, + "tabbable": null, + "tooltip": null, + "transition": null, + "v_model": "!!disabled!!", + "v_on": null, + "v_slots": [], + "width": 50.0 + } + }, + "3021efa1288e4212b1fc1ace7bfb1e83": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.8.5", + "model_name": "ImgModel", + "state": { + "_dom_classes": [], + "_events": [], + "_jupyter_vue": "IPY_MODEL_a2bfa0a441db4fceb6b667c42fca2da9", + "_metadata": null, + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.8.5", + "_model_name": "ImgModel", + "_view_count": null, + "_view_module": "jupyter-vuetify", + "_view_module_version": "^1.8.5", + "_view_name": "VuetifyView", + "alt": null, + "aspect_ratio": null, + "attributes": {}, + "children": [], + "class_": null, + "contain": null, + "eager": null, + "gradient": null, + "height": null, + "layout": null, + "lazy_src": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "options": null, + "position": null, + "sizes": null, + "slot": null, + "src": "data:image/png;base64,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", + "srcset": null, + "style_": null, + "tabbable": null, + "tooltip": null, + "transition": null, + "v_model": "!!disabled!!", + "v_on": null, + "v_slots": [], + "width": 50.0 + } + }, + "427fc2f204944cdbbc7ba85a2cc933be": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.10.0", + "model_name": "ThemeModel", + "state": { + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.10.0", + "_model_name": "ThemeModel", + "_view_count": null, + "_view_module": null, + "_view_module_version": "^1.10.0", + "_view_name": null, + "dark": null, + "dark_effective": null + } + }, + "835a31356882497cb5036495d82fee92": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.8.5", + "model_name": "ImgModel", + "state": { + "_dom_classes": [], + "_events": [], + "_jupyter_vue": "IPY_MODEL_a2bfa0a441db4fceb6b667c42fca2da9", + "_metadata": null, + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.8.5", + "_model_name": "ImgModel", + "_view_count": null, + "_view_module": "jupyter-vuetify", + "_view_module_version": "^1.8.5", + "_view_name": "VuetifyView", + "alt": null, + "aspect_ratio": null, + "attributes": {}, + "children": [], + "class_": null, + "contain": null, + "eager": null, + "gradient": null, + "height": null, + "layout": null, + "lazy_src": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "options": null, + "position": null, + "sizes": null, + "slot": null, + "src": "data:image/png;base64,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", + "srcset": null, + "style_": null, + "tabbable": null, + "tooltip": null, + "transition": null, + "v_model": "!!disabled!!", + "v_on": null, + "v_slots": [], + "width": 50.0 + } + }, + "851bd2e73a0f4d7c8b70c67b6b18fd76": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.8.5", + "model_name": "ImgModel", + "state": { + "_dom_classes": [], + "_events": [], + "_jupyter_vue": "IPY_MODEL_a2bfa0a441db4fceb6b667c42fca2da9", + "_metadata": null, + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.8.5", + "_model_name": "ImgModel", + "_view_count": null, + "_view_module": "jupyter-vuetify", + "_view_module_version": "^1.8.5", + "_view_name": "VuetifyView", + "alt": null, + "aspect_ratio": null, + "attributes": {}, + "children": [], + "class_": null, + "contain": null, + "eager": null, + "gradient": null, + "height": null, + "layout": null, + "lazy_src": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "options": null, + "position": null, + "sizes": null, + "slot": null, + "src": "data:image/png;base64,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", + "srcset": null, + "style_": null, + "tabbable": null, + "tooltip": null, + "transition": null, + "v_model": "!!disabled!!", + "v_on": null, + "v_slots": [], + "width": 50.0 + } + }, + "931703a3810c447783a38bf475332b07": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.8.5", + "model_name": "ImgModel", + "state": { + "_dom_classes": [], + "_events": [], + "_jupyter_vue": "IPY_MODEL_a2bfa0a441db4fceb6b667c42fca2da9", + "_metadata": null, + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.8.5", + "_model_name": "ImgModel", + "_view_count": null, + "_view_module": "jupyter-vuetify", + "_view_module_version": "^1.8.5", + "_view_name": "VuetifyView", + "alt": null, + "aspect_ratio": null, + "attributes": {}, + "children": [], + "class_": null, + "contain": null, + "eager": null, + "gradient": null, + "height": null, + "layout": null, + "lazy_src": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "options": null, + "position": null, + "sizes": null, + "slot": null, + "src": "data:image/png;base64,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", + "srcset": null, + "style_": null, + "tabbable": null, + "tooltip": null, + "transition": null, + "v_model": "!!disabled!!", + "v_on": null, + "v_slots": [], + "width": 50.0 + } + }, + "963d770ee9d449d089de5ba3ee4e026a": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.8.5", + "model_name": "ImgModel", + "state": { + "_dom_classes": [], + "_events": [], + "_jupyter_vue": "IPY_MODEL_a2bfa0a441db4fceb6b667c42fca2da9", + "_metadata": null, + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.8.5", + "_model_name": "ImgModel", + "_view_count": null, + "_view_module": "jupyter-vuetify", + "_view_module_version": "^1.8.5", + "_view_name": "VuetifyView", + "alt": null, + "aspect_ratio": null, + "attributes": {}, + "children": [], + "class_": null, + "contain": null, + "eager": null, + "gradient": null, + "height": null, + "layout": null, + "lazy_src": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "options": null, + "position": null, + "sizes": null, + "slot": null, + "src": "data:image/png;base64,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", + "srcset": null, + "style_": null, + "tabbable": null, + "tooltip": null, + "transition": null, + "v_model": "!!disabled!!", + "v_on": null, + "v_slots": [], + "width": 50.0 + } + }, + "a2bfa0a441db4fceb6b667c42fca2da9": { + "model_module": "jupyter-vue", + "model_module_version": "^1.11.0", + "model_name": "ForceLoadModel", + "state": { + "_dom_classes": [], + "_model_module": "jupyter-vue", + "_model_module_version": "^1.11.0", + "_model_name": "ForceLoadModel", + "_view_count": null, + "_view_module": null, + "_view_module_version": "", + "_view_name": null, + "layout": "IPY_MODEL_13af7a6ab7494f5da035857ccc860bb8", + "tabbable": null, + "tooltip": null + } + }, + "ad504733553d46de9327cc048aa3c3df": { + "model_module": "jupyter-vuetify", + "model_module_version": "^1.10.0", + "model_name": "ThemeColorsModel", + "state": { + "_model_module": "jupyter-vuetify", + "_model_module_version": "^1.10.0", + "_model_name": "ThemeColorsModel", + "_theme_name": "light", + "_view_count": null, + "_view_module": null, + "_view_module_version": "^1.10.0", + "_view_name": null, + "accent": "#82B1FF", + "anchor": null, + "error": "#FF5252", + "info": "#2196F3", + "primary": "#1976D2", + "secondary": "#424242", + "success": "#4CAF50", + "warning": "#FB8C00" + } + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/guide/explorer/ipynb/explorer.ipynb b/docs/source/guide/explorer/ipynb/explorer.ipynb index dd92f94..754fa5e 100644 --- a/docs/source/guide/explorer/ipynb/explorer.ipynb +++ b/docs/source/guide/explorer/ipynb/explorer.ipynb @@ -81,11 +81,7 @@ "name": "#%% md\n" } }, - "source": [ - "Here, the `truncated_dim` parameters are important. For the fluxonium, with `cutoff` set to 110, the internal Hilbert space dimension is 110. Once diagonalized, we will only keep a few eigenstates going forward - in the above example 9. Similarly, we keep 5 levels for the resonators, i.e., photon states n=0,1,...,4 are included in the following.\n", - "\n", - "Next, the two subsystems are declared as the two components of a joint Hilbert space:" - ] + "source": "Here, the `truncated_dim` parameters are important. For the fluxonium, with `cutoff` set to 110, the internal Hilbert space dimension is 110. Once diagonalized, we will only keep a few eigenstates going forward - in the above example 9. Similarly, we keep 5 levels for the resonator, i.e., photon states n=0,1,...,4 are included in the following.\n\nNext, the two subsystems are declared as the two components of a joint Hilbert space:" }, { "cell_type": "code", @@ -144,16 +140,7 @@ "name": "#%% md\n" } }, - "source": [ - "### Parameter sweep setup\n", - "We consider sweeping the external flux through the fluxonium loop. To create the necessary `ParameterSweep` object, we specify:\n", - "1. `param_name`: the name of the sweep parameter (below expressed in LaTeX format as the flux in units of the flux quantum)\n", - "2. `param_vals_by_name`: a dictionary that names our parameter and associates the array of flux values with it\n", - "3. `subsys_update_info` (optional): a dictionary listing the particular Hilbert space subsystems that change as each parameter (here the flux) is varied\n", - "4. `update_hilbertspace(param_val)`: a function that shows how a change in the sweep parameter affects the Hilbert space; here only the `.flux` attributed of the fluxonium qubit needs to be changed\n", - "\n", - "These ingredients all make it into the initialization of the `ParameterSweep` object. Once initialized, spectral data is generated and stored. Here, we additionally generate data for dispersive shifts and charge matrix elements." - ] + "source": "### Parameter sweep setup\nWe consider sweeping the external flux through the fluxonium loop. To create the necessary `ParameterSweep` object, we specify:\n1. `param_name`: the name of the sweep parameter (below expressed in LaTeX format as the flux in units of the flux quantum)\n2. `param_vals_by_name`: a dictionary that names our parameter and associates the array of flux values with it\n3. `subsys_update_info` (optional): a dictionary listing the particular Hilbert space subsystems that change as each parameter (here the flux) is varied\n4. `update_hilbertspace(param_val)`: a function that shows how a change in the sweep parameter affects the Hilbert space; here only the `.flux` attribute of the fluxonium qubit needs to be changed\n\nThese ingredients all make it into the initialization of the `ParameterSweep` object. Once initialized, spectral data is generated and stored. Here, we additionally generate data for dispersive shifts and charge matrix elements." }, { "cell_type": "code", diff --git a/docs/source/guide/hilbertspace/ipynb/branch_analysis.ipynb b/docs/source/guide/hilbertspace/ipynb/branch_analysis.ipynb index 003a8bc..7bc00b8 100644 --- a/docs/source/guide/hilbertspace/ipynb/branch_analysis.ipynb +++ b/docs/source/guide/hilbertspace/ipynb/branch_analysis.ipynb @@ -57,34 +57,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "## Basic Procedure of Branch Analysis\n", - "\n", - "Branch analysis associates the eigenstates with bare product state labels $(t, r)$, with $t$ and $r$ being the excitations in the transmon and resonator, respectively. It is performed in the following steps:\n", - "\n", - "1. We begin with identifying an eigenstate of the system with the largest overlap with a bare product state $|0,0\\rangle$ and label it by $|\\overline{0,0}\\rangle$.\n", - "2. For each bare label $(0, r)$, we find the corresponding eigenstate $|\\overline{0,r}\\rangle$ recursively, starting from $r=1$: \n", - " a) Put one resonator excitation on a labeled eigenstate $|\\overline{0,r-1}\\rangle$, which yields a new state $|\\psi_e\\rangle = a^\\dagger |\\overline{0,r-1}\\rangle$; \n", - " b) Among all the unlabeled eigenstates, identify the eigenstate $|\\psi_g\\rangle$ with the largest overlap with $|\\psi_e\\rangle$; \n", - " c) Label $|\\psi_g\\rangle$ by $|\\overline{0,r}\\rangle$; \n", - " d) Repeat the steps a)—c) until $r=N_\\text{res}-1$, where $N_\\text{res}$ is the dimension of the truncated Hilbert space of the resonator mode. This procedure yields a set of eigenstates $\\{|\\overline{0,r}\\rangle\\}_{n=0}^{N_\\text{res}-1}$ corresponding to the transmon initialized in the ground state, and such set is called a branch.\n", - "3. To find other branches with different transmon excitations, we repeat the step 2 for different initial eigenstates $|\\overline{1, 0}\\rangle$, $|\\overline{2, 0}\\rangle$, etc. These initial eigenstates are found as follows: \n", - " a) Put one transmon excitation on a given labeled eigenstate $|\\overline{t-1,0}\\rangle$. For a transmon (and any other non-linear modes), we define the excitation operator \n", - " $$T^+ = \\sum_{t=1}^{N_\\text{tmon}-1} |t\\rangle\\langle t-1| \\otimes I_\\text{res},$$ \n", - " where $N_\\text{tmon}$ is the dimension of the transmon's Hilbert space. The corresponding excited state is given by $|\\psi_e\\rangle = T^+ |\\overline{t-1,0}\\rangle$; \n", - " b) Among all the unlabeled eigenstates, identify the eigenstate $|\\psi_g\\rangle$ with the largest overlap with $|\\psi_e\\rangle$, which is labeled as $|\\overline{t,0}\\rangle$.\n", - "\n", - "The following figure summarizes the procedure for performing branch analysis for a system with $N_\\text{tmon}=3$ and $N_\\text{res}=4$: the numbers in front of each eigenstate show the order in which these states are labeled, and each arrow indicates how a labeled eigenstate is excited to help identify and label the next eigenstate.\n", - "
\n", - " \"Branch\n", - "
\n", - "\n", - "From the above figure, it is clear that the eigenstates are labeled in the [lexical order](https://en.wikipedia.org/wiki/Lexicographic_order#Cartesian_products) of the bare product labels—the latter index $r$ increases \"faster\" than the first index $t$ in the iteration, just like the order of the words in a dictionary.\n", - "\n", - "In the package, branch analysis can be performed as an option of the `generate_lookup()` function:" - ] + "source": "## Basic Procedure of Branch Analysis\n\nBranch analysis associates the eigenstates with bare product state labels $(t, r)$, with $t$ and $r$ being the excitations in the transmon and resonator, respectively. It is performed in the following steps:\n\n1. We begin with identifying an eigenstate of the system with the largest overlap with a bare product state $|0,0\\rangle$ and label it by $|\\overline{0,0}\\rangle$.\n2. For each bare label $(0, r)$, we find the corresponding eigenstate $|\\overline{0,r}\\rangle$ recursively, starting from $r=1$: \n a) Put one resonator excitation on a labeled eigenstate $|\\overline{0,r-1}\\rangle$, which yields a new state $|\\psi_e\\rangle = a^\\dagger |\\overline{0,r-1}\\rangle$; \n b) Among all the unlabeled eigenstates, identify the eigenstate $|\\psi_g\\rangle$ with the largest overlap with $|\\psi_e\\rangle$; \n c) Label $|\\psi_g\\rangle$ by $|\\overline{0,r}\\rangle$; \n d) Repeat the steps a)—c) until $r=N_\\text{res}-1$, where $N_\\text{res}$ is the dimension of the truncated Hilbert space of the resonator mode. This procedure yields a set of eigenstates $\\{|\\overline{0,r}\\rangle\\}_{r=0}^{N_\\text{res}-1}$ corresponding to the transmon initialized in the ground state, and such set is called a branch.\n3. To find other branches with different transmon excitations, we repeat the step 2 for different initial eigenstates $|\\overline{1, 0}\\rangle$, $|\\overline{2, 0}\\rangle$, etc. These initial eigenstates are found as follows: \n a) Put one transmon excitation on a given labeled eigenstate $|\\overline{t-1,0}\\rangle$. For a transmon (and any other non-linear modes), we define the excitation operator \n $$T^+ = \\sum_{t=1}^{N_\\text{tmon}-1} |t\\rangle\\langle t-1| \\otimes I_\\text{res},$$ \n where $N_\\text{tmon}$ is the dimension of the transmon's Hilbert space. The corresponding excited state is given by $|\\psi_e\\rangle = T^+ |\\overline{t-1,0}\\rangle$; \n b) Among all the unlabeled eigenstates, identify the eigenstate $|\\psi_g\\rangle$ with the largest overlap with $|\\psi_e\\rangle$, which is labeled as $|\\overline{t,0}\\rangle$.\n\nThe following figure summarizes the procedure for performing branch analysis for a system with $N_\\text{tmon}=3$ and $N_\\text{res}=4$: the numbers in front of each eigenstate show the order in which these states are labeled, and each arrow indicates how a labeled eigenstate is excited to help identify and label the next eigenstate.\n
\n \"Branch\n
\n\nFrom the above figure, it is clear that the eigenstates are labeled in the [lexical order](https://en.wikipedia.org/wiki/Lexicographic_order#Cartesian_products) of the bare product labels—the latter index $r$ increases \"faster\" than the first index $t$ in the iteration, just like the order of the words in a dictionary.\n\nIn the package, branch analysis can be performed as an option of the `generate_lookup()` function:" }, { "cell_type": "code", @@ -156,9 +129,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "## Label a Partial Set of Eigentates" - ] + "source": "## Label a Partial Set of Eigenstates" }, { "cell_type": "markdown", @@ -196,14 +167,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "\"BE\" ordering can be tuned by `subsys_priority` argument, and this controls where to put the next excitation to label the next eigenstate. For example, with `subsys_priority=[1, 0]`, the labeling follows follows the pattern shown in the figure. Different from the case using a default `subsys_priority`, the eigenstate labeled $(1,1)$ is identified by applying the transmon excitation operator to the previously labeled state $|\\overline{0,1}\\rangle$.\n", - "
\n", - " \"Branch\n", - "
\n" - ] + "source": "\"BE\" ordering can be tuned by `subsys_priority` argument, and this controls where to put the next excitation to label the next eigenstate. For example, with `subsys_priority=[1, 0]`, the labeling follows the pattern shown in the figure. Different from the case using a default `subsys_priority`, the eigenstate labeled $(1,1)$ is identified by applying the transmon excitation operator to the previously labeled state $|\\overline{0,1}\\rangle$.\n
\n \"Branch\n
\n" } ], "metadata": { @@ -227,4 +191,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/docs/source/guide/hilbertspace/ipynb/hilbertspace.ipynb b/docs/source/guide/hilbertspace/ipynb/hilbertspace.ipynb index 50e7719..22df1ef 100644 --- a/docs/source/guide/hilbertspace/ipynb/hilbertspace.ipynb +++ b/docs/source/guide/hilbertspace/ipynb/hilbertspace.ipynb @@ -317,25 +317,7 @@ "name": "#%% md\n" } }, - "source": [ - "`expr` is a string used to define the interaction as a Python expression. It should use variables that are already defined globally, and operators given by the names provided in `op1`, `op2`, `op3`, etc. When using `expr`, each argument `op1`, `op2`, ... should be a tuple of the form
\n", - "`(, )` or
\n", - "`(, , )`.\n", - "\n", - "Beyond built-in Python functions and operations, acceptable functions to use in `expr` are:\n", - "\n", - "| Function | Function translation |\n", - "|-----------------------|---------------------------------|\n", - "| `'cos'` | `'Qobj.cosm'` |\n", - "| `'sin'` | `'Qobj.sinm'` |\n", - "| `'exp'` | `'Qobj.expm'` |\n", - "| `'sqrt'` | `'Qobj.sqrtm'` |\n", - "\n", - "\n", - "### Option 3: *Qobj* interface\n", - "\n", - "Finally `add_interaction` can also been used to directly add a `Qobj` object that has already been properly identity wrapped:" - ] + "source": "`expr` is a string used to define the interaction as a Python expression. It should use variables that are already defined globally, and operators given by the names provided in `op1`, `op2`, `op3`, etc. When using `expr`, each argument `op1`, `op2`, ... should be a tuple of the form
\n`(, )` or
\n`(, , )`.\n\nBeyond built-in Python functions and operations, acceptable functions to use in `expr` are:\n\n| Function | Function translation |\n|-----------------------|---------------------------------|\n| `'cos'` | `'Qobj.cosm'` |\n| `'sin'` | `'Qobj.sinm'` |\n| `'exp'` | `'Qobj.expm'` |\n| `'sqrt'` | `'Qobj.sqrtm'` |\n\n\n### Option 3: *Qobj* interface\n\nFinally, `add_interaction` can also be used to directly add a `Qobj` object that has already been properly identity wrapped:" }, { "cell_type": "code", @@ -379,11 +361,7 @@ "name": "#%% md\n" } }, - "source": [ - "## Obtaining the Hamiltonian\n", - "\n", - "With the interactions specified, the full Hamiltonian of the coupled system can be obtained via the method `.hamiltonian()`. This conveniently results in a `qubit.Qobj` operator:" - ] + "source": "## Obtaining the Hamiltonian\n\nWith the interactions specified, the full Hamiltonian of the coupled system can be obtained via the method `.hamiltonian()`. This conveniently results in a `qutip.Qobj` operator:" }, { "cell_type": "code", @@ -560,33 +538,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "Internally, the lookup table is generated entry by entry through a particular order, and we provide the user the following three ordering schemes:\n", - "\n", - "1. **Ordered by Dressed Energy (DE, default)**: traverse the dressed eigenstates, in ascending order of their eigenenergies. For each of the eigenstates, find the corresponding bare state with the maximum overlap. Note:\n", - " * Once a bare label is assigned to a dressed state, it won't be assigned to another dressed state. \n", - " * Eigenstates that do not have a bare state with overlap exceeding `scqubits.settings.OVERLAP_THRESHOLD` are not assigned any bare label, which ensures that labeled eigenstates are sufficiently close to the corresponding bare states.\n", - "2. **Branch analysis with lexical ordering (LX)**: traverse the bare product state labels in the [lexical order](https://en.wikipedia.org/wiki/Lexicographic_order#Cartesian_products) and perform the branch analysis introduced in [Dumas2024]. This is done as follows:\n", - " ```python\n", - " hilbertspace.generate_lookup(\n", - " ordering='LX',\n", - " subsys_priority=[0, 1, 2]\n", - " )\n", - " ```\n", - " The `subsys_priority` argument is optional. It is a permutation of the subsystem indices. If it is provided, lexical ordering is performed on the bare labels of permuted subsystems. Besides specifying the ordering, `subsys_priority` also determines which subsystem is to be excited in each step of the traversal. Specifically, a \"branch\" is defined as a series of eigenstates formed by putting excitations into the last subsystem in the list. \n", - "3. **Partial branch analysis, with Bare Energy (BE) ordering**: traverse the bare states in the order of their energy without coupling and perform branch analysis. This is particularly useful when the Hilbert space is too large and only a few low-lying bare states need to be labeled (specifies by `BEs_count`). This is done as follows:\n", - " ```python\n", - " hilbertspace.generate_lookup(\n", - " ordering='BE',\n", - " subsys_priority=[0, 1, 2],\n", - " BEs_count=10,\n", - " )\n", - " ```\n", - " The users can provide `subsys_priority` argument to determine which subsystem is to be excited during each step of the traversal, while it no longer specifies the ordering.\n", - "\n", - "For more details on the branch analysis, please refer to [Eigenstate Labeling by Branch Analysis](./branch_analysis.ipynb).\n", - "Note that these three schemes may not produce the same labeling and the users should choose the one that best suits their needs." - ] + "source": "Internally, the lookup table is generated entry by entry through a particular order, and we provide the user the following three ordering schemes:\n\n1. **Ordered by Dressed Energy (DE, default)**: traverse the dressed eigenstates, in ascending order of their eigenenergies. For each of the eigenstates, find the corresponding bare state with the maximum overlap. Note:\n * Once a bare label is assigned to a dressed state, it won't be assigned to another dressed state. \n * Eigenstates that do not have a bare state with overlap exceeding `scqubits.settings.OVERLAP_THRESHOLD` are not assigned any bare label, which ensures that labeled eigenstates are sufficiently close to the corresponding bare states.\n2. **Branch analysis with lexical ordering (LX)**: traverse the bare product state labels in the [lexical order](https://en.wikipedia.org/wiki/Lexicographic_order#Cartesian_products) and perform the branch analysis introduced in [Dumas2024]. This is done as follows:\n ```python\n hilbertspace.generate_lookup(\n ordering='LX',\n subsys_priority=[0, 1, 2]\n )\n ```\n The `subsys_priority` argument is optional. It is a permutation of the subsystem indices. If it is provided, lexical ordering is performed on the bare labels of permuted subsystems. Besides specifying the ordering, `subsys_priority` also determines which subsystem is to be excited in each step of the traversal. Specifically, a \"branch\" is defined as a series of eigenstates formed by putting excitations into the last subsystem in the list. \n3. **Partial branch analysis, with Bare Energy (BE) ordering**: traverse the bare states in the order of their energy without coupling and perform branch analysis. This is particularly useful when the Hilbert space is too large and only a few low-lying bare states need to be labeled (specified by `BEs_count`). This is done as follows:\n ```python\n hilbertspace.generate_lookup(\n ordering='BE',\n subsys_priority=[0, 1, 2],\n BEs_count=10,\n )\n ```\n The users can provide `subsys_priority` argument to determine which subsystem is to be excited during each step of the traversal, while it no longer specifies the ordering.\n\nFor more details on the branch analysis, please refer to [Eigenstate Labeling by Branch Analysis](./branch_analysis.ipynb).\nNote that these three schemes may not produce the same labeling and the users should choose the one that best suits their needs." }, { "cell_type": "markdown", @@ -1141,4 +1093,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/docs/source/guide/noise/dephasing.rst b/docs/source/guide/noise/dephasing.rst index eed56a7..e1b9d8e 100644 --- a/docs/source/guide/noise/dephasing.rst +++ b/docs/source/guide/noise/dephasing.rst @@ -42,7 +42,7 @@ with the following parameters: The frequency derivatives in the above expressions are calculated from matrix elements of :math:`\partial_\lambda H`. The `Method Parameter Name` column in the above table describes the argument names that can be passed to various 1/f noise methods (see below) when one wants to use custom parameter values. -Currently, at sweet spots, where :math:`\partial_\lambda H` is zero, scqubits returns a ``np.nan`` value as the dephasing time. Higher order corrections will be implemented in the future. +Currently, at sweet spots, where :math:`\partial_\lambda H` is zero, scqubits returns a ``np.nan`` value as the dephasing time. Higher-order corrections will be implemented in the future. The general-purpose scqubits method for calculating 1/f dephasing times due to an arbitrary noise channel is given by ``tphi_1_over_f()``. Depending on the qubit of interest, more specific methods for the different kinds diff --git a/docs/source/guide/noise/depolarization.rst b/docs/source/guide/noise/depolarization.rst index 359575e..0878656 100644 --- a/docs/source/guide/noise/depolarization.rst +++ b/docs/source/guide/noise/depolarization.rst @@ -15,22 +15,22 @@ The rate of a transition from state :math:`i` to state :math:`j` can be expresse \Gamma_{ij} = \frac{1}{\hbar^2} |\langle i| B_{\lambda} |j \rangle|^2 S(\omega_{ij}), where :math:`B_\lambda` is the noise operator, and :math:`S(\omega_{ij})` the spectral density function evaluated at -the angular frequency associated with the transition frequency, :math:`\omega_{ij} = \omega_{j} - \omega_{i}`. -:math:`\omega_{ij}` is positive in the case of decay (the qubit emits energy to the bath), and negative in case of +the angular frequency associated with the transition frequency, :math:`\omega_{ij} = \omega_{i} - \omega_{j}`. +:math:`\omega_{ij}` is positive in the case of decay (the qubit emits energy to the bath), and negative in the case of excitations (the qubit absorbs energy from the bath). Unless stated otherwise, it is assumed that the depolarizing noise channels satisfy detailed balance. This implies .. math:: - \frac{S(\omega)}{S(-\omega)} = \exp{\frac{\hbar \omega}{k_B T}}, + \frac{S(\omega)}{S(-\omega)} = \exp\left(\frac{\hbar \omega}{k_B T}\right), where :math:`T` is the bath temperature, and :math:`k_B` Boltzmann's constant. .. note:: - By default all :math:`t_1` methods estimate the coherence depolarization times from the sum of the upward and downward rates. + By default, all :math:`T_1` methods estimate the coherence depolarization times from the sum of the upward and downward rates. This behavior is controlled by the argument `total`, which can be modified by the user. For example, setting `total=False` will calculate only a single-directional transition rate from the state indexed `i` to the state indexed `j` (both of which can also be changed by the user through providing their values as arguments) @@ -40,7 +40,7 @@ Capacitive noise ----------------------- +-------------------+--------------------+ -| Noise operator | ``t1_capacitive`` | +| Method name | ``t1_capacitive`` | +===================+====================+ | :math:`B_\lambda` | :math:`2e \hat{n}` | +-------------------+--------------------+ @@ -80,7 +80,7 @@ are ``i``, ``j`` and ``total``. Their properties are described below. | | | time (or rate) corresponds to a relaxation or excitation process, respectively. | | | | | | | | If ``total=True`` then both transition rates from ``j`` to ``i`` | -| | | and ``i`` to ``j`` are combined to give total effective depolarization | +| | | and ``i`` to ``j`` are combined to give a total effective depolarization | | | | time (or rate). | +----------------+---------------+----------------------------------------------------------------------------------+ @@ -112,7 +112,7 @@ Inductive noise ----------------------- +-------------------+----------------------------------------+ -| Noise operator | ``t1_inductive`` | +| Method name | ``t1_inductive`` | +===================+========================================+ | :math:`B_\lambda` | :math:`\frac{\Phi_0}{2\pi} \hat{\phi}` | +-------------------+----------------------------------------+ @@ -156,7 +156,7 @@ are ``i``, ``j`` and ``total``. Their properties are described below. | | | time (or rate) corresponds to a relaxation or excitation process, respectively. | | | | | | | | If ``total=True`` then both transition rates from ``j`` to ``i`` | -| | | and ``i`` to ``j`` are combined to give total effective depolarization | +| | | and ``i`` to ``j`` are combined to give a total effective depolarization | | | | time (or rate). | +----------------+---------------+----------------------------------------------------------------------------------+ @@ -190,7 +190,7 @@ Charge-coupled impedance noise ------------------------------ +--------------------------------------------+-----------------------------------------+ -| Noise operator | ``t1_charge_impedance`` | +| Method name | ``t1_charge_impedance`` | +--------------------------------------------+-----------------------------------------+ | :math:`B_\lambda` | :math:`2e \hat{n}` | +--------------------------------------------+-----------------------------------------+ @@ -230,7 +230,7 @@ are ``i``, ``j`` and ``total``. Their properties are described below. | | | time (or rate) corresponds to a relaxation or excitation process, respectively. | | | | | | | | If ``total=True`` then both transition rates from ``j`` to ``i`` | -| | | and ``i`` to ``j`` are combined to give total effective depolarization | +| | | and ``i`` to ``j`` are combined to give a total effective depolarization | | | | time (or rate). | +----------------+---------------+----------------------------------------------------------------------------------+ @@ -262,7 +262,7 @@ Flux-bias line noise ------------------------- +-------------------+--------------------------------------------------+ -| Noise operator | ``t1_flux_bias_line`` | +| Method name | ``t1_flux_bias_line`` | +===================+==================================================+ | :math:`B_\lambda` | :math:`\frac{\partial \hat{H}}{\partial \Phi_x}` | +-------------------+--------------------------------------------------+ @@ -298,7 +298,7 @@ are ``i``, ``j`` and ``total``. Their properties are described below. | | | time (or rate) corresponds to a relaxation or excitation process, respectively. | | | | | | | | If ``total=True`` then both transition rates from ``j`` to ``i`` | -| | | and ``i`` to ``j`` are combined to give total effective depolarization | +| | | and ``i`` to ``j`` are combined to give a total effective depolarization | | | | time (or rate). | +----------------+---------------+----------------------------------------------------------------------------------+ @@ -326,13 +326,13 @@ Other parameters that could be used for further customization are: +----------------+---------------+---------------------------------------------------------------------+ -References: [Koch2007]_, [Groszkowski2018]_, +References: [Koch2007]_, [Groszkowski2018]_ Quasiparticle-tunneling noise ---------------------------------- +-------------------+--------------------------------------------------+ -| Noise operator | ``t1_quasiparticle_tunneling`` | +| Method name | ``t1_quasiparticle_tunneling`` | +===================+==================================================+ | :math:`B_\lambda` | :math:`\sin(\hat{\phi}/2)` (see note ** below) | +-------------------+--------------------------------------------------+ @@ -343,10 +343,7 @@ Noise due to quasiparticle tunneling. The assumed spectral density reads S(\omega) = \hbar \omega {\rm Re} Y_{\rm qp}(\omega) \left(1 + \coth \frac{\hbar |\omega|}{2 k_B T} \right) -where :math:`L_J` (with :math:`E_J = \phi_0^2/L_J` ) is the relevant inductance or superinductance, and :math:`Q_{\rm ind}` the corresponding inductive -quality factor. The default value of the frequency-dependent quality factor is assumed to be - -The default real part of admittance is assumed to be +where :math:`Y_{\rm qp}(\omega)` is the admittance associated with quasiparticle tunneling. The default real part of the admittance is assumed to be .. math:: @@ -354,6 +351,8 @@ The default real part of admittance is assumed to be \left(\frac{2 \Delta}{\hbar \omega} \right)^{3/2} x_{\rm qp} \ K_{0} \left( \frac{\hbar |\omega|}{2 k_B T} \right) \sinh \left( \frac{\hbar \omega }{2 k_B T} \right). +where :math:`R_k = h/e^2` is the resistance quantum, :math:`\Delta` the superconducting gap, :math:`x_{\rm qp}` the quasiparticle density, and :math:`K_0` a modified Bessel function of the second kind. + ** This form assumes that the external flux is grouped with the inductive term of the Hamiltonian. In qubits where the flux is grouped with the Josephson term, the noise operator is appropriately transformed. To see a detailed signature of this method, see the API description of qubits that support this particular noise channel. These are @@ -379,7 +378,7 @@ are ``i``, ``j`` and ``total``. Their properties are described below. | | | time (or rate) corresponds to a relaxation or excitation process, respectively. | | | | | | | | If ``total=True`` then both transition rates from ``j`` to ``i`` | -| | | and ``i`` to ``j`` are combined to give total effective depolarization | +| | | and ``i`` to ``j`` are combined to give a total effective depolarization | | | | time (or rate). | +----------------+---------------+----------------------------------------------------------------------------------+ @@ -395,7 +394,7 @@ Other parameters that could be used for further customization are: +----------------+-------------------------------------+------------------------------------------------+ | Parameter name | Default value | Description | +================+=====================================+================================================+ -| Y_qp | :math:`Y_{\rm qp}` | Complex admittance (:math:`\Omega`) | +| Y_qp | :math:`Y_{\rm qp}` | Complex admittance (:math:`\Omega^{-1}`) | | | | | | | | Can be function of :math:`\omega`, or a number | +----------------+-------------------------------------+------------------------------------------------+ @@ -415,7 +414,7 @@ User-defined noise ----------------------- +--------------------------------------------+-----------------------------------------+ -| Noise operator | ``t1`` | +| Method name | ``t1`` | +--------------------------------------------+-----------------------------------------+ | :math:`B_\lambda` | user defined | +--------------------------------------------+-----------------------------------------+ diff --git a/docs/source/guide/noise/effective_noise.rst b/docs/source/guide/noise/effective_noise.rst index 8388770..fcb3bda 100644 --- a/docs/source/guide/noise/effective_noise.rst +++ b/docs/source/guide/noise/effective_noise.rst @@ -23,13 +23,13 @@ as well as depolarization channels. This total :math:`T_{2}` time is defined as where :math:`k` (:math:`j`) runs over all relevant pure-dephasing (depolarization) channels. -scqubits enables the evaluation of these effective coherence times. By default, the noise channels that are included in the calculation, -can be shown using the ``effective_noise_channels`` method for each qubit. Note that this list may not include all the noise -channels that can actually be calculated for any given qubit, to see a list of those, the ``supported_noise_channels`` method -could be used. Users can also explicitly specify what noise processes should be included in effective noise calculations. +scqubits enables the evaluation of these effective coherence times. By default, the noise channels that are included in the calculation +can be shown using the ``effective_noise_channels`` method for each qubit. Note that this list may not include all the noise +channels that can actually be calculated for a given qubit. To see a list of those, the ``supported_noise_channels`` method +can be used. Users can also explicitly specify what noise processes should be included in effective noise calculations. -Calculating :math:`T_1` and :math:`T_2` can be done via the methods ``t1_effective`` and ``t2_effective`` respectively. +Calculating :math:`T_1` and :math:`T_2` can be done via the methods ``t1_effective`` and ``t2_effective``, respectively. For more information on the method signatures, see the :ref:`API documentation ` diff --git a/docs/source/guide/noise/ipynb/visualization.ipynb b/docs/source/guide/noise/ipynb/visualization.ipynb index 2326c2b..8aff241 100644 --- a/docs/source/guide/noise/ipynb/visualization.ipynb +++ b/docs/source/guide/noise/ipynb/visualization.ipynb @@ -172,9 +172,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "As an example of some of the non-default options, we consider a $T_1$ noise process due to direct coupling of the qubit to a charge line. The effects of such a noise channel can be calculated using a method called ``t1_charge_impedance``. For example, suppose we wish the calculate the rate for transitions between the 3rd and 1st energy levels, assuming a standard transmission line at a temperature of T=100mK. To obtain the resulting rate, we execute: " - ] + "source": "As an example of some of the non-default options, we consider a $T_1$ noise process due to direct coupling of the qubit to a charge line. The effects of such a noise channel can be calculated using a method called ``t1_charge_impedance``. For example, suppose we wish to calculate the rate for transitions between the 3rd and 1st energy levels, assuming a standard transmission line at a temperature of T=100mK. To obtain the resulting rate, we execute: " }, { "cell_type": "code", @@ -204,9 +202,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "The option ``total=False`` in the above code signals that only the rate from level 3 to level 1 should be calculated, without inclusion of the upward (excitation) rate. The contribution from excitation processes is included by passing the option ``total=True`` (which is also the default for all the methods that consider $T_1$ processes). The implication of the default ``total=True`` option, naturally implies that passing state-index arguments $i=3$ together with $j=1$ results in a $T_1$ coherence time equivalent to passing in $i=1$ with $j=3$. " - ] + "source": "The option ``total=False`` in the above code signals that only the rate from level 3 to level 1 should be calculated, without inclusion of the upward (excitation) rate. The contribution from excitation processes is included by passing the option ``total=True`` (which is also the default for all the methods that consider $T_1$ processes). The default ``total=True`` option naturally implies that passing state-index arguments $i=3$ together with $j=1$ results in a $T_1$ coherence time equivalent to passing in $i=1$ with $j=3$. " }, { "cell_type": "markdown", @@ -5516,9 +5512,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "For additional control, we may choose to calculate coherences with non-default options for all the noise channels we want to plot. This can be done by passing a `common_noise_options` argument to `plot_coherence_vs_paramvals`, which contains a dictionary of option/value pairs. We can also choose different noise-specific options or each noise channel. This is possible by supplying the `noise_channels` argument with tuples containing (1) a noise-channel name, and (2) a dictionary with options that are internally used to calculate the noise. In the example below, we set a non-default temperature for all the provided noise channels to 100 $mK$, but also choose a non-default energy levels 3 and 2 for the ``t1_capacitive`` noise channel calculation (instead of default 1 and 0).\n" - ] + "source": "For additional control, we may choose to calculate coherences with non-default options for all the noise channels we want to plot. This can be done by passing a `common_noise_options` argument to `plot_coherence_vs_paramvals`, which contains a dictionary of option/value pairs. We can also choose different noise-specific options for each noise channel. This is possible by supplying the `noise_channels` argument with tuples containing (1) a noise-channel name, and (2) a dictionary with options that are internally used to calculate the noise. In the example below, we set a non-default temperature for all the provided noise channels to 100 $mK$, but also choose non-default energy levels 3 and 2 for the ``t1_capacitive`` noise channel calculation (instead of default 1 and 0).\n" }, { "cell_type": "code", @@ -11879,4 +11873,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/namedslots.ipynb b/docs/source/guide/parametersweep/ipynb/namedslots.ipynb index c4f1db5..93aeb35 100644 --- a/docs/source/guide/parametersweep/ipynb/namedslots.ipynb +++ b/docs/source/guide/parametersweep/ipynb/namedslots.ipynb @@ -285,11 +285,7 @@ "name": "#%% md\n" } }, - "source": [ - "There are two names axes, one for the flux parameter, one for the offset charge parameter. The last (unnamed) axis is for the number of eigenvalues at each point (the default is 20).\n", - "\n", - "The `param_info` entries are kept up-to-date upon slicing an `NamedSlotsNdarray`:" - ] + "source": "There are two named axes, one for the flux parameter, one for the offset charge parameter. The last (unnamed) axis is for the number of eigenvalues at each point (the default is 20).\n\nThe `param_info` entries are kept up-to-date upon slicing an `NamedSlotsNdarray`:" }, { "cell_type": "code", @@ -3849,4 +3845,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/paramsweep2-customsweep.ipynb b/docs/source/guide/parametersweep/ipynb/paramsweep2-customsweep.ipynb index c5cc922..b1915fe 100644 --- a/docs/source/guide/parametersweep/ipynb/paramsweep2-customsweep.ipynb +++ b/docs/source/guide/parametersweep/ipynb/paramsweep2-customsweep.ipynb @@ -220,9 +220,7 @@ "name": "#%% md\n" } }, - "source": [ - "The `add_sweep` method takes the callable function one argument, and the name under which the scan should be stored as the second argument:" - ] + "source": "The `add_sweep` method takes the callable function as the first argument, and the name under which the scan should be stored as the second argument:" }, { "cell_type": "code", @@ -1073,4 +1071,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/paramsweep2-data.ipynb b/docs/source/guide/parametersweep/ipynb/paramsweep2-data.ipynb index 8daf254..426a020 100644 --- a/docs/source/guide/parametersweep/ipynb/paramsweep2-data.ipynb +++ b/docs/source/guide/parametersweep/ipynb/paramsweep2-data.ipynb @@ -178,29 +178,7 @@ "name": "#%% md\n" } }, - "source": [ - "## ParameterSweep data\n", - "\n", - "Much of the computed data that is stored and immediately retrievable after this sweep by accessing the `ParameterSweep` object like a dictionary with the following string keys:\n", - "\n", - "\n", - "+-------------------------------+------------------------------------------------------------------------+\n", - "| string keyword | data |\n", - "+===============================+========================================================================+\n", - "| `\"evals\"`, `\"evecs\"` | dressed eigenenergies and eigenstates as `NamedSlotsNdarray` |\n", - "| | eigenstates are decomposed in the bare product-state basis of the |\n", - "| | non-interacting subsystems' eigenbases |\n", - "+-------------------------------+------------------------------------------------------------------------+\n", - "| `\"bare_evals\"`, `\"bare_evecs\"`| eigenenergies and eigenstates for each subsystem as `NamedSlotsNdarray`| \n", - "| | The arrays first axis (name: `\"subsys\"` enumerates the subsystems |\n", - "+-------------------------------+------------------------------------------------------------------------+\n", - "| `\"lamb\"`, `\"chi\"`, `\"kerr\"` | dispersive energy coefficients as `NamedSlotsNdarray` |\n", - "| | (see description below) |\n", - "+-------------------------------+------------------------------------------------------------------------+\n", - "\n", - "\n", - "Data are returned as a `NamedSlotsNdarray` which behaves like a regular numpy array:" - ] + "source": "## ParameterSweep data\n\nMuch of the computed data is stored and immediately retrievable after this sweep by accessing the `ParameterSweep` object like a dictionary with the following string keys:\n\n\n+-------------------------------+------------------------------------------------------------------------+\n| string keyword | data |\n+===============================+========================================================================+\n| `\"evals\"`, `\"evecs\"` | dressed eigenenergies and eigenstates as `NamedSlotsNdarray` |\n| | eigenstates are decomposed in the bare product-state basis of the |\n| | non-interacting subsystems' eigenbases |\n+-------------------------------+------------------------------------------------------------------------+\n| `\"bare_evals\"`, `\"bare_evecs\"`| eigenenergies and eigenstates for each subsystem as `NamedSlotsNdarray`|\n| | The array's first axis (name: `\"subsys\"`) enumerates the subsystems |\n+-------------------------------+------------------------------------------------------------------------+\n| `\"lamb\"`, `\"chi\"`, `\"kerr\"` | dispersive energy coefficients as `NamedSlotsNdarray` |\n| | (see description below) |\n+-------------------------------+------------------------------------------------------------------------+\n\n\nData are returned as a `NamedSlotsNdarray` which behaves like a regular numpy array:" }, { "cell_type": "code", @@ -331,4 +309,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/paramsweep2-deepcopy.ipynb b/docs/source/guide/parametersweep/ipynb/paramsweep2-deepcopy.ipynb index 02dbd73..27a487e 100644 --- a/docs/source/guide/parametersweep/ipynb/paramsweep2-deepcopy.ipynb +++ b/docs/source/guide/parametersweep/ipynb/paramsweep2-deepcopy.ipynb @@ -243,32 +243,7 @@ "name": "#%% md\n" } }, - "source": [ - "This way of updating is of particular interest when using the `deepcopy` option\n", - "discussed next.\n", - "\n", - "#### State after the sweep and using `deepcopy`\n", - "\n", - "By default, the `HilbertSpace` object and its constituents will be left by `ParameterSweep` in a state reached with the last evaluation involved in the sweep. (When multiprocessing, this final state may not be easy to predict.)\n", - "\n", - "Alternatively, the `deepcopy` option can be used to\n", - "1. disconnect all global ``HilbertSpace` constituents from the sweep,and\n", - "2. restore the `HilbertSpace` object stored internally with the `ParameterSweep` to the parameters prior to the sweep.\n", - "\n", - "Without use of `deepcopy`, there is a good chance that, for example, the offset\n", - "charge of `tmon2` is now different than prior to the sweep.\n", - "For `deepcopy=True` the global instances are disconnected from the sweep\n", - "and remain untouched. The `HilbertSpace` object interior to `sweep` is restored to its\n", - "original state, but remains a copy separate from the `HilbertSpace` object used to\n", - "initialize `ParameterSweep`.\n", - "\n", - ".. note::\n", - " When using `deepcopy=True`, the original state of `HilbertSpace` objects\n", - " is restored. With `deepcopy` enabled,\n", - " `update_hilbertspace` **must** be based on manipulating the objects interior to\n", - " `ParameterSweep`. (Changing the global objects will have no effect in this case.)\n", - "\n" - ] + "source": "This way of updating is of particular interest when using the `deepcopy` option\ndiscussed next.\n\n#### State after the sweep and using `deepcopy`\n\nBy default, the `HilbertSpace` object and its constituents will be left by `ParameterSweep` in a state reached with the last evaluation involved in the sweep. (When multiprocessing, this final state may not be easy to predict.)\n\nAlternatively, the `deepcopy` option can be used to\n1. disconnect all global `HilbertSpace` constituents from the sweep, and\n2. restore the `HilbertSpace` object stored internally with the `ParameterSweep` to the parameters prior to the sweep.\n\nWithout use of `deepcopy`, there is a good chance that, for example, the offset\ncharge of `tmon2` is now different than prior to the sweep.\nFor `deepcopy=True` the global instances are disconnected from the sweep\nand remain untouched. The `HilbertSpace` object interior to `sweep` is restored to its\noriginal state, but remains a copy separate from the `HilbertSpace` object used to\ninitialize `ParameterSweep`.\n\n.. note::\n When using `deepcopy=True`, the original state of `HilbertSpace` objects\n is restored. With `deepcopy` enabled,\n `update_hilbertspace` **must** be based on manipulating the objects interior to\n `ParameterSweep`. (Changing the global objects will have no effect in this case.)\n" } ], "metadata": { @@ -335,4 +310,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/paramsweep2-dispersive.ipynb b/docs/source/guide/parametersweep/ipynb/paramsweep2-dispersive.ipynb index 3f39a61..3e5b1c8 100644 --- a/docs/source/guide/parametersweep/ipynb/paramsweep2-dispersive.ipynb +++ b/docs/source/guide/parametersweep/ipynb/paramsweep2-dispersive.ipynb @@ -4668,13 +4668,7 @@ "name": "#%% md\n" } }, - "source": [ - "\n", - ".. note::\n", - " Since dressed eigenenergies are used to compute these coefficients, results will not precisely agree with a \n", - " purely perturbative calculations stopping at finite order. For instance, the coefficients calculated here will\n", - " not always show the divergences typical for the breakdown of perturbation theory at avoided crossings. " - ] + "source": "\n.. note::\n Since dressed eigenenergies are used to compute these coefficients, results will not precisely agree with a \n purely perturbative calculation stopping at finite order. For instance, the coefficients calculated here will\n not always show the divergences typical for the breakdown of perturbation theory at avoided crossings. " }, { "cell_type": "markdown", @@ -4683,66 +4677,7 @@ "name": "#%% md\n" } }, - "source": [ - "#### Theoretical background, definition of dispersive quantities\n", - "Consider a system of harmonic modes ($s=0,1,\\ldots$) and qubit modes ($q=0,1,\\ldots$) coupled to each other,\n", - " \n", - "**Hamiltonian**\n", - "\\begin{equation}\n", - "H = \\sum_s \\omega_s a_s^\\dagger a_s + \\sum_{q,l} \\epsilon^q_l |l_q\\rangle\\langle l_q| \n", - "+ \\sum_{s\\not=s'} g^{ss'}(a_s + a_s^\\dagger)(a_{s'} + a_{s'}^\\dagger)\n", - "+ \\sum_{s,q,l} g^{sq}_{ll'} (a_s + a_s^\\dagger)|l_q\\rangle\\langle l_q'|\n", - "+ \\sum_{q\\not=q'}\\sum_{lm,l'm'}g^{qq'}_{lm,l'm'}|l_q l'_{q'}\\rangle\\langle m_q m'_{q'}|\n", - "\\end{equation}\n", - "\n", - " \n", - "If this system is fully dispersive, then the leading terms in the effective Hamiltonian, as obtained by a Schrieffer-Wolff transformation, can be written as:
\n", - "\n", - "**Dispersive Hamiltonian**\n", - "\\begin{align}\n", - "H_\\text{eff}&= E_0 + \\underbrace{\\sum_s (\\omega_s + \\Delta\\omega_s) a_s^\\dagger a_s + \\sum_{q,l>0} (\\bar{\\epsilon}^q_l + \\Delta \\bar{\\epsilon}^q_l)|l_q\\rangle\\langle l_q|}_\\text{bare modes plus Lamb shifts}\n", - "+\\underbrace{\\sum_{s;q,l>0}\\bar{\\chi}^{sq}_l a_s^\\dagger a_s |l_q\\rangle\\langle l_q|}_\\text{ac Stark shifts}\n", - "+\\underbrace{\\sum_{s> s'} K_{ss'} a_s^\\dagger a_s a_{s'}^\\dagger a_{s'}}_\\text{cross-Kerr}\\\\\n", - "&\\quad +\\underbrace{\\sum_{s} K_{s} a_s^\\dagger a_{s}^\\dagger a_{s} a_{s}}_\\text{self-Kerr}\n", - "+\\underbrace{\\sum_{ql \\not= q'l'} \\Lambda^{qq'}_{ll'} |l_q,l'_{q'}\\rangle \\langle l_q, l'_{q'}|}_\\text{interaction among anharmonic modes}\n", - "\\end{align}\n", - "\n", - "Here, the energy coefficients are:\n", - "\\begin{align}\n", - "&E_0 =\\textstyle \\sum_q \\epsilon^q_0 && \\text{(global energy offset)}\\\\\n", - "&\\Delta\\omega_s && \\text{(harmonic mode frequency corrections)}\\\\\n", - "&\\bar{\\epsilon}^q_l = \\epsilon^q_l - \\epsilon^q && \\text{(anharmonic mode energies relative to respective ground state energy)}\\\\\n", - "&\\Delta\\bar{\\epsilon}^q_l && \\text{(Lamb shifts)}\\\\\n", - "&\\bar{\\chi}^{sq}_l = \\chi^{sq}_l - \\chi^{sq}_0 && \\text{(ac Stark shift for modes $s$ and $q$, relative to the $q=0$ state)}\\\\\n", - "&K_{ss'}, K_s && \\text{(cross- and self-Kerr)}\\\\\n", - "&\\Lambda^{qq'}_{ll'} && \\text{(\"Kerr\" among qubit modes)}\n", - "\\end{align}\n", - "\n", - "#### Evaluation of energy coefficients\n", - "The various energy coefficients are evaluated by forming appropriate energy differences of the dressed eigenenergies. Denote the latter as\n", - "\n", - "\\begin{equation} E(n_1,n_2,\\ldots;l_1,l_2,\\ldots) = E(\\vec{n},\\vec{l})\\end{equation}\n", - "\n", - "With this the dispersive energy coefficients are:\n", - "\n", - "**Lamb shift, anharmonic mode**
\n", - "$\\Delta\\bar{\\epsilon}^q_l = E(\\vec{o},l\\hat{e}_q) - E(\\vec{o},\\vec{o}) - \\bar{\\epsilon}^q_l$ \n", - "\n", - "**Lamb shift, harmonic mode**
\n", - "$\\Delta\\omega_s = E(\\hat{e}_s,\\vec{o}) - E(\\vec{o},\\vec{o}) - \\omega_s$ \n", - "\n", - "**AC Stark shift**
\n", - "$\\bar{\\chi}^{sq}_l = E(\\hat{e}_s,l\\hat{e}_q) -(\\epsilon^q_l + \\Delta\\epsilon^q_l) - (\\omega_s + \\Delta\\omega_s) - E(\\vec{o},\\vec{o})$\n", - "\n", - "**self-Kerr**
\n", - "$K_{s} = [E(2\\hat{e}_s,\\vec{o}) - E(\\vec{o},\\vec{o}) - 2(\\omega_s + \\Delta\\omega_s)]/2$\n", - "\n", - "**cross-Kerr**
\n", - "$K_{ss'} = E(\\hat{e}_s + \\hat{e}_{s'}) - E(\\vec{o},\\vec{o}) - (\\omega_s + \\Delta\\omega_s) - (\\omega_{s'} + \\Delta\\omega_{s'})\\qquad (s\\not=s')$\n", - "\n", - "**anharmonic \"Kerr\"**
\n", - "$\\Lambda^{qq'}_{ll'} = E(\\vec{o}, l\\hat{e}_q + l'\\hat{e}_{q'},\\vec{o}) - E(\\vec{o},\\vec{o}) - (\\bar{\\epsilon}^q_l + \\Delta\\bar{\\epsilon}^q_l) - (\\bar{\\epsilon}^{q'}_{l'} + \\Delta\\bar{\\epsilon}^{q'}_{l'})\\qquad (s\\not=s')$\n" - ] + "source": "#### Theoretical background, definition of dispersive quantities\nConsider a system of harmonic modes ($s=0,1,\\ldots$) and qubit modes ($q=0,1,\\ldots$) coupled to each other,\n \n**Hamiltonian**\n\\begin{equation}\nH = \\sum_s \\omega_s a_s^\\dagger a_s + \\sum_{q,l} \\epsilon^q_l |l_q\\rangle\\langle l_q| \n+ \\sum_{s\\not=s'} g^{ss'}(a_s + a_s^\\dagger)(a_{s'} + a_{s'}^\\dagger)\n+ \\sum_{s,q,l} g^{sq}_{ll'} (a_s + a_s^\\dagger)|l_q\\rangle\\langle l_q'|\n+ \\sum_{q\\not=q'}\\sum_{lm,l'm'}g^{qq'}_{lm,l'm'}|l_q l'_{q'}\\rangle\\langle m_q m'_{q'}|\n\\end{equation}\n\n \nIf this system is fully dispersive, then the leading terms in the effective Hamiltonian, as obtained by a Schrieffer-Wolff transformation, can be written as:
\n\n**Dispersive Hamiltonian**\n\\begin{align}\nH_\\text{eff}&= E_0 + \\underbrace{\\sum_s (\\omega_s + \\Delta\\omega_s) a_s^\\dagger a_s + \\sum_{q,l>0} (\\bar{\\epsilon}^q_l + \\Delta \\bar{\\epsilon}^q_l)|l_q\\rangle\\langle l_q|}_\\text{bare modes plus Lamb shifts}\n+\\underbrace{\\sum_{s;q,l>0}\\bar{\\chi}^{sq}_l a_s^\\dagger a_s |l_q\\rangle\\langle l_q|}_\\text{ac Stark shifts}\n+\\underbrace{\\sum_{s> s'} K_{ss'} a_s^\\dagger a_s a_{s'}^\\dagger a_{s'}}_\\text{cross-Kerr}\\\\\n&\\quad +\\underbrace{\\sum_{s} K_{s} a_s^\\dagger a_{s}^\\dagger a_{s} a_{s}}_\\text{self-Kerr}\n+\\underbrace{\\sum_{ql \\not= q'l'} \\Lambda^{qq'}_{ll'} |l_q,l'_{q'}\\rangle \\langle l_q, l'_{q'}|}_\\text{interaction among anharmonic modes}\n\\end{align}\n\nHere, the energy coefficients are:\n\\begin{align}\n&E_0 =\\textstyle \\sum_q \\epsilon^q_0 && \\text{(global energy offset)}\\\\\n&\\Delta\\omega_s && \\text{(harmonic mode frequency corrections)}\\\\\n&\\bar{\\epsilon}^q_l = \\epsilon^q_l - \\epsilon^q && \\text{(anharmonic mode energies relative to respective ground state energy)}\\\\\n&\\Delta\\bar{\\epsilon}^q_l && \\text{(Lamb shifts)}\\\\\n&\\bar{\\chi}^{sq}_l = \\chi^{sq}_l - \\chi^{sq}_0 && \\text{(ac Stark shift for modes $s$ and $q$, relative to the $q=0$ state)}\\\\\n&K_{ss'}, K_s && \\text{(cross- and self-Kerr)}\\\\\n&\\Lambda^{qq'}_{ll'} && \\text{(\"Kerr\" among qubit modes)}\n\\end{align}\n\n#### Evaluation of energy coefficients\nThe various energy coefficients are evaluated by forming appropriate energy differences of the dressed eigenenergies. Denote the latter as\n\n\\begin{equation} E(n_1,n_2,\\ldots;l_1,l_2,\\ldots) = E(\\vec{n},\\vec{l})\\end{equation}\n\nWith this the dispersive energy coefficients are:\n\n**Lamb shift, anharmonic mode**
\n$\\Delta\\bar{\\epsilon}^q_l = E(\\vec{o},l\\hat{e}_q) - E(\\vec{o},\\vec{o}) - \\bar{\\epsilon}^q_l$ \n\n**Lamb shift, harmonic mode**
\n$\\Delta\\omega_s = E(\\hat{e}_s,\\vec{o}) - E(\\vec{o},\\vec{o}) - \\omega_s$ \n\n**AC Stark shift**
\n$\\bar{\\chi}^{sq}_l = E(\\hat{e}_s,l\\hat{e}_q) -(\\epsilon^q_l + \\Delta\\epsilon^q_l) - (\\omega_s + \\Delta\\omega_s) - E(\\vec{o},\\vec{o})$\n\n**self-Kerr**
\n$K_{s} = [E(2\\hat{e}_s,\\vec{o}) - E(\\vec{o},\\vec{o}) - 2(\\omega_s + \\Delta\\omega_s)]/2$\n\n**cross-Kerr**
\n$K_{ss'} = E(\\hat{e}_s + \\hat{e}_{s'}) - E(\\vec{o},\\vec{o}) - (\\omega_s + \\Delta\\omega_s) - (\\omega_{s'} + \\Delta\\omega_{s'})\\qquad (s\\not=s')$\n\n**anharmonic \"Kerr\"**
\n$\\Lambda^{qq'}_{ll'} = E(\\vec{o}, l\\hat{e}_q + l'\\hat{e}_{q'},\\vec{o}) - E(\\vec{o},\\vec{o}) - (\\bar{\\epsilon}^q_l + \\Delta\\bar{\\epsilon}^q_l) - (\\bar{\\epsilon}^{q'}_{l'} + \\Delta\\bar{\\epsilon}^{q'}_{l'})$\n" }, { "cell_type": "markdown", @@ -4832,4 +4767,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/paramsweep2-transitions.ipynb b/docs/source/guide/parametersweep/ipynb/paramsweep2-transitions.ipynb index 91baf84..6c864a3 100644 --- a/docs/source/guide/parametersweep/ipynb/paramsweep2-transitions.ipynb +++ b/docs/source/guide/parametersweep/ipynb/paramsweep2-transitions.ipynb @@ -210,18 +210,7 @@ "name": "#%% md\n" } }, - "source": [ - "## Transition plots\n", - "Energy spectra obtained in single-tone or two-tone spectroscopy always represent transitions energies, rather than absolute energies of individual eigenstates. To generate data mimicking this, appropriate differences between eigenenergies must be taken.\n", - "\n", - "The methods for generating transition energy data and plotting them are `.transitions(...)` and `.plot_transitions(...)`. To create a plot, we use **\"pre-slicing\"** of the `ParameterSweep` instance to specify a sweep along a single axis, and then call `.plot_transitions()`.\n", - "\n", - ".. note::\n", - " **Pre-slicing** applies to `ParameterSweep` objects. It uses numpy or generalized slicing notation to \n", - " specify a subset of the sweep. For plotting, the resulting subset should be a one-dimensional sweep. Note that \n", - " pre-slicing does not actually discard any data. Rather, it internally marks the selected sub-sweep which is \n", - " then looked up when applying `.transitions()` or `plot_transitions()`." - ] + "source": "## Transition plots\nEnergy spectra obtained in single-tone or two-tone spectroscopy always represent transition energies, rather than absolute energies of individual eigenstates. To generate data mimicking this, appropriate differences between eigenenergies must be taken.\n\nThe methods for generating transition energy data and plotting them are `.transitions(...)` and `.plot_transitions(...)`. To create a plot, we use **\"pre-slicing\"** of the `ParameterSweep` instance to specify a sweep along a single axis, and then call `.plot_transitions()`.\n\n.. note::\n **Pre-slicing** applies to `ParameterSweep` objects. It uses numpy or generalized slicing notation to \n specify a subset of the sweep. For plotting, the resulting subset should be a one-dimensional sweep. Note that \n pre-slicing does not actually discard any data. Rather, it internally marks the selected sub-sweep which is \n then looked up when applying `.transitions()` or `plot_transitions()`." }, { "cell_type": "code", @@ -17918,27 +17907,7 @@ "name": "#%% md\n" } }, - "source": [ - "Overall, `initial` and `final` inputs of different kinds accommodate a variety of\n", - "situations:\n", - "\n", - "\n", - "* Tuples of integers for `initial` and/or `final` are interpreted as excitation numbers of bare product states. scqubits attempts an identification of dressed states with\n", - " bare product states by considering maximum overlaps.\n", - "* Non-negative integer entries for `initial` and/or `final` refer to dressed-state indices (and lead to disabling of the `sidebands` and `subsystems` options).\n", - "* The option `final=-1` signals that all final states are selected for highlighting and are labeled via dressed-state indices.\n", - "\n", - "\n", - "#### `photon_number`\n", - "For **multi-photon transitions**, this keyword argument can be set to the number of photons involved in the transition. This results in division of the transition energies by `photon_number`.\n", - "\n", - "#### `make_positive`\n", - "When considering excited as in the previous example, some of the transition energies will naturally be negative. Experimentally, these transitions are driven at the absolute frequency. By default, absolute values of transition energies are displayed. This can be disabled by setting `make_positive=False`.\n", - "\n", - "\n", - "#### `sidebands`\n", - "By default, sideband transitions are not highlighted. If set to true, sideband transitions with multiple subsystems changing excitation levels are included as well:" - ] + "source": "Overall, `initial` and `final` inputs of different kinds accommodate a variety of\nsituations:\n\n\n* Tuples of integers for `initial` and/or `final` are interpreted as excitation numbers of bare product states. scqubits attempts an identification of dressed states with\n bare product states by considering maximum overlaps.\n* Non-negative integer entries for `initial` and/or `final` refer to dressed-state indices (and lead to disabling of the `sidebands` and `subsystems` options).\n* The option `final=-1` signals that all final states are selected for highlighting and are labeled via dressed-state indices.\n\n\n#### `photon_number`\nFor **multi-photon transitions**, this keyword argument can be set to the number of photons involved in the transition. This results in division of the transition energies by `photon_number`.\n\n#### `make_positive`\nWhen considering excited initial states as in the previous example, some of the transition energies will naturally be negative. Experimentally, these transitions are driven at the absolute frequency. By default, absolute values of transition energies are displayed. This can be disabled by setting `make_positive=False`.\n\n\n#### `sidebands`\nBy default, sideband transitions are not highlighted. If set to true, sideband transitions with multiple subsystems changing excitation levels are included as well:" }, { "cell_type": "code", @@ -22071,4 +22040,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/parametersweep/ipynb/paramsweep2.ipynb b/docs/source/guide/parametersweep/ipynb/paramsweep2.ipynb index de4bd88..a89dfb4 100644 --- a/docs/source/guide/parametersweep/ipynb/paramsweep2.ipynb +++ b/docs/source/guide/parametersweep/ipynb/paramsweep2.ipynb @@ -119,39 +119,7 @@ "name": "#%% md\n" } }, - "source": [ - "\n", - "\n", - "\n", - "### Creating a ParameterSweep object\n", - "\n", - "The `ParameterSweep` class facilitates computation of spectra as function of one or multiple external parameter(s). For efficiency in computing a variety of derived quantities and creating plots, the computed bare and dressed spectral data are stored internally. \n", - "\n", - "A `ParameterSweep` object is initialized by providing the following arguments:\n", - "\n", - "* **hilbertspace** (`scq.HilbertSpace`) -- a `HilbertSpace` object instance that describes the quantum system of interest\n", - "* **paramvals_by_name** (`Dict[str, np.ndarray]`) -- a dictionary that maps each parameter name (string) to an array of parameter values \n", - "* **update_hilbertspace** (`Callable`) -- a function that defines how parameters changes affect the system\n", - "\n", - "`ParameterSweep` accepts the following optional arguments:\n", - "\n", - "* **subsys_update_info** (`Dict[str, List[QuantumSystem]] | None`) -- for potential speed-up, specify which subsystems undergo changes as each of the parameters is varied\n", - "* **labeling_scheme** (`Literal[\"DE\", \"LX\", \"BE\"]`) -- determines the scheme in which the lookup table is generated. \n", - " * **\"DE\"**: traverse eigenstates in the order of their eigenenergy, and find the corresponding bare label one by one\n", - " * **\"LX\"**: traverse the bare labels in the lexical order, and find the corresponding dressed state via branch analysis [Dumas2024]. For more details, please refer to [Eigenstate Labeling by Branch Analysis](../../hilbertspace/ipynb/branch_analysis.ipynb).\n", - " * **\"BE\"**: traverse the bare states in the order of their energy before coupling, and find the corresponding dressed state by branch analysis\n", - "* **labeling_subsys_priority** (`List[int] | None`) -- a permutation of the subsystem indices and bare labels. If it is provided, lexical ordering is performed on the permuted labels. Besides, `labeling_subsys_priority` also determines which subsystem is to be excited during the traversal for both \"LX\" and \"BE\" schemes.\n", - "* **labeling_BEs_count** (`int | None`) -- for scheme \"BE\" only, specifies the number of low-lying bare states to be labeled\n", - "* **deepcopy** (`bool | None`) -- determines whether the `HilbertSpace` object and all constituents should be duplicated and disconnected from the global objects\n", - "* **num_cpus** (`int | None`) -- number of CPU cores requested for the sweep evaluation\n", - "\n", - "(See API documentation for additional options.)\n", - "\n", - "These ingredients all enter as initialization arguments of the `ParameterSweep` object. Once initialized, spectral data is generated and stored.\n", - "\n", - "In our example, we consider the strength of a global magnetic field as the parameter to be changed. This field determines the magnetic fluxes for both qubits, in proportions according to their SQUID loop areas. We will reference the flux for transmon 1, and express the flux for transmon 2 in terms of it via an area ratio. In addition, we will vary the offset charge of transmon 2.\n", - "\n" - ] + "source": "\n\n### Creating a ParameterSweep object\n\nThe `ParameterSweep` class facilitates computation of spectra as function of one or multiple external parameter(s). For efficiency in computing a variety of derived quantities and creating plots, the computed bare and dressed spectral data are stored internally. \n\nA `ParameterSweep` object is initialized by providing the following arguments:\n\n* **hilbertspace** (`scq.HilbertSpace`) -- a `HilbertSpace` object instance that describes the quantum system of interest\n* **paramvals_by_name** (`Dict[str, np.ndarray]`) -- a dictionary that maps each parameter name (string) to an array of parameter values \n* **update_hilbertspace** (`Callable`) -- a function that defines how parameter changes affect the system\n\n`ParameterSweep` accepts the following optional arguments:\n\n* **subsys_update_info** (`Dict[str, List[QuantumSystem]] | None`) -- for potential speed-up, specify which subsystems undergo changes as each of the parameters is varied\n* **labeling_scheme** (`Literal[\"DE\", \"LX\", \"BE\"]`) -- determines the scheme in which the lookup table is generated. \n * **\"DE\"**: traverse eigenstates in the order of their eigenenergy, and find the corresponding bare label one by one\n * **\"LX\"**: traverse the bare labels in the lexical order, and find the corresponding dressed state via branch analysis [Dumas2024]. For more details, please refer to [Eigenstate Labeling by Branch Analysis](../../hilbertspace/ipynb/branch_analysis.ipynb).\n * **\"BE\"**: traverse the bare states in the order of their energy before coupling, and find the corresponding dressed state by branch analysis\n* **labeling_subsys_priority** (`List[int] | None`) -- a permutation of the subsystem indices and bare labels. If it is provided, lexical ordering is performed on the permuted labels. Besides, `labeling_subsys_priority` also determines which subsystem is to be excited during the traversal for both \"LX\" and \"BE\" schemes.\n* **labeling_BEs_count** (`int | None`) -- for scheme \"BE\" only, specifies the number of low-lying bare states to be labeled\n* **deepcopy** (`bool | None`) -- determines whether the `HilbertSpace` object and all constituents should be duplicated and disconnected from the global objects\n* **num_cpus** (`int | None`) -- number of CPU cores requested for the sweep evaluation\n\n(See API documentation for additional options.)\n\nThese ingredients all enter as initialization arguments of the `ParameterSweep` object. Once initialized, spectral data is generated and stored.\n\nIn our example, we consider the strength of a global magnetic field as the parameter to be changed. This field determines the magnetic fluxes for both qubits, in proportions according to their SQUID loop areas. We will reference the flux for transmon 1, and express the flux for transmon 2 in terms of it via an area ratio. In addition, we will vary the offset charge of transmon 2.\n\n" }, { "cell_type": "markdown", @@ -352,4 +320,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/qubits/cos2phi_qubit.rst b/docs/source/guide/qubits/cos2phi_qubit.rst index ec523d4..f5885fb 100644 --- a/docs/source/guide/qubits/cos2phi_qubit.rst +++ b/docs/source/guide/qubits/cos2phi_qubit.rst @@ -26,7 +26,7 @@ In the presence of disorder, the circuit is described by & + E_\text{L}'(\phi - \pi\Phi_\text{ext}/\Phi_0)^2 + E_\text{L}' \zeta^2 - 2 E_\text{J}\cos{\theta}\cos{\phi} \\ & + 2 dE_\text{J} E_\text{J}\sin{\theta}\sin{\phi} \\ & - 4 dC_\text{J} E_\text{CJ}' n_\phi (n_\theta - n_\text{g}-n_\zeta) \\ - & + dL E_\text{L}'(2\phi - \varphi_\text{ext})\zeta , + & + dL E_\text{L}'(2\phi - \varphi_\text{ext})\zeta, where :math:`E_\text{CJ}' = E_\text{CJ} / (1 - dC_\text{J})^2` and :math:`E_\text{L}' = E_\text{L} / (1 - dL)^2`. diff --git a/docs/source/guide/qubits/flux_qubit.rst b/docs/source/guide/qubits/flux_qubit.rst index b53adb3..145b23f 100644 --- a/docs/source/guide/qubits/flux_qubit.rst +++ b/docs/source/guide/qubits/flux_qubit.rst @@ -1,11 +1,11 @@ .. scqubits Copyright (C) 2017 and later, Jens Koch & Peter Groszkowski +.. _qubit_flux_qubit: + `FluxQubit` =========== -.. _qubit_flux_qubit: - .. figure:: ../../graphics/fluxqubit.png :align: center :width: 4in diff --git a/docs/source/guide/qubits/fullzeropi.rst b/docs/source/guide/qubits/fullzeropi.rst index a29f83e..7b6cec9 100644 --- a/docs/source/guide/qubits/fullzeropi.rst +++ b/docs/source/guide/qubits/fullzeropi.rst @@ -22,12 +22,12 @@ Hamiltonian :math:`H = H_{0-\pi} + H_\text{int} + H_\zeta`, where H_\text{int} =& 2E_{C\Sigma}dC\,\partial_\theta\partial_\zeta + E_L dE_L \phi\,\zeta\\ H_\zeta =& \omega_\zeta a^\dagger a -expressed in the phase basis. The definition of the relevant charging energies +expressed in the phase basis. The definitions of the relevant charging energies :math:`E_\text{CJ}`, :math:`E_{\text{C}\Sigma}`, Josephson energies :math:`E_\text{J}`, inductive energies :math:`E_\text{L}`, and relative amounts of disorder -:math:`dC_\text{J}`, :math:`dE_\text{J}`, :math:`dC`, :math:`dE_\text{L}` follows [Groszkowski2018]_. +:math:`dC_\text{J}`, :math:`dE_\text{J}`, :math:`dC`, :math:`dE_\text{L}` follow [Groszkowski2018]_. Internally, the ``FullZeroPi`` class formulates the Hamiltonian matrix via the product basis of the decoupled Zero-Pi -qubit (realized by ``ZeroPi``) on one hand, and the zeta LC oscillator on the other hand. +qubit (realized by ``ZeroPi``) on the one hand, and the zeta LC oscillator on the other hand. An instance of the full Zero-Pi qubit is created as follows:: @@ -49,7 +49,7 @@ An instance of the full Zero-Pi qubit is created as follows:: zeta_cutoff = 30) Here, ``flux`` is given in terms of the flux quantum, i.e., in the form :math:`\Phi_\text{ext}/\Phi_0`. In the above example, -the disorder parameters ``dEJ`` and ``dCJ`` are not specified, and hence take on the default value zero (no disorder). +the disorder parameters ``dEJ``, ``dCJ``, ``dEL``, and ``dC`` are all specified explicitly (here, to nonzero values introducing disorder). From within a Jupyter notebook, an instance of the disordered Zero-Pi qubit can alternatively be created with:: diff --git a/docs/source/guide/qubits/zeropi.rst b/docs/source/guide/qubits/zeropi.rst index 8aeadff..9bba5ea 100644 --- a/docs/source/guide/qubits/zeropi.rst +++ b/docs/source/guide/qubits/zeropi.rst @@ -19,9 +19,9 @@ The Zero-Pi qubit [Brooks2013]_ [Dempster2014]_, when decoupled from the zeta mo &\qquad -2E_\text{J}\cos\theta\cos(\phi-\varphi_\text{ext}/2)+E_L\phi^2+2E_\text{J} + E_J dE_J \sin\theta\sin(\phi-\varphi_\text{ext}/2) -expressed in phase basis. The definition of the relevant charging energies :math:`E_\text{CJ}`, :math:`E_{\text{C}\Sigma}`, +expressed in phase basis. The definitions of the relevant charging energies :math:`E_\text{CJ}`, :math:`E_{\text{C}\Sigma}`, Josephson energies :math:`E_\text{J}`, inductive energies :math:`E_\text{L}`, and relative amounts of disorder -:math:`dC_\text{J}`, :math:`dE_\text{J}` follows [Groszkowski2018]_. +:math:`dC_\text{J}`, :math:`dE_\text{J}` follow [Groszkowski2018]_. Internally, the ``ZeroPi`` class formulates the Hamiltonian matrix by discretizing the ``phi`` variable, and using charge basis for the ``theta`` variable. diff --git a/docs/source/guide/settings/guide-plot-options.rst b/docs/source/guide/settings/guide-plot-options.rst index 9eb3aac..39e42ee 100644 --- a/docs/source/guide/settings/guide-plot-options.rst +++ b/docs/source/guide/settings/guide-plot-options.rst @@ -47,10 +47,10 @@ summarized here: | ``filename``: `str` | If provided, plot is written to file | +------------------------------+------------------------------------------------+ -A number of additional options falling in the ``Axes.set_xxx(...)`` category is available; consult the +A number of additional options falling in the ``Axes.set_xxx(...)`` category are available; consult the ``matplotlib.axes.Axes`` `API documentation`__ to see the complete list. -Matplotlib's option ``grid`` is also supported and appropriately handled by scqubits. An argument that reads ``grid=xxx`` which is passed to an scqubits plotting command, is internally processed as ``Axes.grid(**xxx)``, if the ``xxx`` is a python dictionary, or as ``Axes.grid(xxx)`` otherwise. +Matplotlib's option ``grid`` is also supported and appropriately handled by scqubits. An argument that reads ``grid=xxx`` which is passed to an scqubits plotting command, is internally processed as ``Axes.grid(**xxx)``, if ``xxx`` is a Python dictionary, or as ``Axes.grid(xxx)`` otherwise. There are also some plotting options that scqubits plotting routines directly pass to the appropriate Matplotlib plotting commands (such as ``plot`` or ``imshow``). In the case of standard x vs y types of plots, these include: @@ -65,7 +65,7 @@ There are also some plotting options that scqubits plotting routines directly pa +---------------------------------+-------------------------------------------------------+ | ``marker``: `str` | Marker style | +---------------------------------+-------------------------------------------------------+ -| ``markersize``: `str` | Markersize in points | +| ``markersize``: `float` | Markersize in points | +---------------------------------+-------------------------------------------------------+ scqubits plotting routines that internally use Matplotlib's ``imshow`` command (such as ``ZeroPi.plot_wavefunction`` for example) support @@ -73,7 +73,7 @@ scqubits plotting routines that internally use Matplotlib's ``imshow`` command ( +------------------------------+-----------------------------------------------------------------+ | keyword | Description | +==============================+=================================================================+ -| ``interpolation``: `str` | Types of interpolation such (e.g. "spline16", "bilinear", etc.) | +| ``interpolation``: `str` | Type of interpolation (e.g., "spline16", "bilinear", etc.) | +------------------------------+-----------------------------------------------------------------+ For a more detailed description of some of the above options, see Matplotlib's `documentation `_. @@ -85,6 +85,6 @@ __ API_ Returns of plot functions ------------------------- -Every scqubit routine for plotting returns a tuple ``(Figure, Axes)`` of Matplotlib objects. These can be used for +Every scqubits routine for plotting returns a tuple ``(Figure, Axes)`` of Matplotlib objects. These can be used for further processing by the user. In Jupyter, lines calling plot routines can be ended with a ``;`` to avoid the text output indicating the returned objects. diff --git a/docs/source/guide/settings/guide-settings.rst b/docs/source/guide/settings/guide-settings.rst index 1a96115..9d0737f 100644 --- a/docs/source/guide/settings/guide-settings.rst +++ b/docs/source/guide/settings/guide-settings.rst @@ -14,33 +14,47 @@ User Accessible Parameters scqubits has a few internal parameters that can be changed by the user: -.. tabularcolumns:: | p{3cm} | p{3cm} | p{3cm} | - -.. cssclass:: table-striped - -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| Setting | Options | Description | -+==============================+==============================+=============+=====================================================+ -| ``FILE_FORMAT`` | `FileType.h5`, `FileType.csv`| Switches between supported file formats for writing data to disk. | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``PROGRESSBAR_DISABLED`` | True / False | Switches display of progressbar on/off. | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``AUTORUN_SWEEP`` | True / False (default: True) | Whether to generate ``ParameterSweep`` | -| | | immediately upon initialization | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``DISPATCH_ENABLED`` | True / False (default: True) | Whether to use central dispatch system | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``MULTIPROC`` | `str` | 'pathos' (default) or 'multiprocessing' | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``NUM_CPUS`` | int | Number of cores to be used in parallelization (default: 1) | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``FUZZY_SLICING`` | True / False (default: False)| Whether to enable approximate value-based slicing | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``FUZZY_WARNING`` | True / False (default: True) | Whether to warn user about use of approximate values in slicing | -+------------------------------+------------------------------+-------------------------------------------------------------------+ -| ``SYM_INVERSION_MAX_NODES`` | int (default: 3) | Threshold number of nodes above which the capacitance matrix is | -| | | inverted numerically | -+------------------------------+------------------------------+-------------------------------------------------------------------+ +.. list-table:: + :header-rows: 1 + :widths: 30 30 50 + :class: table-striped + + * - Setting + - Options + - Description + * - ``FILE_FORMAT`` + - ``FileType.h5``, ``FileType.csv`` + - Switches between supported file formats for writing data to disk. + * - ``PROGRESSBAR_DISABLED`` + - ``True`` / ``False`` + - Switches display of progressbar on/off. + * - ``AUTORUN_SWEEP`` + - ``True`` / ``False`` (default: ``True``) + - Whether to generate ``ParameterSweep`` immediately upon initialization. + * - ``DISPATCH_ENABLED`` + - ``True`` / ``False`` (default: ``True``) + - Whether to use central dispatch system. + * - ``MULTIPROC`` + - ``str`` + - ``"pathos"`` (default) or ``"multiprocessing"``. + * - ``NUM_CPUS`` + - ``int`` + - Number of cores to be used in parallelization (default: 1). + * - ``FUZZY_SLICING`` + - ``True`` / ``False`` (default: ``False``) + - Whether to enable approximate value-based slicing. + * - ``FUZZY_WARNING`` + - ``True`` / ``False`` (default: ``True``) + - Whether to warn user about use of approximate values in slicing. + * - ``SYM_INVERSION_MAX_NODES`` + - ``int`` (default: ``3``) + - Threshold number of nodes above which the capacitance matrix is inverted numerically. + * - ``CSC_DEFAULT_TARGET_ABS_GHZ`` + - ``float`` (default: ``1e-4``) + - Default absolute energy-error target (GHz) used by the zero-input :func:`scqubits.csc` convenience. Tune for tighter (kHz) or looser (MHz) precision needs. + * - ``CSC_DEFAULT_NLEVELS_CAP`` + - ``int`` (default: ``6``) + - Upper bound on ``n_levels`` chosen automatically by :func:`scqubits.csc` from ``truncated_dim`` / ``dimension`` / ``hilbertdim()``. Raise this if you routinely care about more states. Users can also set up units of the energy scales. This is discussed in the :ref:`guide_units` section of the user guide. diff --git a/docs/source/guide/settings/ipynb/custom_diagonalization.ipynb b/docs/source/guide/settings/ipynb/custom_diagonalization.ipynb index f580e1d..7196c91 100644 --- a/docs/source/guide/settings/ipynb/custom_diagonalization.ipynb +++ b/docs/source/guide/settings/ipynb/custom_diagonalization.ipynb @@ -110,30 +110,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "In the above, the first part of the string represents whether just the eigenvalues or both eigenvalues and eigenvectors are returned. Naturally, procedures that return the eigenvalues (eigenvalues **and** eigenvectors) are used by the method `eigenvals` (`eigensys`) of the different quantum objects that `scqubits` implements. \n", - "The second word labels what library is used (e.g., `scipy` or `cuda`, etc.), and the third, whether sparse or dense diagonalization should be performed. Everything that follows, is simply some description of specific diagonalization options that are used.\n", - "\n", - "For example, a method `esys_cupy_sparse` will invoke the diagonalization function [eigsh](https://docs.cupy.dev/en/stable/reference/generated/cupyx.scipy.sparse.linalg.eigsh.html) from the sparse implementation of the cupy library (see [here](https://docs.cupy.dev/en/stable/reference/scipy_sparse_linalg.html)), which will return the lowest set of requested eigenvalues and eigenvectors (i.e., will have the options `which='SA'` passed in).\n", - "\n", - "On the other hand, if the user sets `esys_method` to `\"esys_scipy_sparse_LA_shift-inverse\"` when initializing a, for example, `Transmon` object, will results in `scqubits` internally invoking the `scipy`'s sparse diagonalization routine (here `eighs`), whenever the `Transmon.eigensys` method is called. Furthermore, the shift-inverse method will be used, with algebraic (and not by magnitude) eigenvalue ordering (i.e., `which='LA'` will be passed to `eighs` - see `scipy`'s documentation for more details). \n", - "\n", - ".. warning::\n", - "It is crucial to note that in some cases, a particular method may be the wrong choice. For example in quantum systems where the eigenenergies are not guaranteed to be positive, using the \"SM\" method (that sorts eigenvalues by magnitude), may lead to incorrect results.\n", - "\n", - "\n", - "`scqubits` supports a number of backend libraries such as, \n", - "[scipy](https://docs.scipy.org/doc/scipy/tutorial/index.html),\n", - "[primme](https://www.cs.wm.edu/~andreas/software/doc/apieigs.html),\n", - "[cupy](https://cupy.dev/) (which allows for GPU-based diagonalization),\n", - "as well as \n", - "[jax](https://jax.readthedocs.io/en/latest/index.html) (which also, optionally, allows for GPU-based operations).\n", - "\n", - ".. note::\n", - " Some of the libraries that can be used for diagonalization (e.g., [cupy](https://cupy.dev/) or [primme](https://www.cs.wm.edu/~andreas/software/doc/apieigs.html)) are only optional dependencies of `scqubits`.\n", - " Naturally, however, they do need to be installed before a diagonalization method that relies on them is selected and used.\n", - "\n" - ] + "source": "In the above, the first part of the string represents whether just the eigenvalues or both eigenvalues and eigenvectors are returned. Naturally, procedures that return the eigenvalues (eigenvalues **and** eigenvectors) are used by the method `eigenvals` (`eigensys`) of the different quantum objects that `scqubits` implements. \nThe second word labels what library is used (e.g., `scipy` or `cupy`, etc.), and the third, whether sparse or dense diagonalization should be performed. Everything that follows, is simply some description of specific diagonalization options that are used.\n\nFor example, a method `esys_cupy_sparse` will invoke the diagonalization function [eigsh](https://docs.cupy.dev/en/stable/reference/generated/cupyx.scipy.sparse.linalg.eigsh.html) from the sparse implementation of the cupy library (see [here](https://docs.cupy.dev/en/stable/reference/scipy_sparse_linalg.html)), which will return the lowest set of requested eigenvalues and eigenvectors (i.e., will have the options `which='SA'` passed in).\n\nOn the other hand, if the user sets `esys_method` to `\"esys_scipy_sparse_LA_shift-inverse\"` when initializing, for example, a `Transmon` object, this will result in `scqubits` internally invoking scipy's sparse diagonalization routine (here `eigsh`), whenever the `Transmon.eigensys` method is called. Furthermore, the shift-inverse method will be used, with algebraic (and not by magnitude) eigenvalue ordering (i.e., `which='LA'` will be passed to `eigsh` - see `scipy`'s documentation for more details). \n\n.. warning::\nIt is crucial to note that in some cases, a particular method may be the wrong choice. For example in quantum systems where the eigenenergies are not guaranteed to be positive, using the \"SM\" method (that sorts eigenvalues by magnitude), may lead to incorrect results.\n\n\n`scqubits` supports a number of backend libraries such as, \n[scipy](https://docs.scipy.org/doc/scipy/tutorial/index.html),\n[primme](https://www.cs.wm.edu/~andreas/software/doc/apieigs.html),\n[cupy](https://cupy.dev/) (which allows for GPU-based diagonalization),\nas well as \n[jax](https://jax.readthedocs.io/en/latest/index.html) (which also, optionally, allows for GPU-based operations).\n\n.. note::\n Some of the libraries that can be used for diagonalization (e.g., [cupy](https://cupy.dev/) or [primme](https://www.cs.wm.edu/~andreas/software/doc/apieigs.html)) are only optional dependencies of `scqubits`.\n Naturally, however, they do need to be installed before a diagonalization method that relies on them is selected and used.\n" }, { "cell_type": "markdown", @@ -379,13 +356,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "## Diagonalization of composite systems\n", - "\n", - "Custom diagonalization procedure can be set by the user for both, the predefined qubit classes (as shown above), but also for systems consisting of joint [Hilbert spaces](../../hilbertspace/ipynb/hilbertspace.ipynb). Since often one is interested in a low-lying energy landscape of larger systems, `scqubits` uses the concept of hierarchical diagonalization to minimize the size of the relevant Hilbert space that has to be considered: Each system is first diagonalized separately, the coupling terms are then rewritten in the (often some subset of) respective eigenbasis, and finally the combined system is diagonalized at the end. This gives a lot of control to the user, and `scqubits` allows one to set custom (and even different) diagonalization procedure for each step of this process. \n", - "\n", - "Here as an example of a joint system consisting of a Fluxonium and a Transmon qubit, where each qubit, as well as the combined Hamiltonian are all diagonalized using a different method. " - ] + "source": "## Diagonalization of composite systems\n\nCustom diagonalization procedure can be set by the user for both, the predefined qubit classes (as shown above), but also for systems consisting of joint [Hilbert spaces](../../hilbertspace/ipynb/hilbertspace.ipynb). Since often one is interested in a low-lying energy landscape of larger systems, `scqubits` uses the concept of hierarchical diagonalization to minimize the size of the relevant Hilbert space that has to be considered: Each system is first diagonalized separately, the coupling terms are then rewritten in the (often some subset of) respective eigenbasis, and finally the combined system is diagonalized at the end. This gives a lot of control to the user, and `scqubits` allows one to set custom (and even different) diagonalization procedure for each step of this process. \n\nHere is an example of a joint system consisting of a Fluxonium and a Transmon qubit, where each qubit, as well as the combined Hamiltonian, is diagonalized using a different method. " }, { "cell_type": "code", @@ -556,16 +527,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "## GPU support\n", - "\n", - "Diagonalization on GPUs is currently supported through the [cupy](https://cupy.dev/), and optionally, the [jax](https://jax.readthedocs.io/en/latest/index.html) libraries. As already outlined above, to use user any of these packages for diagonalization, they have to be installed on the user's machine. \n", - "\n", - "It is worth pointing out, that depending on one's hardware, and the quantum system studied, the performance of GPU vs CPU diagonalization may vary dramatically from setup to setup. \n", - "\n", - ".. warning::\n", - "Using multiple GPU-reliant libraries within the same `python` session may not always be supported by either the libraries, or the hardware vendors (e.g. GPUs may need resetting and/or reinitialization between uses). Users may need to consult documentation on details of how that is done in their setup.\n" - ] + "source": "## GPU support\n\nDiagonalization on GPUs is currently supported through the [cupy](https://cupy.dev/), and optionally, the [jax](https://jax.readthedocs.io/en/latest/index.html) libraries. As already outlined above, to use any of these packages for diagonalization, they have to be installed on the user's machine. \n\nIt is worth pointing out, that depending on one's hardware, and the quantum system studied, the performance of GPU vs CPU diagonalization may vary dramatically from setup to setup. \n\n.. warning::\nUsing multiple GPU-reliant libraries within the same `python` session may not always be supported by either the libraries, or the hardware vendors (e.g. GPUs may need resetting and/or reinitialization between uses). Users may need to consult documentation on details of how that is done in their setup.\n" }, { "cell_type": "markdown", @@ -2374,12 +2336,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "#### GPU use with `jax`\n", - "\n", - "The `jax` library supports both CPU, and well as GPU based backends. \n", - "The default on this machine can be checked with" - ] + "source": "#### GPU use with `jax`\n\nThe `jax` library supports both CPU and GPU based backends. \nThe default on this machine can be checked with" }, { "cell_type": "code", @@ -2407,9 +2364,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "Setting `esys_method` and/or `evals_method` to one of the `jax`-based routines, will use the backed that is currently set, which here is GPU-based" - ] + "source": "Setting `esys_method` and/or `evals_method` to one of the `jax`-based routines, will use the backend that is currently set, which here is GPU-based" }, { "cell_type": "code", @@ -2490,4 +2445,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file diff --git a/docs/source/guide/storage/ipynb/storage.ipynb b/docs/source/guide/storage/ipynb/storage.ipynb index fc0beb7..372345b 100644 --- a/docs/source/guide/storage/ipynb/storage.ipynb +++ b/docs/source/guide/storage/ipynb/storage.ipynb @@ -3,23 +3,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "# Saving Data and Figures\n", - "\n", - "Much of the data and plots computed with scqubits can easily be stored in memory, or exported and written to files. Data that we may want to save includes \n", - "\n", - "* computed eigenvalues and eigenvectors, \n", - "* qubit parameters,\n", - "* matrix elements,\n", - "* parameter sweeps, and\n", - "* plots,\n", - "\n", - "to name a few. Further, scqubits makes it possible to write the configuration of a qubit or a `HilbertSpace` object to disk, and recreate the object instance later on. The following subsections illustrate usage the different usage cases.\n", - "\n", - "\n", - "## Storing qubit spectral data in memory\n", - "Consider an instance of a transmon qubit:" - ] + "source": "# Saving Data and Figures\n\nMuch of the data and plots computed with scqubits can easily be stored in memory, or exported and written to files. Data that we may want to save includes \n\n* computed eigenvalues and eigenvectors, \n* qubit parameters,\n* matrix elements,\n* parameter sweeps, and\n* plots,\n\nto name a few. Further, scqubits makes it possible to write the configuration of a qubit or a `HilbertSpace` object to disk, and recreate the object instance later on. The following subsections illustrate the different usage cases.\n\n\n## Storing qubit spectral data in memory\nConsider an instance of a transmon qubit:" }, { "cell_type": "code", @@ -94,9 +78,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": [ - "The relevant data is accessible through the attributes `.energy_table`, `.state_table`. The system parameters used to generate the data is stored alongside under `.system_params`." - ] + "source": "The relevant data is accessible through the attributes `.energy_table`, `.state_table`. The system parameters used to generate the data are stored alongside under `.system_params`." }, { "cell_type": "code", diff --git a/docs/source/index.rst b/docs/source/index.rst index eaeafd3..c2cccab 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,7 +2,7 @@ Copyright (C) 2019, Jens Koch & Peter Groszkowski -scQubits documentation +scqubits documentation ====================== scqubits is an open-source Python library for simulating superconducting qubits. @@ -83,6 +83,7 @@ appropriately acknowledged by citing: ./guide/qubits/guide-qubits.rst ./guide/noise/guide-noise.rst + ./guide/convergence/guide-convergence.rst Single-Qubit Parameter Sweep <./guide/parametersweep/ipynb/paramsweep.ipynb> diff --git a/docs/source/install/gen-requirements.rst b/docs/source/install/gen-requirements.rst index cd8022d..94e9bf2 100644 --- a/docs/source/install/gen-requirements.rst +++ b/docs/source/install/gen-requirements.rst @@ -44,7 +44,7 @@ The following packages are optional: +------------------------+--------------+-----------------------------------------------------+ | pytest | 5.3+ | For running the test suite. | +------------------------+--------------+-----------------------------------------------------+ -| matplotlib-label-lines | 0.3.6+ | For smart labelling of matrix element plots | +| matplotlib-label-lines | 0.3.6+ | For smart labeling of matrix element plots | +------------------------+--------------+-----------------------------------------------------+ .. warning::