From 0b82033add78ffee748adaf45cae4a6f0b3afe4f Mon Sep 17 00:00:00 2001 From: ABBY CROSS Date: Fri, 14 Aug 2026 12:17:25 -0400 Subject: [PATCH 1/8] add box link --- scripts/config/api-html-artifacts.json | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/config/api-html-artifacts.json b/scripts/config/api-html-artifacts.json index f1fb2d2f04b..eadede94f97 100644 --- a/scripts/config/api-html-artifacts.json +++ b/scripts/config/api-html-artifacts.json @@ -109,6 +109,7 @@ "0.1": "https://ibm.box.com/shared/static/avbot44xlamcvccs8ylj7md7kjfjgfw8.zip" }, "qiskit-addon-sqd": { + "0.13": "https://ibm.box.com/shared/static/fclsbxvg3a92x7n1jay0bbke5hbda63f.zip", "0.12": "https://ibm.box.com/shared/static/s96j7d1ofs6esevo75ox78u8kqks131i.zip", "0.11": "https://ibm.box.com/shared/static/b2d306sfbkejd7j6c80asywh1fjrpftn.zip", "0.10": "https://ibm.box.com/shared/static/g73sbmg2bt3gmq3x26ybxbm7vsj6ioyb.zip", From 0eed1b488bf8c9a88cdbd2d3c7e4d94d04aa962f Mon Sep 17 00:00:00 2001 From: ABBY CROSS Date: Fri, 14 Aug 2026 12:20:38 -0400 Subject: [PATCH 2/8] save historical docs --- docs/api/qiskit-addon-sqd/0.12/_package.json | 4 + docs/api/qiskit-addon-sqd/0.12/_toc.json | 43 ++ .../0.12/configuration-recovery.mdx | 77 ++++ docs/api/qiskit-addon-sqd/0.12/counts.mdx | 146 +++++++ docs/api/qiskit-addon-sqd/0.12/fermion.mdx | 413 ++++++++++++++++++ docs/api/qiskit-addon-sqd/0.12/index.mdx | 15 + docs/api/qiskit-addon-sqd/0.12/qubit.mdx | 144 ++++++ .../api/qiskit-addon-sqd/0.12/subsampling.mdx | 112 +++++ .../api/qiskit-addon-sqd/0.12/objects.inv | Bin 0 -> 1805 bytes .../config/historical-pages-to-latest.json | 2 + 10 files changed, 956 insertions(+) create mode 100644 docs/api/qiskit-addon-sqd/0.12/_package.json create mode 100644 docs/api/qiskit-addon-sqd/0.12/_toc.json create mode 100644 docs/api/qiskit-addon-sqd/0.12/configuration-recovery.mdx create mode 100644 docs/api/qiskit-addon-sqd/0.12/counts.mdx create mode 100644 docs/api/qiskit-addon-sqd/0.12/fermion.mdx create mode 100644 docs/api/qiskit-addon-sqd/0.12/index.mdx create mode 100644 docs/api/qiskit-addon-sqd/0.12/qubit.mdx create mode 100644 docs/api/qiskit-addon-sqd/0.12/subsampling.mdx create mode 100644 public/docs/api/qiskit-addon-sqd/0.12/objects.inv diff --git a/docs/api/qiskit-addon-sqd/0.12/_package.json b/docs/api/qiskit-addon-sqd/0.12/_package.json new file mode 100644 index 00000000000..1f226e87545 --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/_package.json @@ -0,0 +1,4 @@ +{ + "name": "qiskit-addon-sqd", + "version": "0.12.1" +} diff --git a/docs/api/qiskit-addon-sqd/0.12/_toc.json b/docs/api/qiskit-addon-sqd/0.12/_toc.json new file mode 100644 index 00000000000..eaf2f37f38c --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/_toc.json @@ -0,0 +1,43 @@ +{ + "title": "Sample-based quantum diagonalization (SQD)", + "children": [ + { + "title": "API index", + "url": "/docs/api/qiskit-addon-sqd/0.12" + }, + { + "title": "Release notes", + "useDivider": true, + "url": "/docs/api/qiskit-addon-sqd/release-notes" + }, + { + "title": "qiskit_addon_sqd.configuration_recovery", + "url": "/docs/api/qiskit-addon-sqd/0.12/configuration-recovery", + "untranslatable": true + }, + { + "title": "qiskit_addon_sqd.counts", + "url": "/docs/api/qiskit-addon-sqd/0.12/counts", + "untranslatable": true + }, + { + "title": "qiskit_addon_sqd.fermion", + "url": "/docs/api/qiskit-addon-sqd/0.12/fermion", + "untranslatable": true + }, + { + "title": "qiskit_addon_sqd.qubit", + "url": "/docs/api/qiskit-addon-sqd/0.12/qubit", + "untranslatable": true + }, + { + "title": "qiskit_addon_sqd.subsampling", + "url": "/docs/api/qiskit-addon-sqd/0.12/subsampling", + "untranslatable": true + } + ], + "collapsed": true, + "untranslatable": true, + "parentUrl": "/docs/addons/qiskit-addon-sqd", + "parentLabel": "Sample-based quantum diagonalization (SQD)" +} diff --git a/docs/api/qiskit-addon-sqd/0.12/configuration-recovery.mdx b/docs/api/qiskit-addon-sqd/0.12/configuration-recovery.mdx new file mode 100644 index 00000000000..79e46134a6b --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/configuration-recovery.mdx @@ -0,0 +1,77 @@ +--- +title: configuration_recovery (v0.12) +description: API reference for qiskit_addon_sqd.configuration_recovery in qiskit-addon-sqd v0.12 +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_sqd.configuration_recovery +--- + + + + + +# Configuration recovery + +`qiskit_addon_sqd.configuration_recovery` + +Functions for performing self-consistent configuration recovery. + +### post\_select\_by\_hamming\_weight + + + Post-select bitstrings based on the hamming weight of each half. + + + The function `qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()` is deprecated as of qiskit-addon-sqd 0.12.0. It will be removed no earlier than v0.13.0. Instead, use the `postselect_by_hamming_right_and_left` function. + + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring + * **hamming\_right** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The target hamming weight of the right half of bitstrings + * **hamming\_left** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The target hamming weight of the left half of bitstrings + + **Returns** + + A mask signifying which samples (rows) were selected from the input matrix. + + **Return type** + + [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) + + +### recover\_configurations + + + Refine bitstrings based on average orbital occupancy and a target hamming weight. + + This function refines each bit in isolation in an attempt to transform the Hilbert space represented by the input `bitstring_matrix` into a space closer to that which supports the ground state. + + + This function makes the assumption that bit `i` represents the spin-down orbital corresponding to the spin-up orbital in bit `i + N` where `N` is the number of spatial orbitals and `i < N`. + + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring + * **probabilities** ([*Sequence*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence)*\[*[*float*](https://docs.python.org/3/library/functions.html#float)*] |* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 1D array specifying a probability distribution over the bitstrings + * **avg\_occupancies** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*]*) – A length-2 tuple of arrays holding the mean occupancy of the spin-up and spin-down orbitals, respectively. The occupancies should be formatted as: `(array([occ_a_0, ..., occ_a_N]), array([occ_b_0, ..., occ_b_N]))` + * **num\_elec\_a** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of spin-up electrons in the system. + * **num\_elec\_b** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of spin-down electrons in the system. + * **rand\_seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed for controlling randomness + + **Returns** + + A refined bitstring matrix and an updated probability array. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + **References** + + **\[1]: J. Robledo-Moreno, et al., [Chemistry Beyond Exact Solutions on a Quantum-Centric Supercomputer](https://arxiv.org/abs/2405.05068),** + + arXiv:2405.05068 \[quant-ph]. + + diff --git a/docs/api/qiskit-addon-sqd/0.12/counts.mdx b/docs/api/qiskit-addon-sqd/0.12/counts.mdx new file mode 100644 index 00000000000..70baa64fc7d --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/counts.mdx @@ -0,0 +1,146 @@ +--- +title: counts (v0.12) +description: API reference for qiskit_addon_sqd.counts in qiskit-addon-sqd v0.12 +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_sqd.counts +--- + + + + + +# Counts + +`qiskit_addon_sqd.counts` + +Functions for transforming counts dictionaries. + +### counts\_to\_arrays + + + Convert a counts dictionary into a bitstring matrix and a probability array. + + **Parameters** + + **counts** ([*Mapping*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*float*](https://docs.python.org/3/library/functions.html#float) *|*[*int*](https://docs.python.org/3/library/functions.html#int)*]*) – The counts dictionary to convert + + **Returns** + + * A 2D array representing the sampled bitstrings. Each row represents a bitstring, and each element is a `bool` representation of the bit’s value + * A 1D array containing the probability with which each bitstring was sampled + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + +### generate\_counts\_uniform + + + Generate a bitstring counts dictionary of samples drawn from the uniform distribution. + + **Parameters** + + * **num\_samples** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of samples to draw + * **num\_bits** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of bits in the bitstrings + * **rand\_seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed for controlling randomness + + **Returns** + + A dictionary mapping bitstrings of length `num_bits` to the number of times they were sampled. + + **Raises** + + [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – `num_samples` and `num_bits` must be positive integers. + + **Return type** + + [dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [int](https://docs.python.org/3/library/functions.html#int)] + + +### generate\_counts\_bipartite\_hamming + + + Generate a bitstring counts dictionary with specified bipartite hamming weight. + + **Parameters** + + * **num\_samples** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of samples to draw + * **num\_bits** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of bits in the bitstrings + * **hamming\_right** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The hamming weight on the right half of each bitstring + * **hamming\_left** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The hamming weight on the left half of each bitstring + * **rand\_seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed for controlling randomness + + **Returns** + + A dictionary mapping bitstrings to the number of times they were sampled. Each half of each bitstring in the output dictionary will have a hamming weight as specified by the inputs. + + **Raises** + + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – `num_bits` and `num_samples` must be positive integers. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Hamming weights must be specified as non-negative integers. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – `num_bits` must be even. + + **Return type** + + [dict](https://docs.python.org/3/library/stdtypes.html#dict)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [int](https://docs.python.org/3/library/functions.html#int)] + + +### normalize\_counts\_dict + + + Convert a counts dictionary into a probability dictionary. + + **Parameters** + + **counts** ([*Mapping*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)*\[*[*str*](https://docs.python.org/3/library/stdtypes.html#str)*,* [*float*](https://docs.python.org/3/library/functions.html#float) *|*[*int*](https://docs.python.org/3/library/functions.html#int)*]*) + + **Return type** + + [*Mapping*](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)\[[str](https://docs.python.org/3/library/stdtypes.html#str), [float](https://docs.python.org/3/library/functions.html#float)] + + +### bit\_array\_to\_arrays + + + Convert a bit array into a bitstring matrix and a probability array. + + **Parameters** + + **bit\_array** ([*BitArray*](/docs/api/qiskit/qiskit.primitives.BitArray)) – The bit array to convert + + **Returns** + + * A 2D array representing the sampled bitstrings. Each row represents a bitstring, and each element is a `bool` representation of the bit’s value + * A 1D array containing the probability with which each bitstring was sampled + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + +### generate\_bit\_array\_uniform + + + Generate a bit array of samples drawn from the uniform distribution. + + **Parameters** + + * **num\_samples** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of samples to draw + * **num\_bits** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of bits in the bitstrings + * **rand\_seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed for controlling randomness + + **Returns** + + The sampled bit array. + + **Raises** + + [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – `num_samples` and `num_bits` must be positive integers. + + **Return type** + + [*BitArray*](/docs/api/qiskit/qiskit.primitives.BitArray) + + diff --git a/docs/api/qiskit-addon-sqd/0.12/fermion.mdx b/docs/api/qiskit-addon-sqd/0.12/fermion.mdx new file mode 100644 index 00000000000..95b4133d79c --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/fermion.mdx @@ -0,0 +1,413 @@ +--- +title: fermion (v0.12) +description: API reference for qiskit_addon_sqd.fermion in qiskit-addon-sqd v0.12 +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_sqd.fermion +--- + + + + + +# Fermion + +`qiskit_addon_sqd.fermion` + +Functions for the study of fermionic systems. + +### SCIState + + + Bases: [`object`](https://docs.python.org/3/library/functions.html#object) + + The amplitudes and determinants describing a quantum state. + + **Parameters** + + * **amplitudes** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) + * **ci\_strs\_a** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) + * **ci\_strs\_b** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) + * **norb** ([*int*](https://docs.python.org/3/library/functions.html#int)) + * **nelec** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*]*) + + #### amplitudes + + + An $M \times N$ array where $M =$ len(`ci_strs_a`) and $N$ = len(`ci_strs_b`). `amplitudes[i][j]` is the amplitude of the determinant pair (`ci_strs_a[i]`, `ci_strs_b[j]`). + + + #### ci\_strs\_a + + + The alpha determinants. + + + #### ci\_strs\_b + + + The beta determinants. + + + #### load + + + Load an SCIState object from an .npz file. + + + #### nelec + + + The numbers of alpha and beta electrons. + + + #### norb + + + The number of spatial orbitals. + + + #### orbital\_occupancies + + + Average orbital occupancies. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + + #### rdm + + + Compute reduced density matrix. + + **Parameters** + + * **rank** ([*int*](https://docs.python.org/3/library/functions.html#int)) + * **spin\_summed** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) + + **Return type** + + [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) + + + #### save + + + Save the SCIState object to an .npz file. + + + #### spin\_square + + + Return spin squared. + + **Return type** + + [float](https://docs.python.org/3/library/functions.html#float) + + + +### bitstring\_matrix\_to\_ci\_strs + + + Convert bitstrings (rows) in a `bitstring_matrix` into integer representations of determinants. + + This function separates each bitstring in `bitstring_matrix` in half, translates them into integer representations, and finally appends them to their respective (spin-up or spin-down) lists. Those lists are sorted and output from this function. + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring + * **open\_shell** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – A flag specifying whether unique configurations from the left and right halves of the bitstrings should be kept separate. If `False`, configurations from the left and right halves of the bitstrings are combined into a single set of unique configurations. That combined set will be returned for both the left and right bitstrings. + + **Returns** + + A length-2 tuple of determinant lists representing the right (spin-up) and left (spin-down) halves of the bitstrings, respectively. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + +### diagonalize\_fermionic\_hamiltonian + + + Run the sample-based quantum diagonalization (SQD) algorithm. + + **Parameters** + + * **one\_body\_tensor** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – The one-body tensor of the Hamiltonian. + + * **two\_body\_tensor** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – The two-body tensor of the Hamiltonian. + + * **bit\_array** ([*BitArray*](/docs/api/qiskit/qiskit.primitives.BitArray)) – Array of sampled bitstrings. Each bitstring should have both the alpha part and beta part concatenated together, with the alpha part concatenated on the right-hand side, like this: `[b_N, ..., b_0, a_N, ..., a_0]`. + + * **samples\_per\_batch** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of bitstrings to include in each subsampled batch of bitstrings. + + * **norb** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of spatial orbitals. + + * **nelec** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*]*) – The numbers of alpha and beta electrons. + + * **num\_batches** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of batches to subsample in each configuration recovery iteration. This argument indirectly controls the dimensions of the diagonalization subspaces. A higher value will yield larger subspace dimensions. + + * **energy\_tol** ([*float*](https://docs.python.org/3/library/functions.html#float)) – Numerical tolerance for convergence of the energy. If the change in energy between iterations is smaller than this value, then the configuration recovery loop will exit, if the occupancies have also converged (see the `occupancies_tol` argument). + + * **occupancies\_tol** ([*float*](https://docs.python.org/3/library/functions.html#float)) – Numerical tolerance for convergence of the average orbital occupancies. If the maximum change in absolute value of the average occupancy of an orbital between iterations is smaller than this value, then the configuration recovery loop will exit, if the energy has also converged (see the `energy_tol` argument). + + * **max\_iterations** ([*int*](https://docs.python.org/3/library/functions.html#int)) – Limit on the number of configuration recovery iterations. + + * **sci\_solver** ([*Callable*](https://docs.python.org/3/library/typing.html#typing.Callable)*\[\[*[*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[*[*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*]],* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*,* [*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*]],* [*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[SCIResult]] | None*) – + + Selected configuration interaction solver function. + + Inputs: + + * List of pairs (strings\_a, strings\_b) of arrays of spin-alpha CI strings and spin-beta CI strings whose Cartesian product give the basis of the subspace in which to perform a diagonalization. A list is passed to allow the solver function to perform the diagonalizations in parallel. + * One-body tensor of the Hamiltonian. + * Two-body tensor of the Hamiltonian. + * The number of spatial orbitals. + * A pair (n\_alpha, n\_beta) indicating the numbers of alpha and beta electrons. + + Output: List of (energy, sci\_state, occupancies) triplets, where each triplet contains the result of the corresponding diagonalization. + + * **symmetrize\_spin** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – Whether to always merge spin-alpha and spin-beta CI strings into a single list, so that the diagonalization subspace is invariant with respect to the exchange of spin alpha with spin beta. + + * **max\_dim** ([*int*](https://docs.python.org/3/library/functions.html#int) *|*[*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*] | None*) – + + Limit on the dimension of the spin sectors of the SCI subspace. It can be either: + + * A tuple `(max_dim_a, max_dim_b)` of integers giving separate limits for the spin-alpha and spin-beta sectors. In this case, the dimension of the SCI subspace won’t exceed `max_dim_a * max_dim_b`. + * A single integer specifying a limit that will be used for both the spin-alpha and spin-beta sectors. In this case, the dimension of the SCI subspace won’t exceed `max_dim**2`. + * `None`, in which case no limit is set. + + Note that the dimension limit is set on the spin-sector(s), while the full dimension of the SCI subspace is the product of the dimensions of the individual spin sectors. + + * **include\_configurations** ([*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*] |* [*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*],* [*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*]] |* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) *| None*) – Configurations to always include in the diagonalization subspace. You can specify either a single list of single-spin strings to use for both spin sectors, or a pair (alpha\_strings, beta\_strings) of lists of single-spin strings, one for each spin. + + * **initial\_occupancies** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*] | None*) – Initial guess for the average occupancies of the orbitals. + + * **carryover\_threshold** ([*float*](https://docs.python.org/3/library/functions.html#float)) – Threshold for carrying over bitstrings with large CI weight from one iteration of configuration recovery to the next. All single-spin CI strings associated with configurations whose coefficient has absolute value greater than this threshold will be included in the diagonalization subspace for the next iteration. A smaller threshold will retain more configurations, leading to a larger subspace and hence a more costly diagonalization. + + * **callback** ([*Callable*](https://docs.python.org/3/library/typing.html#typing.Callable)*\[\[*[*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[SCIResult]], None] | None*) – A callback function to be called after each configuration recovery iteration. The function will be passed the output of the sci\_solver function, which is a list of (energy, sci\_state, occupancies) triplets, where each triplet contains the result of a diagonalization. + + * **seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed for the pseudorandom number generator. + + **Returns** + + The estimate of the energy and the SCI state with that energy. + + **Return type** + + *SCIResult* + + +### enlarge\_batch\_from\_transitions + + + Apply the set of transition operators to the configurations represented in `bitstring_matrix`. + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. + * **transition\_operators** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 1D or 2D array `I`, `+`, `-`, and `n` strings representing the action of the identity, creation, annihilation, or number operators. Each row represents a transition operator. + + **Returns** + + Bitstring matrix representing the augmented set of electronic configurations after applying the excitation operators. + + **Return type** + + [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) + + +### solve\_fermion + + + Approximate the ground state given molecular integrals and a set of electronic configurations. + + **Parameters** + + * **bitstring\_matrix** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*] |* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – + + A set of configurations defining the subspace onto which the Hamiltonian will be projected and diagonalized. + + This may be specified in two ways: + + * Bitstring matrix: A 2D `numpy.ndarray` of `bool` values, where each row represents a bitstring. The spin-up configurations should occupy column indices `(N, N/2]`, and the spin-down configurations should occupy column indices `(N/2, 0]`, where `N` is the number of qubits. + * CI strings: A tuple of two sequences containing integer representations of spin-up and spin-down determinants, respectively. The expected format is `([a_str_0, ..., a_str_N], [b_str_0, ..., b_str_M])`. + + * **hcore** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Core Hamiltonian matrix representing single-electron integrals + + * **eri** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Electronic repulsion integrals representing two-electron integrals + + * **open\_shell** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – A flag specifying whether configurations from the left and right halves of the bitstrings should be kept separate. If `False`, CI strings from the left and right halves of the bitstrings are combined into a single set of unique configurations and used for both the alpha and beta subspaces. + + * **spin\_sq** ([*float*](https://docs.python.org/3/library/functions.html#float) *| None*) – Target value for the total spin squared for the ground state, $S^2 = s(s + 1)$. If `None`, no spin will be imposed. + + * **shift** ([*float*](https://docs.python.org/3/library/functions.html#float)) – Level shift for states which have different spin. $(H + shift * S^2)|ψ> = E|ψ>$ + + * **\*\*kwargs** – Keyword arguments to pass to [pyscf.fci.selected\_ci.kernel\_fixed\_space](https://pyscf.org/pyscf_api_docs/pyscf.fci.html#pyscf.fci.selected_ci.kernel_fixed_space) + + **Returns** + + * Minimum energy from SCI calculation + * The SCI ground state + * Tuple containing orbital occupancies for spin-up and spin-down orbitals. Formatted as: `(array([occ_a_0, ..., occ_a_N]), array([occ_b_0, ..., occ_b_N]))` + * Expectation value of spin-squared + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[float](https://docs.python.org/3/library/functions.html#float), [*SCIState*](#qiskit_addon_sqd.fermion.SCIState "qiskit_addon_sqd.fermion.SCIState"), [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)], [float](https://docs.python.org/3/library/functions.html#float)] + + +### solve\_sci + + + Diagonalize Hamiltonian in subspace defined by CI strings. + + **Parameters** + + * **ci\_strings** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*]*) – Pair (strings\_a, strings\_b) of arrays of spin-alpha CI strings and spin-beta CI strings whose Cartesian product give the basis of the subspace in which to perform a diagonalization. + + * **one\_body\_tensor** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – The one-body tensor of the Hamiltonian. + + * **two\_body\_tensor** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – The two-body tensor of the Hamiltonian. + + * **norb** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of spatial orbitals. + + * **nelec** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*]*) – The numbers of alpha and beta electrons. + + * **spin\_sq** ([*float*](https://docs.python.org/3/library/functions.html#float) *| None*) – Target value for the total spin squared for the ground state. If `None`, no spin will be imposed. + + * **\*\*kwargs** – + + Keyword arguments to pass to [pyscf.fci.selected\_ci.kernel\_fixed\_space](https://pyscf.org/pyscf_api_docs/pyscf.fci.html#pyscf.fci.selected_ci.kernel_fixed_space) + + **Returns** + + The diagonalization result. + + **Return type** + + *SCIResult* + + +### solve\_sci\_batch + + + Diagonalize Hamiltonian in subspaces. + + **Parameters** + + * **ci\_strings** ([*list*](https://docs.python.org/3/library/stdtypes.html#list)*\[*[*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*]]*) – List of pairs (strings\_a, strings\_b) of arrays of spin-alpha CI strings and spin-beta CI strings whose Cartesian product give the basis of the subspace in which to perform a diagonalization. + + * **one\_body\_tensor** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – The one-body tensor of the Hamiltonian. + + * **two\_body\_tensor** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – The two-body tensor of the Hamiltonian. + + * **norb** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of spatial orbitals. + + * **nelec** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*int*](https://docs.python.org/3/library/functions.html#int)*,* [*int*](https://docs.python.org/3/library/functions.html#int)*]*) – The numbers of alpha and beta electrons. + + * **spin\_sq** ([*float*](https://docs.python.org/3/library/functions.html#float) *| None*) – Target value for the total spin squared for the ground state. If `None`, no spin will be imposed. + + * **\*\*kwargs** – + + Keyword arguments to pass to [pyscf.fci.selected\_ci.kernel\_fixed\_space](https://pyscf.org/pyscf_api_docs/pyscf.fci.html#pyscf.fci.selected_ci.kernel_fixed_space) + + **Returns** + + The results of the diagonalizations in the subspaces given by ci\_strings. + + **Return type** + + [list](https://docs.python.org/3/library/stdtypes.html#list)\[*SCIResult*] + + +### optimize\_orbitals + + + Optimize orbitals to produce a minimal ground state. + + The process involves iterating over 3 steps: + + **For `num_iters` iterations:** + + * Rotate the integrals with respect to the parameters, `k_flat` + * Diagonalize and approximate the groundstate energy and wavefunction amplitudes + * Optimize `k_flat` using gradient descent and the wavefunction amplitudes found in Step 2 + + Refer to [Sec. II A 4](https://arxiv.org/pdf/2405.05068) for more detailed discussion on this orbital optimization technique. + + **Parameters** + + * **bitstring\_matrix** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*] |* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – + + A set of configurations defining the subspace onto which the Hamiltonian will be projected and diagonalized. + + This may be specified in two ways: + + * Bitstring matrix: A 2D `numpy.ndarray` of `bool` values, where each row represents a bitstring. The spin-up configurations should occupy column indices `(N, N/2]`, and the spin-down configurations should occupy column indices `(N/2, 0]`, where `N` is the number of qubits. + * CI strings: A tuple of two sequences containing integer representations of spin-up and spin-down determinants, respectively. The expected format is `([a_str_0, ..., a_str_N], [b_str_0, ..., b_str_M])`. + + * **hcore** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Core Hamiltonian matrix representing single-electron integrals + + * **eri** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Electronic repulsion integrals representing two-electron integrals + + * **k\_flat** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – 1D array defining the orbital transform, `K`. The array should specify the upper triangle of the anti-symmetric transform operator in row-major order, excluding the diagonal. + + * **open\_shell** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – A flag specifying whether configurations from the left and right halves of the bitstrings should be kept separate. If `False`, CI strings from the left and right halves of the bitstrings are combined into a single set of unique configurations and used for both the alpha and beta subspaces. + + * **spin\_sq** ([*float*](https://docs.python.org/3/library/functions.html#float)) – Target value for the total spin squared for the ground state + + * **num\_iters** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of iterations of orbital optimization to perform + + * **num\_steps\_grad** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of steps of gradient descent to perform during each optimization iteration + + * **learning\_rate** ([*float*](https://docs.python.org/3/library/functions.html#float)) – The learning rate to use during gradient descent + + * **\*\*kwargs** – + + Keyword arguments to pass to [pyscf.fci.selected\_ci.kernel\_fixed\_space](https://pyscf.org/pyscf_api_docs/pyscf.fci.html#pyscf.fci.selected_ci.kernel_fixed_space) + + **Returns** + + * The groundstate energy found during the last optimization iteration + * An optimized 1D array defining the orbital transform + * Tuple containing orbital occupancies for spin-up and spin-down orbitals. Formatted as: `(array([occ_a_0, ..., occ_a_N]), array([occ_b_0, ..., occ_b_N]))` + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[float](https://docs.python.org/3/library/functions.html#float), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)]] + + +### rotate\_integrals + + + Perform a similarity transform on the integrals. + + The transformation is described as: + +$$ +\hat{\widetilde{H}} = \hat{U^{\dagger}}(k)\hat{H}\hat{U}(k) +$$ + + For more information on how $\hat{U}$ and $\hat{U^{\dagger}}$ are generated from `k_flat` and applied to the one- and two-body integrals, refer to [Sec. II A 4](https://arxiv.org/pdf/2405.05068). + + **Parameters** + + * **hcore** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Core Hamiltonian matrix representing single-electron integrals + * **eri** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Electronic repulsion integrals representing two-electron integrals + * **k\_flat** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – 1D array defining the orbital transform, `K`. The array should specify the upper triangle of the anti-symmetric transform operator in row-major order, excluding the diagonal. + + **Returns** + + * The rotated core Hamiltonian matrix + * The rotated ERI matrix + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + diff --git a/docs/api/qiskit-addon-sqd/0.12/index.mdx b/docs/api/qiskit-addon-sqd/0.12/index.mdx new file mode 100644 index 00000000000..bc7070e827d --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/index.mdx @@ -0,0 +1,15 @@ +--- +title: Sample-based quantum diagonalization (SQD) API documentation (v0.12) +description: Index of all the modules in qiskit-addon-sqd v0.12. +--- + + + +# `qiskit-addon-sqd` API reference + +* [Configuration recovery (`qiskit_addon_sqd.configuration_recovery`)](configuration-recovery) +* [Counts (`qiskit_addon_sqd.counts`)](counts) +* [Fermion (`qiskit_addon_sqd.fermion`)](fermion) +* [Qubit (`qiskit_addon_sqd.qubit`)](qubit) +* [Subsampling (`qiskit_addon_sqd.subsampling`)](subsampling) + diff --git a/docs/api/qiskit-addon-sqd/0.12/qubit.mdx b/docs/api/qiskit-addon-sqd/0.12/qubit.mdx new file mode 100644 index 00000000000..3aeb5c19b3d --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/qubit.mdx @@ -0,0 +1,144 @@ +--- +title: qubit (v0.12) +description: API reference for qiskit_addon_sqd.qubit in qiskit-addon-sqd v0.12 +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_sqd.qubit +--- + + + + + +# Qubit + +`qiskit_addon_sqd.qubit` + +Functions for handling quantum samples. + +### solve\_qubit + + + Find the energies and eigenstates of a Hamiltonian projected into a subspace. + + The subspace is defined by a collection of computational basis states which are specified by the bitstrings (rows) in the `bitstring_matrix`. The `bitstring_matrix` will be sorted and de-duplicated in this function, as the underlying solver requires that structure. + + This function calls [scipy.sparse.linalg.eigsh](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.eigsh.html#eigsh) for the diagonalization. + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. This set of bitstrings specifies the subspace into which the `hamiltonian` will be projected and diagonalized. + + * **hamiltonian** ([*SparsePauliOp*](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp)) – A Hamiltonian specified as a Pauli operator. + + * **verbose** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – Whether to print the stage of the subroutine. + + * **\*\*scipy\_kwargs** – + + Keyword arguments to be passed to [scipy.sparse.linalg.eigsh](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.eigsh.html#eigsh). + + **Returns** + + * 1D array with the eigenvalues + * 2D array with the eigenvectors. Each column represents an eigenvector. + + **Raises** + + [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Bitstrings (rows) in `bitstring_matrix` must have length \< `64`. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + +### project\_operator\_to\_subspace + + + Project a Pauli operator onto a Hilbert subspace defined by the computational basis states (rows) in `bitstring_matrix`. + + The output sparse matrix, `A`, represents an `NxN` matrix s.t. `N` is the number of rows in `bitstring_matrix`. The rows of `A` represent the input configurations, and the columns represent the connected component associated with the configuration in the corresponding row. The non-zero elements of the matrix represent the complex amplitudes associated with the connected components. + + + The bitstrings in the `bitstring_matrix` must be unique and sorted in ascending order according to their unsigned integer representation. Otherwise the projection will return wrong results. This function does not explicitly check for uniqueness and order because this can be rather time consuming. See [`qiskit_addon_sqd.qubit.sort_and_remove_duplicates()`](#qiskit_addon_sqd.qubit.sort_and_remove_duplicates "qiskit_addon_sqd.qubit.sort_and_remove_duplicates") for a simple way to ensure your bitstring matrix is well-formatted. + + + + This function relies on `jax` to efficiently perform some calculations. `jax` converts the bit arrays to `int64_t`, which means the bit arrays in `bitstring_matrix` may not have length greater than `63`. + + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. This set of bitstrings specifies the subspace into which the `hamiltonian` will be projected and diagonalized. + * **hamiltonian** ([*SparsePauliOp*](/docs/api/qiskit/qiskit.quantum_info.SparsePauliOp)) – A Pauli operator to project onto a Hilbert subspace defined by `bitstring_matrix`. + * **verbose** ([*bool*](https://docs.python.org/3/library/functions.html#bool)) – Whether to print the stage of the subroutine. + + **Returns** + + A [scipy.sparse.coo\_matrix](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.coo_matrix.html#coo-matrix) representing the operator projected in the subspace. The rows represent the input configurations, and the columns represent the connected component associated with the configuration in the corresponding row. The non-zero elements of the matrix represent the complex amplitudes associated with the pairs of connected components. + + **Raises** + + [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Bitstrings (rows) in `bitstring_matrix` must have length \< `64`. + + **Return type** + + *spmatrix* + + +### sort\_and\_remove\_duplicates + + + Sort a bitstring matrix and remove duplicate entries. + + The lowest bitstring values will be placed in the lowest-indexed rows. + + **Parameters** + + **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. + + **Returns** + + Sorted version of `bitstring_matrix` without repeated rows. + + **Return type** + + [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray) + + +### matrix\_elements\_from\_pauli + + + Find the sparse matrix elements of a Pauli operator in the subspace defined by the bitstrings. + + The sparse matrix, `A`, defined by the outputs represents an `NxN` matrix s.t. `N` is the number of rows in `bitstring_matrix`. The rows of `A` represent the input configurations, and the columns represent the connected component associated with the configuration in the corresponding row. The output arrays define the sparse matrix, `A`, as follows: + + `A[rows[k], cols[k]] = amplutides[k]`. + + + The bitstrings in the `bitstring_matrix` must be unique and sorted in ascending order according to their unsigned integer representation. Otherwise the projection will return wrong results. This function does not explicitly check for uniqueness and order because this can be rather time consuming. See [`qiskit_addon_sqd.qubit.sort_and_remove_duplicates()`](#qiskit_addon_sqd.qubit.sort_and_remove_duplicates "qiskit_addon_sqd.qubit.sort_and_remove_duplicates") for a simple way to ensure your bitstring matrix is well-formatted. + + + + This function relies on `jax` to efficiently perform some calculations. `jax` converts the bit arrays to `int64_t`, which means the bit arrays in `bitstring_matrix` may not have length greater than `63`. + + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. The bitstrings in the matrix must be sorted according to their unsigned integer representations. Otherwise the projection will return wrong results. + * **pauli** ([*Pauli*](/docs/api/qiskit/qiskit.quantum_info.Pauli)) – A Pauli operator for which to find connected elements + + **Returns** + + * The complex amplitudes corresponding to the nonzero matrix elements + * The row indices corresponding to non-zero matrix elements + * The column indices corresponding to non-zero matrix elements + + **Raises** + + [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Bitstrings (rows) in `bitstring_matrix` must have length \< `64`. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + diff --git a/docs/api/qiskit-addon-sqd/0.12/subsampling.mdx b/docs/api/qiskit-addon-sqd/0.12/subsampling.mdx new file mode 100644 index 00000000000..5ded9f34353 --- /dev/null +++ b/docs/api/qiskit-addon-sqd/0.12/subsampling.mdx @@ -0,0 +1,112 @@ +--- +title: subsampling (v0.12) +description: API reference for qiskit_addon_sqd.subsampling in qiskit-addon-sqd v0.12 +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_sqd.subsampling +--- + + + + + +# Subsampling + +`qiskit_addon_sqd.subsampling` + +Functions for creating batches of samples from a bitstring matrix. + +### subsample + + + Subsample batches of bit arrays from an input `bitstring_matrix`. + + Each individual batch will be sampled without replacement from the input `bitstring_matrix`. Samples will be replaced after creation of each batch, so different batches may contain identical samples. + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. + * **probabilities** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 1D array specifying a probability distribution over the bitstrings + * **samples\_per\_batch** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of samples to draw for each batch + * **num\_batches** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of batches to generate + * **rand\_seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed to control random behavior + + **Returns** + + A list of bitstring matrices subsampled from the input bitstring matrix. + + **Raises** + + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – The number of elements in `probabilities` must equal the number of rows in `bitstring_matrix`. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Samples per batch and number of batches must be positive integers. + + **Return type** + + [list](https://docs.python.org/3/library/stdtypes.html#list)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + +### postselect\_and\_subsample + + + Subsample batches of bit arrays with correct hamming weight from an input `bitstring_matrix`. + + Bitstring samples with incorrect hamming weight on either their left or right half will not be sampled. + + Each individual batch will be sampled without replacement from the input `bitstring_matrix`. Samples will be replaced after creation of each batch, so different batches may contain identical samples. + + + The function `qiskit_addon_sqd.subsampling.postselect_and_subsample()` is deprecated as of qiskit-addon-sqd 0.12.0. It will be removed no earlier than v0.13.0. Instead, use the `postselect_by_hamming_right_and_left` and `subsample` functions. + + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. + * **probabilities** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 1D array specifying a probability distribution over the bitstrings + * **hamming\_right** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The target hamming weight for the right half of sampled bitstrings + * **hamming\_left** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The target hamming weight for the left half of sampled bitstrings + * **samples\_per\_batch** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of samples to draw for each batch + * **num\_batches** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The number of batches to generate + * **rand\_seed** ([*Generator*](https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator) *|*[*int*](https://docs.python.org/3/library/functions.html#int) *| None*) – A seed to control random behavior + + **Returns** + + A list of bitstring matrices with correct hamming weight subsampled from the input bitstring matrix + + **Raises** + + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – The number of elements in `probabilities` must equal the number of rows in `bitstring_matrix`. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Hamming weights must be non-negative integers. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Samples per batch and number of batches must be positive integers. + + **Return type** + + [list](https://docs.python.org/3/library/stdtypes.html#list)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + +### postselect\_by\_hamming\_right\_and\_left + + + Postselect bitstrings based on desired Hamming weight on right and left halves. + + **Parameters** + + * **bitstring\_matrix** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 2D array of `bool` representations of bit values such that each row represents a single bitstring. + * **probabilities** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – A 1D array specifying a probability distribution over the bitstrings + * **hamming\_right** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The target hamming weight for the right half of sampled bitstrings + * **hamming\_left** ([*int*](https://docs.python.org/3/library/functions.html#int)) – The target hamming weight for the left half of sampled bitstrings + + **Returns** + + Postselected bitstring matrix and probabilities. The new bitstring matrix contains only those bitstrings from the original matrix that have the desired Hamming weight on the right and left halves, and the new probabilities are constructed by taking the original probabilities corresponding to the postselected bitstrings and rescaling them to sum to one. + + **Raises** + + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – Hamming weights must be non-negative integers. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – The number of columns in `bitstring_matrix` must be even. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError) – The number of elements in `probabilities` must equal the number of rows in `bitstring_matrix`. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple)\[[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray), [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)] + + diff --git a/public/docs/api/qiskit-addon-sqd/0.12/objects.inv b/public/docs/api/qiskit-addon-sqd/0.12/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..73d11ceaed44a17e32a19e895aaeb6867e232661 GIT binary patch literal 1805 zcmV+o2lDtMAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkWX>)67 zbRc15WN&UdAah}DaBO8QVqtS-WFT>MVQzGFZ6IW6VP|h{VQgu7VRUJ4ZXhUAQA8;U zBOq2~a&u{KZaN?eBOp|0Wgv28ZDDC{WMy(7Z)PBLXlZjGW@&6?AZc?TV{dJ6a%FRK zWn>_Ab7^j8AbMR%3USW)Z@|mfBn9gxo3ZAQTxg&xf*s+yZGr@C7iFl{- zf||?MT9j=?(Qjx3$$H3xvuB@C_UW9)x@&~exuO*%IxjBy3D-5_$NXQ)jwfwm9$HR} z3wjPkjZ>sc>3-xRvr5wt@CAdnT&tVjG)*(TXCS-6G)jptxfbrnRG;O7fMHs9nd6+G z!h}c4sl=M*R~;>92O(>iI)YCK(g`bAgQaGg_CsJMR?sayWLi=;;4nQGvc?trHMo?F zXqX&^0@Md8Yvbt;xUMZa;yTQ3|MI%mSW`nlDy$TG9{d$y%GwhAcerjUrrVO*;f1x9 ztY|g$=sZLUAz``FQsp?rcLgk=E9U5mB)UrA(snx4CsBGd){w%$&6E}rqD01?LgIRTj;ccegy*(kdi3(JEzwtpMeMrKOem{2fC)FBwgb<@xj6IS0IA(1-Ayv!x7#XHT*wy7AwnyLV2 z5DtVeIoP+STl5U~%4?6_F%M@~^>tQ zB|Sf%FSuc)AnFU_CH=XRN+YGquN5w6g|cU4n~@8d*^rq!m+1GmS0w3yO3DcZNFHuI zGTg9i@Bm`Wd8A56-W}a$3h#u_i{Fff=EuZ1Pj@Nn2X~@NN+L@s|DU|K*=DD7N1S03 z9Ut2Tfh~GU?g7_zk)zq#?I7^T*|UQecXJtZ+m#{d{)lT+ znmPUe^O^CvGuGNnrpGLx_$e%%ajnG3sST)bf=cFFt8X|l2XzhB+2hKsboi(8pd`<} zHby1gQ+87xS-C9jz|`x}*3zVyw~bSFr%8zImQuoseMZ3)B@vFXoS^ z_G?Cy$I~yr?Y-ZRF`B3JXu+q@4;)gIek5_PGD??a3p0ASWRdtec_1NE6Tt(-fH&)U}K_1$Q59O&;)$&bPmK|M(;& zZ6qbGq}7OukqblxpuSz3(3@@YX<7LU@tEd6`!e&WgDOTSS70r>H~rzRzL)YwK-P_b z>}CYm`ZhqD?0erZQx~OaohkNOBt5rGy7dL9Zh`yWVv)rn%u6)F zA|LB3)F%pz>5QpNQJpbfGD(T9zyXo$``3vA&jw-&DXP&GXoM+^s|tG9tpUBdtLtym zC|jcY2W{|u=zeEr(UvurhJkDVtm8+f1-)I~UL(9pv~v381;E?^N8GLrWOt*^Pc9k* zfG74+BdHx1icOYIeT*^W&HwMy=o=O5UJ8=@iOa%DzR&+rAC}Biz{V2N3fgm v6)3)T_DPerVJR Date: Fri, 14 Aug 2026 12:22:20 -0400 Subject: [PATCH 3/8] update latest docs --- docs/api/qiskit-addon-sqd/_package.json | 2 +- docs/api/qiskit-addon-sqd/_toc.json | 4 +- .../configuration-recovery.mdx | 4 +- docs/api/qiskit-addon-sqd/counts.mdx | 12 +- docs/api/qiskit-addon-sqd/fermion.mdx | 58 +++++--- docs/api/qiskit-addon-sqd/qubit.mdx | 8 +- docs/api/qiskit-addon-sqd/release-notes.mdx | 128 +++++++++++------- docs/api/qiskit-addon-sqd/subsampling.mdx | 6 +- public/docs/api/qiskit-addon-sqd/objects.inv | Bin 3063 -> 3158 bytes 9 files changed, 134 insertions(+), 88 deletions(-) diff --git a/docs/api/qiskit-addon-sqd/_package.json b/docs/api/qiskit-addon-sqd/_package.json index 1f226e87545..2e769efbf10 100644 --- a/docs/api/qiskit-addon-sqd/_package.json +++ b/docs/api/qiskit-addon-sqd/_package.json @@ -1,4 +1,4 @@ { "name": "qiskit-addon-sqd", - "version": "0.12.1" + "version": "0.13.1" } diff --git a/docs/api/qiskit-addon-sqd/_toc.json b/docs/api/qiskit-addon-sqd/_toc.json index ed5c0c5b297..0b5a0466148 100644 --- a/docs/api/qiskit-addon-sqd/_toc.json +++ b/docs/api/qiskit-addon-sqd/_toc.json @@ -37,5 +37,7 @@ } ], "collapsed": true, - "untranslatable": true + "untranslatable": true, + "parentUrl": "/docs/addons/qiskit-addon-sqd", + "parentLabel": "Sample-based quantum diagonalization (SQD)" } diff --git a/docs/api/qiskit-addon-sqd/configuration-recovery.mdx b/docs/api/qiskit-addon-sqd/configuration-recovery.mdx index d5652c9c554..73ce1b2b0ff 100644 --- a/docs/api/qiskit-addon-sqd/configuration-recovery.mdx +++ b/docs/api/qiskit-addon-sqd/configuration-recovery.mdx @@ -18,7 +18,7 @@ Functions for performing self-consistent configuration recovery. ### post\_select\_by\_hamming\_weight - + Post-select bitstrings based on the hamming weight of each half. @@ -42,7 +42,7 @@ Functions for performing self-consistent configuration recovery. ### recover\_configurations - + Refine bitstrings based on average orbital occupancy and a target hamming weight. This function refines each bit in isolation in an attempt to transform the Hilbert space represented by the input `bitstring_matrix` into a space closer to that which supports the ground state. diff --git a/docs/api/qiskit-addon-sqd/counts.mdx b/docs/api/qiskit-addon-sqd/counts.mdx index 6c1f0f4a5a3..88f608f2c13 100644 --- a/docs/api/qiskit-addon-sqd/counts.mdx +++ b/docs/api/qiskit-addon-sqd/counts.mdx @@ -18,7 +18,7 @@ Functions for transforming counts dictionaries. ### counts\_to\_arrays - + Convert a counts dictionary into a bitstring matrix and a probability array. **Parameters** @@ -37,7 +37,7 @@ Functions for transforming counts dictionaries. ### generate\_counts\_uniform - + Generate a bitstring counts dictionary of samples drawn from the uniform distribution. **Parameters** @@ -61,7 +61,7 @@ Functions for transforming counts dictionaries. ### generate\_counts\_bipartite\_hamming - + Generate a bitstring counts dictionary with specified bipartite hamming weight. **Parameters** @@ -89,7 +89,7 @@ Functions for transforming counts dictionaries. ### normalize\_counts\_dict - + Convert a counts dictionary into a probability dictionary. **Parameters** @@ -103,7 +103,7 @@ Functions for transforming counts dictionaries. ### bit\_array\_to\_arrays - + Convert a bit array into a bitstring matrix and a probability array. **Parameters** @@ -122,7 +122,7 @@ Functions for transforming counts dictionaries. ### generate\_bit\_array\_uniform - + Generate a bit array of samples drawn from the uniform distribution. **Parameters** diff --git a/docs/api/qiskit-addon-sqd/fermion.mdx b/docs/api/qiskit-addon-sqd/fermion.mdx index 76e559beff4..5cca52923fc 100644 --- a/docs/api/qiskit-addon-sqd/fermion.mdx +++ b/docs/api/qiskit-addon-sqd/fermion.mdx @@ -18,7 +18,7 @@ Functions for the study of fermionic systems. ### SCIState - + Bases: [`object`](https://docs.python.org/3/library/functions.html#object) The amplitudes and determinants describing a quantum state. @@ -33,43 +33,43 @@ Functions for the study of fermionic systems. #### amplitudes - + An $M \times N$ array where $M =$ len(`ci_strs_a`) and $N$ = len(`ci_strs_b`). `amplitudes[i][j]` is the amplitude of the determinant pair (`ci_strs_a[i]`, `ci_strs_b[j]`). #### ci\_strs\_a - + The alpha determinants. #### ci\_strs\_b - + The beta determinants. #### load - + Load an SCIState object from an .npz file. #### nelec - + The numbers of alpha and beta electrons. #### norb - + The number of spatial orbitals. #### orbital\_occupancies - + Average orbital occupancies. **Return type** @@ -79,7 +79,7 @@ Functions for the study of fermionic systems. #### rdm - + Compute reduced density matrix. **Parameters** @@ -94,13 +94,13 @@ Functions for the study of fermionic systems. #### save - + Save the SCIState object to an .npz file. #### spin\_square - + Return spin squared. **Return type** @@ -111,7 +111,7 @@ Functions for the study of fermionic systems. ### bitstring\_matrix\_to\_ci\_strs - + Convert bitstrings (rows) in a `bitstring_matrix` into integer representations of determinants. This function separates each bitstring in `bitstring_matrix` in half, translates them into integer representations, and finally appends them to their respective (spin-up or spin-down) lists. Those lists are sorted and output from this function. @@ -132,7 +132,7 @@ Functions for the study of fermionic systems. ### diagonalize\_fermionic\_hamiltonian - + Run the sample-based quantum diagonalization (SQD) algorithm. **Parameters** @@ -200,11 +200,23 @@ Functions for the study of fermionic systems. **Return type** *SCIResult* + + + This function supports collective multi-process (SPMD) execution using MPI, with a single thread controlling each process (`MPI_THREAD_FUNNELED` or lower). When it is invoked collectively from all processes, the arguments must agree across processes, and the following semantics apply: + + * The `sci_solver` step is the only collective operation: all processes participate in it, so an `sci_solver` implementation can distribute work across every process. The remaining steps of the configuration-recovery loop (preparing the CI strings, processing the diagonalization results, and checking convergence) have no distributed implementation and are performed on the control process alone. + * The `callback`, if provided, is invoked on the control process only. + * The return value is the same on every process: the final result is broadcast from the control process to all ranks. + + Whether the calling program should be launched under MPI depends on the `sci_solver` in use. A collective `sci_solver`, as described above, expects the program to run collectively across all processes. Other implementations require the calling program to run as a single process, outside any MPI/SPMD environment. Some of these implementations might manage their own parallelism internally, for example, by launching `mpirun` themselves. The default `sci_solver` is not distributed and falls into this latter category. + + A collective `sci_solver` implementation is not required to raise an exception on a single process when it encounters an error; instead, it can follow fail-stop semantics for the execution context as a whole, aborting all processes collectively. (This describes what such an implementation is permitted to do, not the behavior of the default `sci_solver`.) + ### enlarge\_batch\_from\_transitions - + Apply the set of transition operators to the configurations represented in `bitstring_matrix`. **Parameters** @@ -223,7 +235,7 @@ Functions for the study of fermionic systems. ### solve\_fermion - + Approximate the ground state given molecular integrals and a set of electronic configurations. **Parameters** @@ -263,7 +275,7 @@ Functions for the study of fermionic systems. ### solve\_sci - + Diagonalize Hamiltonian in subspace defined by CI strings. **Parameters** @@ -295,7 +307,7 @@ Functions for the study of fermionic systems. ### solve\_sci\_batch - + Diagonalize Hamiltonian in subspaces. **Parameters** @@ -327,7 +339,7 @@ Functions for the study of fermionic systems. ### optimize\_orbitals - + Optimize orbitals to produce a minimal ground state. The process involves iterating over 3 steps: @@ -340,6 +352,10 @@ Functions for the study of fermionic systems. Refer to [Sec. II A 4](https://arxiv.org/pdf/2405.05068) for more detailed discussion on this orbital optimization technique. + + The function `qiskit_addon_sqd.fermion.optimize_orbitals()` is deprecated as of qiskit-addon-sqd 0.13.0. It will be removed no earlier than v0.15.0. Orbital optimization is now supported by the ffsim package. See [/addons/qiskit-addon-sqd/guides/optimize-orbitals](/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals) for a guide on how to optimize the Hamiltonian basis with ffsim. + + **Parameters** * **bitstring\_matrix** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple)*\[*[*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*,* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)*] |* [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – @@ -384,7 +400,7 @@ Functions for the study of fermionic systems. ### rotate\_integrals - + Perform a similarity transform on the integrals. The transformation is described as: @@ -395,6 +411,10 @@ $$ For more information on how $\hat{U}$ and $\hat{U^{\dagger}}$ are generated from `k_flat` and applied to the one- and two-body integrals, refer to [Sec. II A 4](https://arxiv.org/pdf/2405.05068). + + The function `qiskit_addon_sqd.fermion.rotate_integrals()` is deprecated as of qiskit-addon-sqd 0.13.0. It will be removed no earlier than v0.15.0. Orbital optimization is now supported by the ffsim package. See [/addons/qiskit-addon-sqd/guides/optimize-orbitals](/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals) for a guide on how to optimize the Hamiltonian basis with ffsim. + + **Parameters** * **hcore** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray)) – Core Hamiltonian matrix representing single-electron integrals diff --git a/docs/api/qiskit-addon-sqd/qubit.mdx b/docs/api/qiskit-addon-sqd/qubit.mdx index 0ac75174753..a96e7293ee4 100644 --- a/docs/api/qiskit-addon-sqd/qubit.mdx +++ b/docs/api/qiskit-addon-sqd/qubit.mdx @@ -18,7 +18,7 @@ Functions for handling quantum samples. ### solve\_qubit - + Find the energies and eigenstates of a Hamiltonian projected into a subspace. The subspace is defined by a collection of computational basis states which are specified by the bitstrings (rows) in the `bitstring_matrix`. The `bitstring_matrix` will be sorted and de-duplicated in this function, as the underlying solver requires that structure. @@ -53,7 +53,7 @@ Functions for handling quantum samples. ### project\_operator\_to\_subspace - + Project a Pauli operator onto a Hilbert subspace defined by the computational basis states (rows) in `bitstring_matrix`. The output sparse matrix, `A`, represents an `NxN` matrix s.t. `N` is the number of rows in `bitstring_matrix`. The rows of `A` represent the input configurations, and the columns represent the connected component associated with the configuration in the corresponding row. The non-zero elements of the matrix represent the complex amplitudes associated with the connected components. @@ -87,7 +87,7 @@ Functions for handling quantum samples. ### sort\_and\_remove\_duplicates - + Sort a bitstring matrix and remove duplicate entries. The lowest bitstring values will be placed in the lowest-indexed rows. @@ -107,7 +107,7 @@ Functions for handling quantum samples. ### matrix\_elements\_from\_pauli - + Find the sparse matrix elements of a Pauli operator in the subspace defined by the bitstrings. The sparse matrix, `A`, defined by the outputs represents an `NxN` matrix s.t. `N` is the number of rows in `bitstring_matrix`. The rows of `A` represent the input configurations, and the columns represent the connected component associated with the configuration in the corresponding row. The output arrays define the sparse matrix, `A`, as follows: diff --git a/docs/api/qiskit-addon-sqd/release-notes.mdx b/docs/api/qiskit-addon-sqd/release-notes.mdx index cf531e2f271..ba5d4f59ed9 100644 --- a/docs/api/qiskit-addon-sqd/release-notes.mdx +++ b/docs/api/qiskit-addon-sqd/release-notes.mdx @@ -10,10 +10,30 @@ in_page_toc_max_heading_level: 2 # Sample-based quantum diagonalization (SQD) release notes - + +## 0.13.0 + + + +### New Features + +* Added support for Python 3.13 and Python 3.14. No code changes were necessary, so older releases are expected to work on Python 3.13 and 3.14 too. + +* [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") can now be called collectively from all processes of a multi-process (SPMD) execution, for example under MPI. When invoked this way, the `sci_solver` step runs on every process, so a custom, distributed `sci_solver` can spread each diagonalization across the available processes; the rest of the configuration-recovery loop runs on the control process alone, and the return value is the same on every process. Single-process behavior is unchanged. See [Support for multi-process and multi-threaded acceleration](guides/hpc-acceleration) for details on the package’s support for multi-process and multi-threaded acceleration. + + + +### Deprecation Notes + +* The [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") and [`qiskit_addon_sqd.fermion.rotate_integrals()`](/docs/api/qiskit-addon-sqd/fermion#rotate_integrals "qiskit_addon_sqd.fermion.rotate_integrals") functions are now deprecated. Refer to the [orbital optimization guide](/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals) for how to optimize the Hamiltonian basis with the ffsim package instead. + + + + + ## 0.12.1 @@ -24,71 +44,75 @@ in_page_toc_max_heading_level: 2 - + ## 0.12.0 + + ### New Features -* Added the `max_dim` argument to the [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") function. This argument is used to limit the dimension of the SCI subspace. +* Added the `max_dim` argument to the [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") function. This argument is used to limit the dimension of the SCI subspace. -* Introduced the [`qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left()`](subsampling#postselect_by_hamming_right_and_left "qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left") function. +* Introduced the [`qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_by_hamming_right_and_left "qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left") function. - + ### Upgrade Notes -* [`qiskit_addon_sqd.fermion.SCIState`](fermion#scistate "qiskit_addon_sqd.fermion.SCIState") now takes two additional required arguments, `norb` and `nelec`. This is a breaking change. +* [`qiskit_addon_sqd.fermion.SCIState`](/docs/api/qiskit-addon-sqd/fermion#scistate "qiskit_addon_sqd.fermion.SCIState") now takes two additional required arguments, `norb` and `nelec`. This is a breaking change. + + ### Deprecation Notes -* [`qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()`](configuration-recovery#post_select_by_hamming_weight "qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight") is now deprecated. Instead, use [`qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left()`](subsampling#postselect_by_hamming_right_and_left "qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left"). +* [`qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()`](/docs/api/qiskit-addon-sqd/configuration-recovery#post_select_by_hamming_weight "qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight") is now deprecated. Instead, use [`qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_by_hamming_right_and_left "qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left"). -* [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample") is now deprecated. Instead, use [`qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left()`](subsampling#postselect_by_hamming_right_and_left "qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left") and [`qiskit_addon_sqd.subsampling.subsample()`](subsampling#subsample "qiskit_addon_sqd.subsampling.subsample"). +* [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample") is now deprecated. Instead, use [`qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_by_hamming_right_and_left "qiskit_addon_sqd.subsampling.postselect_by_hamming_right_and_left") and [`qiskit_addon_sqd.subsampling.subsample()`](/docs/api/qiskit-addon-sqd/subsampling#subsample "qiskit_addon_sqd.subsampling.subsample"). ### Bug Fixes -* Fixed a bug in [`qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()`](fermion#bitstring_matrix_to_ci_strs "qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs") in which the conversion of bitstrings to CI strings could be incorrect when the number of orbitals is greater than 53. +* Fixed a bug in [`qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()`](/docs/api/qiskit-addon-sqd/fermion#bitstring_matrix_to_ci_strs "qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs") in which the conversion of bitstrings to CI strings could be incorrect when the number of orbitals is greater than 53. -* Fixed a bug in which saving and loading [`qiskit_addon_sqd.fermion.SCIState`](fermion#scistate "qiskit_addon_sqd.fermion.SCIState") objects resulted in an error. +* Fixed a bug in which saving and loading [`qiskit_addon_sqd.fermion.SCIState`](/docs/api/qiskit-addon-sqd/fermion#scistate "qiskit_addon_sqd.fermion.SCIState") objects resulted in an error. -* Added a release note to version 0.11 for a breaking change involving [`qiskit_addon_sqd.fermion.SCIState`](fermion#scistate "qiskit_addon_sqd.fermion.SCIState"). +* Added a release note to version 0.11 for a breaking change involving [`qiskit_addon_sqd.fermion.SCIState`](/docs/api/qiskit-addon-sqd/fermion#scistate "qiskit_addon_sqd.fermion.SCIState"). - + ## 0.11.0 - + ### New Features -* Added a new function [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") to serve as the main entrypoint to the SQD algorithm. See the updated [tutorials](https://qiskit.github.io/qiskit-addon-sqd/tutorials/index.html) for a demonstration of how to use this function. +* Added a new function [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") to serve as the main entrypoint to the SQD algorithm. See the updated [tutorials](/docs/addons/qiskit-addon-sqd/tutorials/index) for a demonstration of how to use this function. -* [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") now accepts a `shift` argument used to shift states which have the wrong spin, $(H + shift * S^2)|ψ> = E|ψ>$. +* [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") now accepts a `shift` argument used to shift states which have the wrong spin, $(H + shift * S^2)|ψ> = E|ψ>$. - + ### Upgrade Notes -* [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") now accept trailing `kwargs`, which will be passed directly to [pyscf.fci.selected\_ci.kernel\_fixed\_space](https://pyscf.org/pyscf_api_docs/pyscf.fci.html#pyscf.fci.selected_ci.kernel_fixed_space) under the hood to calculate the target state. The `max_davidson` argument should now be passed as `max_cycle` in both functions. +* [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") now accept trailing `kwargs`, which will be passed directly to [pyscf.fci.selected\_ci.kernel\_fixed\_space](https://pyscf.org/pyscf_api_docs/pyscf.fci.html#pyscf.fci.selected_ci.kernel_fixed_space) under the hood to calculate the target state. The `max_davidson` argument should now be passed as `max_cycle` in both functions. - + ### Bug Fixes @@ -96,25 +120,25 @@ in_page_toc_max_heading_level: 2 - + ## 0.10.0 - + ### Upgrade Notes -* Removed `qiskit_addon_sqd.fermion.flip_orbital_occupancies()`. Users no longer need to flip the orbital occupancies output from [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals"); they will be output in the order expected by [`qiskit_addon_sqd.configuration_recovery.recover_configurations()`](configuration-recovery#recover_configurations "qiskit_addon_sqd.configuration_recovery.recover_configurations"): `tuple(array([occ_a_0, ..., occ_a_N]), array([occ_b_0, ..., occ_b_N]))`. +* Removed `qiskit_addon_sqd.fermion.flip_orbital_occupancies()`. Users no longer need to flip the orbital occupancies output from [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals"); they will be output in the order expected by [`qiskit_addon_sqd.configuration_recovery.recover_configurations()`](/docs/api/qiskit-addon-sqd/configuration-recovery#recover_configurations "qiskit_addon_sqd.configuration_recovery.recover_configurations"): `tuple(array([occ_a_0, ..., occ_a_N]), array([occ_b_0, ..., occ_b_N]))`. - + ### Deprecation Notes -* The `avg_occupancies` argument to [`qiskit_addon_sqd.configuration_recovery.recover_configurations()`](configuration-recovery#recover_configurations "qiskit_addon_sqd.configuration_recovery.recover_configurations") should now be a length-2 tuple containing the spin-up and spin-down occupancies, respectively. +* The `avg_occupancies` argument to [`qiskit_addon_sqd.configuration_recovery.recover_configurations()`](/docs/api/qiskit-addon-sqd/configuration-recovery#recover_configurations "qiskit_addon_sqd.configuration_recovery.recover_configurations") should now be a length-2 tuple containing the spin-up and spin-down occupancies, respectively. Old format: `array([occ_b_N, ..., occ_b_0, occ_a_N, ..., occ_a_0])` @@ -122,45 +146,45 @@ in_page_toc_max_heading_level: 2 - + ### Bug Fixes -* Fixed a bug which would cause the energy output from [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") to be incorrect when the input `spin_sq` deviates from the spin^2 of the output wavefunction. +* Fixed a bug which would cause the energy output from [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") to be incorrect when the input `spin_sq` deviates from the spin^2 of the output wavefunction. - + ## 0.9.0 - + ### Upgrade Notes -* [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") and [`qiskit_addon_sqd.fermion.rotate_integrals()`](fermion#rotate_integrals "qiskit_addon_sqd.fermion.rotate_integrals") now require `k_flat` to specify the upper triangle (not including diagonal) of the rotation matrix, rather than the entire matrix. +* [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") and [`qiskit_addon_sqd.fermion.rotate_integrals()`](/docs/api/qiskit-addon-sqd/fermion#rotate_integrals "qiskit_addon_sqd.fermion.rotate_integrals") now require `k_flat` to specify the upper triangle (not including diagonal) of the rotation matrix, rather than the entire matrix. - + ### Bug Fixes -* Fixed an indexing error in [`qiskit_addon_sqd.configuration_recovery()`](configuration-recovery#module-qiskit_addon_sqd.configuration_recovery "qiskit_addon_sqd.configuration_recovery") which caused bits in the right half of the bitstring to be flipped with respect to the occupancies of the oritals associated with the left half of the bitstring. +* Fixed an indexing error in [`qiskit_addon_sqd.configuration_recovery()`](/docs/api/qiskit-addon-sqd/configuration-recovery#module-qiskit_addon_sqd.configuration_recovery "qiskit_addon_sqd.configuration_recovery") which caused bits in the right half of the bitstring to be flipped with respect to the occupancies of the oritals associated with the left half of the bitstring. * pyscf is no longer considered a dependency on Windows, where it fails to install. However, Windows remains an unsupported platform. - + ## 0.8.0 - + ### New Features @@ -170,41 +194,41 @@ in_page_toc_max_heading_level: 2 - + ### Upgrade Notes -* The ground state returned by [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") will now be an instance of [`qiskit_addon_sqd.fermion.SCIState`](fermion#scistate "qiskit_addon_sqd.fermion.SCIState"), rather than a PySCF `SCIVector` instance. +* The ground state returned by [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") will now be an instance of [`qiskit_addon_sqd.fermion.SCIState`](/docs/api/qiskit-addon-sqd/fermion#scistate "qiskit_addon_sqd.fermion.SCIState"), rather than a PySCF `SCIVector` instance. - + ## 0.7.0 - + ### Bug Fixes -* Fixed a bug in [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") which causes the determinants for spin-up and spin-down to be incorrectly flipped before solving. +* Fixed a bug in [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") which causes the determinants for spin-up and spin-down to be incorrectly flipped before solving. -* Fixed a bug in open-shell workflows which would cause [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") to crash with a `malloc` error. +* Fixed a bug in open-shell workflows which would cause [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") to crash with a `malloc` error. - + ## 0.6.0 - + ### Upgrade Notes -* Specifying `addresses` as a keyword argument to [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") is no longer supported. Users may still pass `addresses` as the first positional argument; however, this usage is deprecated. Users are encouraged to pass the bitstring matrix defining the subspace as the first positional arguments to these functions, as shown below. +* Specifying `addresses` as a keyword argument to [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") is no longer supported. Users may still pass `addresses` as the first positional argument; however, this usage is deprecated. Users are encouraged to pass the bitstring matrix defining the subspace as the first positional arguments to these functions, as shown below. To upgrade, change this code @@ -251,11 +275,11 @@ in_page_toc_max_heading_level: 2 - + ### Deprecation Notes -* The `qiskit_addon_sqd.fermion.bitstring_matrix_to_sorted_addresses()` function has been deprecated in favor of [`qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()`](fermion#bitstring_matrix_to_ci_strs "qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs"). These two functions behave the same with one key exception – `qiskit_addon_sqd.fermion.bitstring_matrix_to_sorted_addresses()` returns the configurations as `tuple(spin_dn, spin_up)`; whereas, [`qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()`](fermion#bitstring_matrix_to_ci_strs "qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs") returns the configurations as `tuple(spin_up, spin_dn)`. +* The `qiskit_addon_sqd.fermion.bitstring_matrix_to_sorted_addresses()` function has been deprecated in favor of [`qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()`](/docs/api/qiskit-addon-sqd/fermion#bitstring_matrix_to_ci_strs "qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs"). These two functions behave the same with one key exception – `qiskit_addon_sqd.fermion.bitstring_matrix_to_sorted_addresses()` returns the configurations as `tuple(spin_dn, spin_up)`; whereas, [`qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()`](/docs/api/qiskit-addon-sqd/fermion#bitstring_matrix_to_ci_strs "qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs") returns the configurations as `tuple(spin_up, spin_dn)`. To migrate @@ -276,31 +300,31 @@ in_page_toc_max_heading_level: 2 ci_strs_up, ci_strs_dn = bitstring_matrix_to_ci_strs(bs_matrix, open_shell=True) ``` -* The `addresses` argument to [`qiskit_addon_sqd.fermion.solve_fermion()`](fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") has been deprecated in favor of `bitstring_matrix`. Users are no longer required to convert their configurations to integers; instead, they should now pass in the bitstring matrix specifying the subspace onto which to project and diagonalize the Hamiltonian. The conversion to the integer representation of determinants will be done internally. +* The `addresses` argument to [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") and [`qiskit_addon_sqd.fermion.optimize_orbitals()`](/docs/api/qiskit-addon-sqd/fermion#optimize_orbitals "qiskit_addon_sqd.fermion.optimize_orbitals") has been deprecated in favor of `bitstring_matrix`. Users are no longer required to convert their configurations to integers; instead, they should now pass in the bitstring matrix specifying the subspace onto which to project and diagonalize the Hamiltonian. The conversion to the integer representation of determinants will be done internally. - + ### Bug Fixes -* Fixed a bug in [`qiskit_addon_sqd.configuration_recovery.recover_configurations()`](configuration-recovery#recover_configurations "qiskit_addon_sqd.configuration_recovery.recover_configurations") which would sometimes cause a divide-by-zero error when calculating individual bit-flip probability. +* Fixed a bug in [`qiskit_addon_sqd.configuration_recovery.recover_configurations()`](/docs/api/qiskit-addon-sqd/configuration-recovery#recover_configurations "qiskit_addon_sqd.configuration_recovery.recover_configurations") which would sometimes cause a divide-by-zero error when calculating individual bit-flip probability. * Fixes a bug that caused configuration recovery to fail on bitstrings of length greater than 72. - + ## 0.5.0 - + ### Upgrade Notes -* The [`qiskit_addon_sqd.counts.generate_counts_bipartite_hamming()`](counts#generate_counts_bipartite_hamming "qiskit_addon_sqd.counts.generate_counts_bipartite_hamming"), [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample"), and [`qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()`](configuration-recovery#post_select_by_hamming_weight "qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight") now require the `hamming_right` and `hamming_left` arguments to be specified as keyword arguments. Additionally, the `samples_per_batch` and `n_batches` arguments to [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample") should now be passed as keyword arguments. +* The [`qiskit_addon_sqd.counts.generate_counts_bipartite_hamming()`](/docs/api/qiskit-addon-sqd/counts#generate_counts_bipartite_hamming "qiskit_addon_sqd.counts.generate_counts_bipartite_hamming"), [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample"), and [`qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()`](/docs/api/qiskit-addon-sqd/configuration-recovery#post_select_by_hamming_weight "qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight") now require the `hamming_right` and `hamming_left` arguments to be specified as keyword arguments. Additionally, the `samples_per_batch` and `n_batches` arguments to [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample") should now be passed as keyword arguments. To upgrade @@ -354,7 +378,7 @@ in_page_toc_max_heading_level: 2 - + ## 0.4.0 @@ -366,11 +390,11 @@ This is a minor release which introduces a couple of small, but important, break - + ### Upgrade Notes -* The [`qiskit_addon_sqd.counts.generate_counts_bipartite_hamming()`](counts#generate_counts_bipartite_hamming "qiskit_addon_sqd.counts.generate_counts_bipartite_hamming"), [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample"), and [`qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()`](configuration-recovery#post_select_by_hamming_weight "qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight") now take the `hamming_right` positional argument before the `hamming_left` argument to better match the rest of the workflow. +* The [`qiskit_addon_sqd.counts.generate_counts_bipartite_hamming()`](/docs/api/qiskit-addon-sqd/counts#generate_counts_bipartite_hamming "qiskit_addon_sqd.counts.generate_counts_bipartite_hamming"), [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](/docs/api/qiskit-addon-sqd/subsampling#postselect_and_subsample "qiskit_addon_sqd.subsampling.postselect_and_subsample"), and [`qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()`](/docs/api/qiskit-addon-sqd/configuration-recovery#post_select_by_hamming_weight "qiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight") now take the `hamming_right` positional argument before the `hamming_left` argument to better match the rest of the workflow. To upgrade diff --git a/docs/api/qiskit-addon-sqd/subsampling.mdx b/docs/api/qiskit-addon-sqd/subsampling.mdx index c071199dc00..7e10897b032 100644 --- a/docs/api/qiskit-addon-sqd/subsampling.mdx +++ b/docs/api/qiskit-addon-sqd/subsampling.mdx @@ -18,7 +18,7 @@ Functions for creating batches of samples from a bitstring matrix. ### subsample - + Subsample batches of bit arrays from an input `bitstring_matrix`. Each individual batch will be sampled without replacement from the input `bitstring_matrix`. Samples will be replaced after creation of each batch, so different batches may contain identical samples. @@ -47,7 +47,7 @@ Functions for creating batches of samples from a bitstring matrix. ### postselect\_and\_subsample - + Subsample batches of bit arrays with correct hamming weight from an input `bitstring_matrix`. Bitstring samples with incorrect hamming weight on either their left or right half will not be sampled. @@ -85,7 +85,7 @@ Functions for creating batches of samples from a bitstring matrix. ### postselect\_by\_hamming\_right\_and\_left - + Postselect bitstrings based on desired Hamming weight on right and left halves. **Parameters** diff --git a/public/docs/api/qiskit-addon-sqd/objects.inv b/public/docs/api/qiskit-addon-sqd/objects.inv index 6440277abb6e902f8d35764a17c531ff6a94cafd..b5515793b0b52bd0f337f70971d31ced2f5cad2e 100644 GIT binary patch delta 3034 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 delta 2938 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 From 0c936e688fcb3edae2a3981c560419f8d7f3b92c Mon Sep 17 00:00:00 2001 From: ABBY CROSS Date: Fri, 14 Aug 2026 16:25:12 -0400 Subject: [PATCH 4/8] npm run gen-addon -- -p qiskit-addon-sqd --- docs/addons/qiskit-addon-sqd/_toc.json | 16 +- .../guides/benchmark-pauli-projection.ipynb | 4 +- .../guides/choose-subspace-dimension.ipynb | 2 - .../guides/hpc-acceleration.mdx | 39 ++ .../guides/integrate-dice-solver.ipynb | 4 +- .../guides/optimize-orbitals.ipynb | 403 ++++++++++++++++++ .../qiskit-addon-sqd/guides/overview.mdx | 3 +- .../qiskit-addon-sqd/guides/quickstart.ipynb | 6 +- ...use-oo-to-optimize-hamiltonian-basis.ipynb | 400 ----------------- docs/addons/qiskit-addon-sqd/index.mdx | 6 +- .../extracted-outputs/6b961c81-0.avif | Bin 8105 -> 7477 bytes .../extracted-outputs/9abb110f-0.avif | Bin 8281 -> 11110 bytes ...affd888-e89c-4aa9-8bae-4d1bb723b35e-0.avif | Bin 11989 -> 16110 bytes 13 files changed, 461 insertions(+), 422 deletions(-) create mode 100644 docs/addons/qiskit-addon-sqd/guides/hpc-acceleration.mdx create mode 100644 docs/addons/qiskit-addon-sqd/guides/optimize-orbitals.ipynb delete mode 100644 docs/addons/qiskit-addon-sqd/guides/use-oo-to-optimize-hamiltonian-basis.ipynb diff --git a/docs/addons/qiskit-addon-sqd/_toc.json b/docs/addons/qiskit-addon-sqd/_toc.json index 42126fc06e5..33bf4f5669e 100644 --- a/docs/addons/qiskit-addon-sqd/_toc.json +++ b/docs/addons/qiskit-addon-sqd/_toc.json @@ -1,7 +1,7 @@ { "parentUrl": "/docs/guides/addons", "parentLabel": "Documentation", - "title": "Sample-based quantum diagonalization (SQD) 0.12", + "title": "Sample-based quantum diagonalization (SQD) 0.13", "collapsed": true, "children": [ { @@ -30,13 +30,17 @@ "title": "Choose the subspace dimension", "url": "/docs/addons/qiskit-addon-sqd/guides/choose-subspace-dimension" }, + { + "title": "Multi-process and multi-threaded acceleration", + "url": "/docs/addons/qiskit-addon-sqd/guides/hpc-acceleration" + }, { "title": "Scale workloads with the Dice solver", "url": "/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver" }, { "title": "Orbital optimization", - "url": "/docs/addons/qiskit-addon-sqd/guides/use-oo-to-optimize-hamiltonian-basis" + "url": "/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals" }, { "title": "Open- and closed-shell options", @@ -69,11 +73,11 @@ "children": [ { "title": "Sample-based quantum diagonalization of a chemistry Hamiltonian", - "url": "/docs/tutorials/sample-based-quantum-diagonalization" + "url": "https://quantum.cloud.ibm.com/docs/tutorials/sample-based-quantum-diagonalization" }, { "title": "Sample-based Krylov quantum diagonalization of a Fermionic lattice model", - "url": "/docs/tutorials/sample-based-krylov-quantum-diagonalization" + "url": "https://quantum.cloud.ibm.com/docs/tutorials/sample-based-krylov-quantum-diagonalization" } ] }, @@ -83,7 +87,7 @@ "children": [ { "title": "Quantum diagonalization algorithms", - "url": "/learning/courses/quantum-diagonalization-algorithms" + "url": "https://quantum.cloud.ibm.com/learning/courses/quantum-diagonalization-algorithms" } ] }, @@ -93,7 +97,7 @@ "children": [ { "title": "Python API reference", - "url": "/docs/api/qiskit-addon-sqd/" + "url": "https://quantum.cloud.ibm.com/docs/api/qiskit-addon-sqd" }, { "title": "Release notes", diff --git a/docs/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection.ipynb b/docs/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection.ipynb index fb3d2ee73b7..f845c829111 100644 --- a/docs/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection.ipynb +++ b/docs/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection.ipynb @@ -16,9 +16,7 @@ "id": "55900f6c-2fb6-4d2c-8745-29bad8b66d9f", "metadata": {}, "source": [ - "# Benchmark Pauli operator projection\n", - "\n", - "{/* cspell:ignore textrm, walltime */}" + "# Benchmark Pauli operator projection" ] }, { diff --git a/docs/addons/qiskit-addon-sqd/guides/choose-subspace-dimension.ipynb b/docs/addons/qiskit-addon-sqd/guides/choose-subspace-dimension.ipynb index a23d2794783..3041377776a 100644 --- a/docs/addons/qiskit-addon-sqd/guides/choose-subspace-dimension.ipynb +++ b/docs/addons/qiskit-addon-sqd/guides/choose-subspace-dimension.ipynb @@ -18,8 +18,6 @@ "source": [ "# Bounding the subspace dimension\n", "\n", - "{/* cspell:ignore hcore */}\n", - "\n", "In this walkthrough, we will show the effect of the subspace dimension in the [self-consistent configuration recovery technique](https://arxiv.org/abs/2405.05068).\n", "\n", "*A priori*, we do not know what is the correct subspace dimension to obtain a target level of accuracy. However, we do know that increasing the subspace dimension increases the accuracy of the method. Therefore, we can study the accuracy of the predictions as a function of the subspace dimension." diff --git a/docs/addons/qiskit-addon-sqd/guides/hpc-acceleration.mdx b/docs/addons/qiskit-addon-sqd/guides/hpc-acceleration.mdx new file mode 100644 index 00000000000..5098c07122c --- /dev/null +++ b/docs/addons/qiskit-addon-sqd/guides/hpc-acceleration.mdx @@ -0,0 +1,39 @@ +--- +title: "Support for multi-process and multi-threaded acceleration" +description: "Support for multi-process and multi-threaded acceleration for the latest version of Sample-based quantum diagonalization (SQD)" +--- + +# Support for multi-process and multi-threaded acceleration + +This page documents the extent to which `qiskit-addon-sqd` supports multi-threaded and multi-process acceleration, and the assumptions that a high-performance-computing (HPC) developer can rely on when integrating this package into an accelerated workload. + +## The single-threaded assumption + +Unless otherwise specified, the APIs in this package are meant to be called from a single thread. High-level APIs exposed by this package are not guaranteed to be re-entrant, and end users should not invoke them from any thread other than the main thread. + +## Collective multi-process execution + +This package supports collective multi-process acceleration in the single-program, multiple-data (SPMD) style, in which the entire program is launched as multiple isolated processes that run with explicit global synchronization and communication between them (for example, `mpirun -n 128 python my_program.py`). Because the SPMD style composes cleanly with job schedulers and other parallel software and scales to large process counts, it is the recommended model for high-performance and large-scale workloads, and it is the subject of this page. + +Although this package is designed to accommodate different collective-execution backends, its current implementation targets MPI, the standard message-passing API for HPC systems. Regardless of implementation, this package assumes that a single thread controls each process. In the case of MPI, this corresponds to `MPI_THREAD_FUNNELED` or lower. + +If a function supports collective execution, its documentation must say so. If the documentation does not mention collective execution, the function has no collective semantics and must be called from the control process alone. + +The specific return-value and synchronization semantics of a collective function are documented with the function itself. In general, that documentation should make clear: + +* Whether the function is meant to be called independently by each process on its own local data, or collectively by all processes. +* How its arguments must agree across processes. +* How its return value is delivered—whether the result exists only on the control process, whether all processes receive the same value, or whether each process receives a handle to a local portion of a distributed data structure. + +Only one function currently supports being called collectively from all processes: [`diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian"). When it is invoked collectively, the eigensolver step is where all processes participate and contribute work, so an eigensolver implementation can use every process. The remaining parts of the configuration-recovery loop have no distributed implementation and run on the control process (rank 0) only. + +Some existing eigensolver implementations instead require the calling program to run outside an MPI/SPMD environment, because they launch and manage their own parallel processes internally, for example by invoking `mpirun` on the user’s behalf. That mode is convenient for interactive and notebook-based work and remains supported; its requirements on the calling program are described in the API reference of the [`diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") function. + +## Error handling in a multi-process context + +A function that is called collectively from all processes must not raise an exception or abort only a single process, because that would leave the remaining processes deadlocked or in an inconsistent state. Instead, error handling follows fail-stop semantics for the execution context as a whole: upon an error, the implementation must be prepared to abort the entire execution context collectively (for example, by using `MPI_Abort`). + +The API cannot guarantee coordinated error reporting or collective delivery of exceptions across processes, because MPI implementations do not provide such guarantees. An implementation might additionally attempt to make an error visible to all participating processes—for example, by having each process raise an exception—but this can only be provided on a best-effort basis and must not be relied upon for correctness or recovery. + +These are properties that a collective implementation is permitted to have, not guarantees about any particular one. In this package, the only collective step is the eigensolver (see the preceding section); its default implementation is not distributed, so these considerations apply to a custom, collective eigensolver supplied by the user. + diff --git a/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb b/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb index 0b549e78781..d346fc30054 100644 --- a/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb +++ b/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb @@ -18,9 +18,7 @@ "source": [ "# Scale SQD chemistry workflows with Dice solver\n", "\n", - "{/* cspell:ignore hcore */}\n", - "\n", - "This guide shows how to use the Dice solver as an alternative SCI solver to diagonalize larger Fermionic problems beyond what the default PySCF solver can support. For information on how to install and use ``qiskit-addon-dice-solver``, [visit the documentation](https://qiskit.github.io/qiskit-addon-dice-solver/). For more details on the SQD code used in this example, see the [chemistry Hamiltonian tutorial](/docs/tutorials/sample-based-quantum-diagonalization)." + "This guide shows how to use the Dice solver as an alternative SCI solver to diagonalize larger Fermionic problems beyond what the default PySCF solver can support. For information on how to install and use ``qiskit-addon-dice-solver``, [visit the documentation](https://qiskit.github.io/qiskit-addon-dice-solver/). For more details on the SQD code used in this example, see the [chemistry Hamiltonian tutorial](/docs/en/tutorials/sample-based-quantum-diagonalization)." ] }, { diff --git a/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals.ipynb b/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals.ipynb new file mode 100644 index 00000000000..20ce96d1e6b --- /dev/null +++ b/docs/addons/qiskit-addon-sqd/guides/optimize-orbitals.ipynb @@ -0,0 +1,403 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "frontmatter", + "metadata": {}, + "source": [ + "---\n", + "title: \"Improve an SQD estimate with orbital optimization\"\n", + "description: \"Improve an SQD estimate with orbital optimization for the latest version of Sample-based quantum diagonalization (SQD)\"\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "bb5a576d", + "metadata": {}, + "source": [ + "# Improve an SQD estimate with orbital optimization\n", + "\n", + "Sample-based quantum diagonalization (SQD) approximates a ground-state energy by\n", + "diagonalizing the Hamiltonian in a fixed subspace of electronic configurations. That\n", + "estimate depends on the orbital basis in which the Hamiltonian is expressed, and\n", + "*orbital optimization* (OO) exploits this freedom to lower the energy without enlarging\n", + "the subspace.\n", + "\n", + "This guide runs SQD on an $N_2$ molecule and then improves the result with orbital\n", + "optimization, using [`ffsim`](https://qiskit-community.github.io/ffsim/) to represent\n", + "the Hamiltonian and find the energy-minimizing orbital rotation." + ] + }, + { + "cell_type": "markdown", + "id": "77ab953b", + "metadata": {}, + "source": [ + "## Run SQD\n", + "\n", + "We build the molecular integrals for $N_2$ in the molecular-orbital (MO) basis, generate\n", + "uniform random samples, and run SQD to obtain a ground-state approximation." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "b8d5618e", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T01:36:48.334261Z", + "iopub.status.busy": "2026-07-16T01:36:48.334063Z", + "iopub.status.idle": "2026-07-16T01:37:42.585853Z", + "shell.execute_reply": "2026-07-16T01:37:42.584303Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "converged SCF energy = -108.835236570775\n", + "CASCI E = -109.046671778080 E(CI) = -32.8155692383187 S^2 = 0.0000000\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pyscf\n", + "import pyscf.cc\n", + "import pyscf.mcscf\n", + "from qiskit_addon_sqd.counts import generate_bit_array_uniform\n", + "from qiskit_addon_sqd.fermion import diagonalize_fermionic_hamiltonian\n", + "\n", + "# Specify molecule properties\n", + "num_orbitals = 16\n", + "num_elec_a = num_elec_b = 5\n", + "spin_sq = 0\n", + "\n", + "# Build N2 molecule\n", + "mol = pyscf.gto.Mole()\n", + "mol.build(\n", + " atom=[[\"N\", (0, 0, 0)], [\"N\", (1.0, 0, 0)]],\n", + " basis=\"6-31g\",\n", + " symmetry=\"Dooh\",\n", + ")\n", + "\n", + "# Define active space\n", + "n_frozen = 2\n", + "active_space = range(n_frozen, mol.nao_nr())\n", + "\n", + "# Get molecular integrals\n", + "scf = pyscf.scf.RHF(mol).run()\n", + "num_orbitals = len(active_space)\n", + "n_electrons = int(sum(scf.mo_occ[active_space]))\n", + "num_elec_a = (n_electrons + mol.spin) // 2\n", + "num_elec_b = (n_electrons - mol.spin) // 2\n", + "cas = pyscf.mcscf.CASCI(scf, num_orbitals, (num_elec_a, num_elec_b))\n", + "mo = cas.sort_mo(active_space, base=0)\n", + "hcore, nuclear_repulsion_energy = cas.get_h1cas(mo)\n", + "eri = pyscf.ao2mo.restore(1, cas.get_h2cas(mo), num_orbitals)\n", + "\n", + "# Compute exact energy\n", + "exact_energy = cas.run().e_tot\n", + "\n", + "# Create a seed to control randomness throughout this workflow\n", + "rng = np.random.default_rng(24)\n", + "\n", + "\n", + "# Generate random samples\n", + "bit_array = generate_bit_array_uniform(\n", + " 10_000, num_orbitals * 2, rand_seed=rng\n", + ")\n", + "\n", + "# Run SQD\n", + "result = diagonalize_fermionic_hamiltonian(\n", + " hcore,\n", + " eri,\n", + " bit_array,\n", + " samples_per_batch=100,\n", + " norb=num_orbitals,\n", + " nelec=(num_elec_a, num_elec_b),\n", + " num_batches=1,\n", + " max_iterations=5,\n", + " symmetrize_spin=True,\n", + " seed=rng,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0ca70028", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T01:37:42.590790Z", + "iopub.status.busy": "2026-07-16T01:37:42.589477Z", + "iopub.status.idle": "2026-07-16T01:37:42.595563Z", + "shell.execute_reply": "2026-07-16T01:37:42.595133Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exact energy: -109.04667178\n", + "SQD energy: -108.98469255\n" + ] + } + ], + "source": [ + "sqd_energy = result.energy + nuclear_repulsion_energy\n", + "print(f\"Exact energy: {exact_energy:.8f}\")\n", + "print(f\"SQD energy: {sqd_energy:.8f}\")" + ] + }, + { + "cell_type": "markdown", + "id": "9160d09c", + "metadata": {}, + "source": [ + "## Optimize the orbitals\n", + "\n", + "Orbital optimization searches for an orbital rotation that lowers the variational energy\n", + "\n", + "$$\n", + "E = \\langle \\psi | \\mathcal{U}^\\dagger\\, H\\, \\mathcal{U} | \\psi \\rangle\n", + "$$\n", + "\n", + "of the SQD ground-state approximation $|\\psi\\rangle$. An orbital rotation is specified by\n", + "an $N \\times N$ unitary matrix $\\mathbf{U}$ ($N$ is the number of spatial orbitals), which\n", + "acts on the many-body state through the operator\n", + "\n", + "$$\n", + "\\mathcal{U} = \\exp\\left[\\sum_{pq, \\sigma} \\log(\\mathbf{U})_{pq}\\, a^\\dagger_{p\\sigma} a_{q\\sigma}\\right].\n", + "$$\n", + "\n", + "`ffsim.optimize_orbitals` returns the **matrix** $\\mathbf{U}$, and applying it to the\n", + "orbital basis (via `hamiltonian.rotated`) is equivalent to applying $\\mathcal{U}$ to the\n", + "state. See the\n", + "[ffsim orbital-rotation explanation](https://qiskit-community.github.io/ffsim/explanations/orbital-rotation.html)\n", + "for details.\n", + "\n", + "Since rotating the orbitals changes the Hamiltonian seen by the subspace, we alternate\n", + "two steps until the energy stops improving:\n", + "\n", + "1. **Diagonalize** the Hamiltonian in the current basis over the fixed set of\n", + " configurations.\n", + "2. **Optimize the orbitals** by finding the rotation that minimizes the energy of the\n", + " resulting state, then rotate the integrals into the new basis.\n", + "\n", + "We delegate the orbital-rotation step to\n", + "[`ffsim.optimize_orbitals`](https://qiskit-community.github.io/ffsim/api/ffsim.html#ffsim.optimize_orbitals),\n", + "which finds the energy-minimizing rotation from the one- and two-body reduced density\n", + "matrices (RDMs) of the state. See\n", + "[Sec. II A 4](https://arxiv.org/pdf/2405.05068) for details." + ] + }, + { + "cell_type": "markdown", + "id": "006745b5", + "metadata": {}, + "source": [ + "### Why orbital optimization helps here\n", + "\n", + "The SCF molecular-orbital (MO) basis is stationary with respect to orbital rotations\n", + "for the *full*-CI problem. But SQD works in a small truncated subspace (here a few\n", + "hundred CI strings out of roughly 19 million full-CI determinants), for which the MO\n", + "basis is generally not optimal, so rotating the orbitals lowers the energy the subspace\n", + "can represent." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "46eb2f5a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T01:37:42.597573Z", + "iopub.status.busy": "2026-07-16T01:37:42.597399Z", + "iopub.status.idle": "2026-07-16T01:37:42.654809Z", + "shell.execute_reply": "2026-07-16T01:37:42.654267Z" + } + }, + "outputs": [], + "source": [ + "import ffsim\n", + "from pyscf import fci\n", + "\n", + "# ffsim's ``MolecularHamiltonian`` uses the same \"chemist\" ordering for the two-body\n", + "# tensor as PySCF's ``eri``, and stores the nuclear repulsion energy as the constant\n", + "# term so that expectation values come out as total energies." + ] + }, + { + "cell_type": "markdown", + "id": "93179dc4", + "metadata": {}, + "source": [ + "### Alternate diagonalization and orbital optimization\n", + "\n", + "We keep the diagonalization subspace **fixed** to the configurations discovered by SQD\n", + "above, so that each iteration isolates the effect of rotating the orbitals. Each\n", + "iteration:\n", + "\n", + "1. **Diagonalizes** the Hamiltonian over the fixed subspace in the current basis, using\n", + " PySCF's selected-CI solver.\n", + "2. **Builds the RDMs** of the resulting state, which is all `ffsim.optimize_orbitals`\n", + " needs.\n", + "3. **Optimizes the orbitals**: `ffsim.optimize_orbitals` returns the energy-minimizing\n", + " rotation, which we apply to the integrals to move into the improved basis.\n", + "\n", + "We record the energy *before* each optimization step. Because the basis improves every\n", + "iteration, this sequence decreases monotonically toward the best energy achievable in\n", + "the fixed subspace." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a0783e88", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T01:37:42.657394Z", + "iopub.status.busy": "2026-07-16T01:37:42.657213Z", + "iopub.status.idle": "2026-07-16T01:38:48.374706Z", + "shell.execute_reply": "2026-07-16T01:38:48.373697Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration 0: energy = -108.98452447\n", + "Iteration 1: energy = -108.99981993\n", + "Iteration 2: energy = -109.00585329\n", + "Iteration 3: energy = -109.00816569\n", + "Iteration 4: energy = -109.00936616\n", + "Iteration 5: energy = -109.01014322\n", + "Iteration 6: energy = -109.01069439\n", + "Iteration 7: energy = -109.01109308\n", + "Iteration 8: energy = -109.01138928\n", + "Iteration 9: energy = -109.01161411\n" + ] + } + ], + "source": [ + "# Fix the diagonalization subspace to the configurations found by SQD.\n", + "ci_strings = (result.sci_state.ci_strs_a, result.sci_state.ci_strs_b)\n", + "nelec = (num_elec_a, num_elec_b)\n", + "\n", + "# Start from the MO basis in which we ran SQD.\n", + "hamiltonian_opt = ffsim.MolecularHamiltonian(\n", + " hcore, eri, constant=nuclear_repulsion_energy\n", + ")\n", + "\n", + "num_iters = 10\n", + "for i in range(num_iters):\n", + " # Diagonalize over the fixed subspace in the current basis.\n", + " myci = fci.selected_ci.SelectedCI()\n", + " myci = fci.addons.fix_spin_(myci, ss=spin_sq)\n", + " _, amplitudes = fci.selected_ci.kernel_fixed_space(\n", + " myci,\n", + " hamiltonian_opt.one_body_tensor,\n", + " hamiltonian_opt.two_body_tensor,\n", + " num_orbitals,\n", + " nelec,\n", + " ci_strs=ci_strings,\n", + " )\n", + "\n", + " # Build the RDMs and record the energy before re-optimizing the orbitals.\n", + " dm1, dm2 = myci.make_rdm12(amplitudes, num_orbitals, nelec)\n", + " rdm = ffsim.ReducedDensityMatrix(dm1, dm2)\n", + " energy = rdm.expectation(hamiltonian_opt).real\n", + " print(f\"Iteration {i}: energy = {energy:.8f}\")\n", + "\n", + " # Rotate the Hamiltonian into the energy-minimizing basis for the next iteration.\n", + " # optimize_orbitals returns the unitary matrix U minimizing\n", + " # rdm.rotated(U).expectation(hamiltonian), equivalently\n", + " # rdm.expectation(hamiltonian.rotated(U.conj().T)), so we rotate by U^dagger.\n", + " orbital_rotation = ffsim.optimize_orbitals(rdm, hamiltonian_opt)\n", + " hamiltonian_opt = hamiltonian_opt.rotated(orbital_rotation.T.conj())" + ] + }, + { + "cell_type": "markdown", + "id": "a61dbda8", + "metadata": {}, + "source": [ + "### Compare the results\n", + "\n", + "Orbital optimization improves the fixed-subspace estimate, closing much of the gap to\n", + "the exact energy while staying above it." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "762b0903", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T01:38:48.377620Z", + "iopub.status.busy": "2026-07-16T01:38:48.377404Z", + "iopub.status.idle": "2026-07-16T01:38:53.111168Z", + "shell.execute_reply": "2026-07-16T01:38:53.110312Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Exact energy: -109.04667178\n", + "SQD energy (MO): -108.98469255\n", + "Energy after OO: -109.01178727\n" + ] + } + ], + "source": [ + "# Diagonalize once more in the final optimized basis to report the improved energy.\n", + "myci = fci.selected_ci.SelectedCI()\n", + "myci = fci.addons.fix_spin_(myci, ss=spin_sq)\n", + "_, amplitudes = fci.selected_ci.kernel_fixed_space(\n", + " myci,\n", + " hamiltonian_opt.one_body_tensor,\n", + " hamiltonian_opt.two_body_tensor,\n", + " num_orbitals,\n", + " nelec,\n", + " ci_strs=ci_strings,\n", + ")\n", + "dm1, dm2 = myci.make_rdm12(amplitudes, num_orbitals, nelec)\n", + "energy_after_oo = (\n", + " ffsim.ReducedDensityMatrix(dm1, dm2).expectation(hamiltonian_opt).real\n", + ")\n", + "\n", + "print(f\"Exact energy: {exact_energy:.8f}\")\n", + "print(f\"SQD energy (MO): {sqd_energy:.8f}\")\n", + "print(f\"Energy after OO: {energy_after_oo:.8f}\")" + ] + } + ], + "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" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/addons/qiskit-addon-sqd/guides/overview.mdx b/docs/addons/qiskit-addon-sqd/guides/overview.mdx index 2147d3756db..e627b79aced 100644 --- a/docs/addons/qiskit-addon-sqd/guides/overview.mdx +++ b/docs/addons/qiskit-addon-sqd/guides/overview.mdx @@ -20,11 +20,12 @@ These guides provide a deeper explanation of specific concepts and components fr ### General * [How to choose the subspace dimension from its impact on eigenvalue estimation accuracy](choose-subspace-dimension) +* [Understand this package’s support for multi-process and multi-threaded acceleration](hpc-acceleration) ### Fermionic systems * [Scale SQD workflows for Fermionic systems with the Dice solver](integrate-dice-solver) -* [Optimize the Hamiltonian basis with orbital optimization to improve energy estimations](use-oo-to-optimize-hamiltonian-basis) +* [Improve an SQD estimate with orbital optimization](optimize-orbitals) * [Understand open- and closed-shell options and their effect on subspace construction](select-open-closed-shell) * [Augment the pool of electronic configurations using Fermionic transition operators to improve energy estimations and compute energies of excited states](add-fermionic-excitations-to-configuration-pool) diff --git a/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb b/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb index 3cfc36c9005..7c5b12b9ad1 100644 --- a/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb +++ b/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb @@ -18,14 +18,12 @@ "source": [ "# Quickstart\n", "\n", - "{/* cspell:ignore mcscf, ncas, nelecas, hcore, binom */}\n", - "\n", "This guide demonstrates a minimal working example of the `qiskit-addon-sqd` package. We use sample-based quantum diagonalization (SQD) to refine noisy samples taken from a quantum circuit that approximates the ground state of a chemistry Hamiltonian. Ground state energies are approximated by diagonalizing the Hamiltonian in subspaces formed by the refined samples.\n", "\n", "For more explanatory end-to-end workflows that run on quantum hardware, check out the tutorials:\n", "\n", - "* [Sample-based quantum diagonalization](/docs/tutorials/sample-based-quantum-diagonalization): chemistry Hamiltonian workflow\n", - "* [Sample-based Krylov quantum diagonalization](/docs/tutorials/sample-based-krylov-quantum-diagonalization): fermionic lattice model workflow" + "* [Sample-based quantum diagonalization](/docs/en/tutorials/sample-based-quantum-diagonalization): chemistry Hamiltonian workflow\n", + "* [Sample-based Krylov quantum diagonalization](/docs/en/tutorials/sample-based-krylov-quantum-diagonalization): fermionic lattice model workflow" ] }, { diff --git a/docs/addons/qiskit-addon-sqd/guides/use-oo-to-optimize-hamiltonian-basis.ipynb b/docs/addons/qiskit-addon-sqd/guides/use-oo-to-optimize-hamiltonian-basis.ipynb deleted file mode 100644 index bedc2a18f96..00000000000 --- a/docs/addons/qiskit-addon-sqd/guides/use-oo-to-optimize-hamiltonian-basis.ipynb +++ /dev/null @@ -1,400 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "frontmatter", - "metadata": {}, - "source": [ - "---\n", - "title: \"Optimize Hamiltonian basis with orbital optimization\"\n", - "description: \"Optimize Hamiltonian basis with orbital optimization for the latest version of Sample-based quantum diagonalization (SQD)\"\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "9e40af77-7f0f-4dd6-ab0a-420cf396050e", - "metadata": {}, - "source": [ - "# Optimize Hamiltonian basis with orbital optimization\n", - "\n", - "{/* cspell:ignore hcore, SQSD */}\n", - "\n", - "In this guide, we will show how to use the `sqd` package to post-process quantum samples using the [self-consistent configuration recovery technique](https://arxiv.org/abs/2405.05068) and then further optimize the ground state approximation using orbital optimization.\n", - "\n", - "Refer to [Sec. II A 4](https://arxiv.org/pdf/2405.05068) for a more detailed discussion on this technique." - ] - }, - { - "cell_type": "markdown", - "id": "a6755afb-ca1e-4473-974b-ba89acc8abce", - "metadata": {}, - "source": [ - "### Specify the molecule and generate samples\n", - "\n", - "In this example, we will approximate the ground state energy of an $N_2$ molecule and then improve the answer using orbital optimization. This guide studies $N_2$ at equilibrium, which is mean-field dominated. This means the MO basis is already a good choice for our integrals; therefore, we will rotate our integrals **out** of the MO basis in order to illustrate the effects of orbital optimization." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "677f54ac-b4ed-47e3-b5ba-5366d3a520f9", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture\n", - "import numpy as np\n", - "import pyscf\n", - "import pyscf.cc\n", - "import pyscf.mcscf\n", - "from qiskit_addon_sqd.fermion import rotate_integrals\n", - "\n", - "# Specify molecule properties\n", - "open_shell = False\n", - "spin_sq = 0\n", - "\n", - "# Build N2 molecule\n", - "mol = pyscf.gto.Mole()\n", - "mol.build(\n", - " atom=[[\"N\", (0, 0, 0)], [\"N\", (1.0, 0, 0)]],\n", - " basis=\"6-31g\",\n", - " symmetry=\"Dooh\",\n", - ")\n", - "\n", - "# Define active space\n", - "n_frozen = 2\n", - "active_space = range(n_frozen, mol.nao_nr())\n", - "\n", - "# Get molecular integrals\n", - "scf = pyscf.scf.RHF(mol).run()\n", - "num_orbitals = len(active_space)\n", - "n_electrons = int(sum(scf.mo_occ[active_space]))\n", - "num_elec_a = (n_electrons + mol.spin) // 2\n", - "num_elec_b = (n_electrons - mol.spin) // 2\n", - "cas = pyscf.mcscf.CASCI(scf, num_orbitals, (num_elec_a, num_elec_b))\n", - "mo = cas.sort_mo(active_space, base=0)\n", - "hcore, nuclear_repulsion_energy = cas.get_h1cas(mo)\n", - "eri = pyscf.ao2mo.restore(1, cas.get_h2cas(mo), num_orbitals)\n", - "\n", - "# Compute exact energy\n", - "exact_energy = cas.run().e_tot" - ] - }, - { - "cell_type": "markdown", - "id": "b23a74fc-708c-4bd0-af4e-c9cd189b6346", - "metadata": {}, - "source": [ - "The MO basis is already a good basis for this problem, so we will rotate out of that basis in this guide in order to highlight the effect of orbital optimization." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "9f46d1c6-3b49-45ad-b9ed-972bd58f7e3c", - "metadata": {}, - "outputs": [], - "source": [ - "# Rotate our integrals out of MO basis\n", - "rng = np.random.default_rng(24)\n", - "num_params = (\n", - " num_orbitals**2 - num_orbitals\n", - ") // 2 # antisymmetric, specified by upper triangle\n", - "k_rot = (rng.random(num_params) - 0.5) * 0.5\n", - "hcore_rot, eri_rot = rotate_integrals(hcore, eri, k_rot)" - ] - }, - { - "cell_type": "markdown", - "id": "c58e988c-a109-44cd-a975-9df43250c318", - "metadata": {}, - "source": [ - "Generate samples:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "e9506e0b-ed64-48bb-a97a-ef851b604af1", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit_addon_sqd.counts import counts_to_arrays, generate_counts_uniform\n", - "\n", - "# Generate random samples\n", - "counts_dict = generate_counts_uniform(10_000, num_orbitals * 2, rand_seed=rng)\n", - "\n", - "# Convert counts into bitstring and probability arrays\n", - "bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)" - ] - }, - { - "cell_type": "markdown", - "id": "eb704101-0fe8-4d12-b572-b1d844e35a90", - "metadata": {}, - "source": [ - "### Iteratively refine the samples using SQD and approximate the ground state" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "b72c048e-fe8e-4fc2-b28b-03138249074e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Starting configuration recovery iteration 0\n", - "Starting configuration recovery iteration 1\n", - "Starting configuration recovery iteration 2\n", - "Starting configuration recovery iteration 3\n", - "Starting configuration recovery iteration 4\n" - ] - } - ], - "source": [ - "from qiskit_addon_sqd.configuration_recovery import recover_configurations\n", - "from qiskit_addon_sqd.fermion import solve_fermion\n", - "from qiskit_addon_sqd.subsampling import postselect_and_subsample\n", - "\n", - "# SQSD options\n", - "iterations = 5\n", - "\n", - "# Eigenstate solver options\n", - "n_batches = 3\n", - "samples_per_batch = 100\n", - "max_davidson_cycles = 200\n", - "\n", - "# Self-consistent configuration recovery loop\n", - "e_hist = np.zeros((iterations, n_batches)) # energy history\n", - "s_hist = np.zeros((iterations, n_batches)) # spin history\n", - "occupancy_hist = []\n", - "avg_occupancy = None\n", - "for i in range(iterations):\n", - " print(f\"Starting configuration recovery iteration {i}\")\n", - " # On the first iteration, we have no orbital occupancy information from the\n", - " # solver, so we just post-select from the full bitstring set based on hamming weight.\n", - " if avg_occupancy is None:\n", - " bs_mat_tmp = bitstring_matrix_full\n", - " probs_arr_tmp = probs_arr_full\n", - "\n", - " # In following iterations, we use both the occupancy info and the target hamming\n", - " # weight to refine bitstrings.\n", - " else:\n", - " bs_mat_tmp, probs_arr_tmp = recover_configurations(\n", - " bitstring_matrix_full,\n", - " probs_arr_full,\n", - " avg_occupancy,\n", - " num_elec_a,\n", - " num_elec_b,\n", - " rand_seed=rng,\n", - " )\n", - "\n", - " # Throw out samples with incorrect hamming weight and create batches of subsamples.\n", - " batches = postselect_and_subsample(\n", - " bs_mat_tmp,\n", - " probs_arr_tmp,\n", - " hamming_right=num_elec_a,\n", - " hamming_left=num_elec_b,\n", - " samples_per_batch=samples_per_batch,\n", - " num_batches=n_batches,\n", - " rand_seed=rng,\n", - " )\n", - "\n", - " # Run eigenstate solvers in a loop. This loop should be parallelized for larger problems.\n", - " int_e = np.zeros(n_batches)\n", - " int_s = np.zeros(n_batches)\n", - " int_occs = []\n", - " cs = []\n", - " for j in range(n_batches):\n", - " energy_sci, coeffs_sci, avg_occs, spin = solve_fermion(\n", - " batches[j],\n", - " hcore_rot,\n", - " eri_rot,\n", - " open_shell=open_shell,\n", - " spin_sq=spin_sq,\n", - " max_cycle=max_davidson_cycles,\n", - " )\n", - " energy_sci += nuclear_repulsion_energy\n", - " int_e[j] = energy_sci\n", - " int_s[j] = spin\n", - " int_occs.append(avg_occs)\n", - " cs.append(coeffs_sci)\n", - "\n", - " # Combine batch results\n", - " avg_occupancy = tuple(np.mean(int_occs, axis=0))\n", - "\n", - " # Track optimization history\n", - " e_hist[i, :] = int_e\n", - " s_hist[i, :] = int_s\n", - " occupancy_hist.append(avg_occupancy)" - ] - }, - { - "cell_type": "markdown", - "id": "917cf2d0", - "metadata": {}, - "source": [ - "### Refine the subspace\n", - "\n", - "To refine the subspace, we will take the CI strings of the batch with the lowest energy\n", - "from the last configuration recovery step. Other strategies may be used, like taking the union\n", - "of the CI strings of the batches in the last configuration recovery iteration." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "2a587030", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Subspace dimension: 32761\n", - "Energy of that batch from SQD: -108.7531706601421\n" - ] - } - ], - "source": [ - "from qiskit_addon_sqd.fermion import bitstring_matrix_to_ci_strs\n", - "\n", - "best_batch = batches[np.argmin(e_hist[-1])]\n", - "ci_strs_up, ci_strs_dn = bitstring_matrix_to_ci_strs(\n", - " best_batch, open_shell=open_shell\n", - ")\n", - "print(f\"Subspace dimension: {len(ci_strs_up) * len(ci_strs_dn)}\")\n", - "print(f\"Energy of that batch from SQD: {e_hist[-1, np.argmin(e_hist[-1])]}\")\n", - "\n", - "# Union strategy\n", - "\n", - "# batches_union = np.concatenate((batches[0], batches[1]), axis = 0)\n", - "# for i in range(n_batches-2):\n", - "# batches_union = np.concatenate((batches_union, batches[ i+ 2]))\n", - "# ci_strs_up, ci_strs_dn = bitstring_matrix_to_ci_strs(\n", - "# batches_union, open_shell=open_shell\n", - "# )\n", - "# print (f\"Subspace dimension: {len(ci_strs_up) * len(ci_strs_dn)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "e8c6d5e4", - "metadata": {}, - "source": [ - "### Perform orbital optimization to improve the energy approximation\n", - "\n", - "We now describe how to optimize the orbitals to further improve the quality of the SQD calculation.\n", - "\n", - "The orbital rotations that are implemented in this package are those described by:\n", - "$$\n", - "U(\\kappa) = e^{\\sum_{pq, \\sigma} \\kappa_{pq} c^\\dagger_{p\\sigma} c_{q\\sigma}},\n", - "$$\n", - "where $\\kappa_{p, q} \\in \\mathbb{R}$ and $\\kappa_{p, q} = -\\kappa_{q, p}$. The orbitals are optimized to\n", - "minimize the variational energy:\n", - "$$\n", - "E(\\kappa) = \\langle \\psi | U^\\dagger(\\kappa) H U(\\kappa) |\\psi \\rangle,\n", - "$$\n", - "with respect to $\\kappa$ using gradient descent with momentum. Recall that\n", - "$|\\psi\\rangle$ is spanned in a subspace defined by determinants.\n", - "\n", - "Since the change of basis alters the Hamiltonian, we allow $|\\psi\\rangle$ to\n", - "respond to the change in the Hamiltonian. This is done by performing a number of alternating\n", - "self-consistent optimizations of $\\kappa$ and $|\\psi\\rangle$. We recall that the optimal\n", - "$|\\psi\\rangle$ is given by the lowest eigenvector of the Hamiltonian projected into the\n", - "subspace.\n", - "\n", - "The ``sqd.fermion.fermion`` module provides the tools to perform this alternating\n", - "optimization. In particular, the function ``sqd.fermion.optimize_orbitals()``.\n", - "\n", - "Some of the arguments that define the optimization are as follows:\n", - "\n", - "- ``num_iters``: number of self-consistent iterations.\n", - "- ``num_steps_grad``: number of gradient step updates performed when optimizing $\\kappa$ on each self-consistent iteration.\n", - "- ``learning_rate``: step-size in the gradient descent optimization of $\\kappa$." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "b5e56baf", - "metadata": {}, - "outputs": [], - "source": [ - "from qiskit_addon_sqd.fermion import optimize_orbitals\n", - "\n", - "k_flat = (rng.random(num_params) - 0.5) * 0.1\n", - "num_iters = 20\n", - "num_steps_grad = 10_000 # relatively cheap to execute\n", - "learning_rate = 0.05\n", - "\n", - "e_improved, k_flat, orbital_occupancies = optimize_orbitals(\n", - " best_batch,\n", - " hcore_rot,\n", - " eri_rot,\n", - " k_flat,\n", - " open_shell=open_shell,\n", - " spin_sq=spin_sq,\n", - " num_iters=num_iters,\n", - " num_steps_grad=num_steps_grad,\n", - " learning_rate=learning_rate,\n", - " max_cycle=max_davidson_cycles,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "e06f5c28-83d0-4dc2-b2bd-2ec92676745d", - "metadata": {}, - "source": [ - "Here we see that by optimizing rotation parameters for our Hamiltonian, we can improve the result from SQD." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "78a80e64", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Exact energy: -109.04667177808032\n", - "SQD energy: -108.7531706601421\n", - "Energy after OO: -108.80400806164377\n" - ] - } - ], - "source": [ - "print(f\"Exact energy: {exact_energy}\")\n", - "print(f\"SQD energy: {np.min(e_hist[-1])}\")\n", - "print(f\"Energy after OO: {e_improved + nuclear_repulsion_energy}\")" - ] - } - ], - "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" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/addons/qiskit-addon-sqd/index.mdx b/docs/addons/qiskit-addon-sqd/index.mdx index 6e50339f19e..1b2065261b0 100644 --- a/docs/addons/qiskit-addon-sqd/index.mdx +++ b/docs/addons/qiskit-addon-sqd/index.mdx @@ -11,9 +11,9 @@ SQD-based workflows involve first preparing one or more quantum states on a quan `qiskit-addon-sqd` can be used to classically process samples drawn from a variety of quantum circuits in practice. For example: -> 1. A variational circuit ansatz with parameters chosen such that sampling the circuit produces electronic configurations on which the target wavefunction (for example, the ground state) has significant support. This is appealing for chemistry applications where Hamiltonians can have millions of interaction terms [\[1\]](#references). For an example of this approach applied to chemistry using an LUCJ circuit, see the [tutorial for approximating the ground state energy of the N2 molecule](/docs/tutorials/sample-based-quantum-diagonalization). -> 2. A set of Krylov basis states are prepared over increasing time intervals. Assuming a good initial state and sparsity of the ground state, this approach is proven to converge efficiently. As one needs to prepare Trotterized time evolution circuits on a quantum device, this approach is best for applications to lattice models [\[2\]](#references) instead of complex many-body Hamiltonians like those for quantum chemistry. For an example of this approach applied to Fermionic lattice Hamiltonians, see the [tutorial for approximating the ground state energy of a simplified single-impurity Anderson model](/docs/tutorials/sample-based-krylov-quantum-diagonalization). -> 3. A set of Krylov basis states implemented with qDRIFT randomized compilation of the time evolution operator. This approach yields shorter-depth circuits compared to Trotter-based decompositions of the time evolution and so can be used for quantum chemistry Hamiltonians. This technique has been applied to the ground state energy of polycyclic aromatic hydrocarbons [\[6\]](#references). +> 1. A variational circuit ansatz with parameters chosen such that sampling the circuit produces electronic configurations on which the target wavefunction (for example, the ground state) has significant support. This is appealing for chemistry applications where Hamiltonians can have millions of interaction terms [\[1\]](#ref1). For an example of this approach applied to chemistry using an LUCJ circuit, see the [tutorial for approximating the ground state energy of the N2 molecule](/docs/tutorials/sample-based-quantum-diagonalization). +> 2. A set of Krylov basis states are prepared over increasing time intervals. Assuming a good initial state and sparsity of the ground state, this approach is proven to converge efficiently. As one needs to prepare Trotterized time evolution circuits on a quantum device, this approach is best for applications to lattice models [\[2\]](#ref2) instead of complex many-body Hamiltonians like those for quantum chemistry. For an example of this approach applied to Fermionic lattice Hamiltonians, see the [tutorial for approximating the ground state energy of a simplified single-impurity Anderson model](/docs/tutorials/sample-based-krylov-quantum-diagonalization). +> 3. A set of Krylov basis states implemented with qDRIFT randomized compilation of the time evolution operator. This approach yields shorter-depth circuits compared to Trotter-based decompositions of the time evolution and so can be used for quantum chemistry Hamiltonians. This technique has been applied to the ground state energy of polycyclic aromatic hydrocarbons [\[6\]](#ref6). ## Getting started diff --git a/public/docs/images/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection/extracted-outputs/6b961c81-0.avif b/public/docs/images/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection/extracted-outputs/6b961c81-0.avif index 95fb46a67fc43c07c8141e10dac102a48b34825d..66993de688b72ef44d67e81d5934507e10e42818 100644 GIT binary patch delta 7137 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 diff --git a/public/docs/images/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection/extracted-outputs/9abb110f-0.avif b/public/docs/images/addons/qiskit-addon-sqd/guides/benchmark-pauli-projection/extracted-outputs/9abb110f-0.avif index 3737095c52080366478e02ea853c36fe17f51897..8514cb8a16e98563e27632d86914c693ff44bcc5 100644 GIT binary patch delta 10820 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 O=(@tE;1U3nEg&pZvj9c_ delta 7967 zcmV+)AK>8TR@p!p0000SW^{RQVRmU|00000ZE0pPVRmU|kr*_QS{(`=mjD6)0000W zE0KXk3l4B;bZr0t00001k;BV>9?flJVRRAz3JMt}Ctj;W1T-2DGKM`&Ja~9!QqRq& zOcu%~E#h^9y)9g1D*HwM*)gK;A$mQL054ABaVv~>d8dV$`HSJ72K^X{x1-Z4z;!Ry z%D%OgrS26k#(<4Bh2~~;O_XU|X39%v^4nsfAC@i(dF+acfkG>@vQ2$|3Ih`di133( zQI!)ZvjK${ca>6sJdDHL1^!lM^dEJvVo|RHO3DZOwr$820IlL@qDJ3tdZd8r6M16{ z>1&FlHU7RaM(Cz=9okA+n}2hw$-|8 ziDq9hHZoCdlD2G)aUofMR&pav$|=W#9yy9M0COnaolph;Dh? z$yrdan;^)Hv|W-~@-sah6Sl9UNF&~w^XG-6vT}n1 zyfbQl5&aHJ3#D&_y>6jeK4S=QZi6I~S(@ykUl&gx*^*cbdvSHZk&#-L22)W+11S)6VOf%h-i0%qiWj$KW6R{IXnu@e)Tpk$MZ>W(5h+jJc||C3IZ4G9UjV z+^CE;>?$o=E+#&_>_KE?OD$MS>XGsd=fr9i*d<|qVg-~atT5T8t>S?0adLahDcCfw zqpHLZ{);&2*r-sulOE@~kwK;_IkA?Kw zDi;v4%(;fdQm5;c$-R(oJ4JdRKX9#l_zM?Z(Cy*fSWh8JhY_hBhMprJmar;k%ghhRFFXRC z1vU2P+hDekY!Ov@prppu4`)OoaByho1g9l`*W9v=o$|a3vj{>k9-d=X_VenGSMiz> z*`_Eh;a~!f0>9ORZG%G^nW@9w(Pu;Qyz$8o=#H_2<}D0c6CL`s>WwO>#wdZR4GNZc zm9jGABR0RsQL7RqZE!=Oz5MabEXl<@_P$Wi1h??uv!qY;N)#!)U23zpI%C!pu$mu# zAJ|O7Gg#wLPzB^*n?m*asPRb%-IFJ-F?Cm4adp4ybtWFX*K#`kW9L%XM_cH`5ady6 z|8K7#T@-N&P}4$7l8IqnKWRIVcGhOA4)4cnr$df3unQtw`&|I^+I(830othU8Jy+ryK8@np|AOTXq~~11CnkJ-^aN1fS%QHK{EdFm1$YTtU?)K;$)IX5S@6{UtRKczOHeyWz7L&M_>p$6rEa|<+{ zZl8;~`9xo#(fjq_%zZ+!6bP7IFRba%N=iPP_`nAML_^TogJF4PfjF>rw>|O%-3PiBkBzO=-Ufp3=<%2`+0^ zKqBi!zb#kL?Y@m3j79)|M_%`85=!GyJlJi(7m%XS6Q?=I{K_f=ea*~EgM5HAaAn^7 z3G=)=j4G>ZhZ52T89i(8H_;!5fX~!Xnvh@v_i8y0$=4+m2`I^>ixjr0M_OZ}tq8KB z`BGD?15jRr`6^M=TQh696Z;u4bb}J#VE4V52g59M_XI!LgFd%^712vxrWbgY0Vq$Z z_C>@acm95k>T~`H>gV>~Lf1|AW79OG{QtVZOifOR^RaR9FA+bU0EzkV|85ZDb!5>s z@ZKxWHKXCzGQ$*SVv%X-8yEsRHlyJN~RG+x5 ze4!((*9c2jSuC1=*1H}*oDf7}->j2;OIq0Ks@G(lLO)na8K%3{+4xItL^^HP{Jz-7(a!J}Ad%iN zxAH8~xhEvI;}%O8P#?Y7;hq8|^)$L44wUdH4|R7j8%^*NUzWy{>@)>SJ$7hEPirBy zJwcWRk}jApRbn`V$q$aY3sPnA8ky{t(l}ZG8Xc!U?<^ehwC}E4ftDhyS16yif{h60 z4T0rpKdz5|Wy%n(k^=_LL=>9pOO0cyt{GILQ`Km3hQcEzw%nPg|CwJkmLV7ex-`f`3M6QL@0c`Kkt5lM`rk7 z@v+k~q5uN^!jvUNZcfa&c7gA)*PQf2{OZJ4l`ygRL#`m(RmFC_dksp0Q80t4cE&36 zgCSFYvxSBM)}(`|*f9Tsa;9uE95Ozmgf4nIE(8z#s1kDkI3&&WURKgS$F*K$9`YDw z;8rP0hcxFeJ%Ly2Q>l4?I0l3e73nL>8jZ@bHvDwXND;TViWXK~p3`DFjUO`;_2MD~ z^}&{`_DeiC5=aR&m?8^M$Dy9d_)vS*=>sT#*|OKwWA_P3+;tWmv_pIKpF1m-K4bL) z$=5JuJlxRL1=|~es^~vA>T<=NHUtAUVq$*}`gY54ZWX;oe2w5Q8d%9h!Xlfy>a!rr zwUf!lYH5qw#ZHi8;IsMck&(iAn=9>`lY(2y+?JQ0&X}(|@m65)cQCN7fc{@P85mxF z%^0_Oe>k8l%(R@|$hV^^@_j_6VDp@|^&Uw*uHP_#`Nx_L%gf^Jev2?>l0z`{2GPS1 zy|u@ifR5_gYx0Mt?S;y=R_nP0P+6Ygt@uw}0gjILp=yyshym)1b8k}?w^U7Fmbljt zwSCPW=b~)!-&GxT?uiYiO8kK`2JioWwyyTB`L?D61kx_1$@IGW{r4JCrN#d3M>yWc zvcFg9i(*ERP?rN9FY`m8`=aEaaEET;j5ZqE@WCz)O0bk6X1@LT*PPUIGl{-rB=UjH?2j=2?!KUDd?HT4+rJG6b|4&e4s#w&A>g8lTd+ z9V`N3+YsjUHS%I6@#xD>mz0(yzlA4sNFe^4eMH~zV6jFVP0U zr}e-xVK$32Nhb%AlSZ)r8uKoH6actp@+%EdF{RvwZ!c;r_QYU}RqAwdH``5W>zle? z0t&QNCt-6PQ6nF&*cn9Dy2FD!hY-qfK-s;afgcRE+b1M4LHtM|(VJ(I_6Io8K_T7c z^4c`ls&1(=H!dA{FLkb5fOFV!<{5LUHX*dWUwmmN65)L6;9U4{0gWAh?O>k*ut)W? zc-@+Wb=;dmYZIIaKB1v%ttWBWkRMglGc`mFk0k|Ug=J?i(fS(afL;5tr^F^2-R0eq zlIbH9p~HVdLrry{3iBq**ko)MwF~^4H*PokhNEp1u><_`9g|bOrF55Fl)79m&YVHT zTWPx&1#lI^C`c*z+RLU3Uj&>l1Tcg&#vNNm*AT^1|yX-3NKEH!^Z+~>?bII1Fc5l^@?+`fa$1Jl?i)i6s5zy3ryW+9R z_5&PRXwk*ZQ{|JJB=XU6^f1)1-Coj62@g0ZkRwzal2@vUNV!88)020H1kprWKHmCd zL=v19<$&AurKFNZdxTkV-V?Pri<;hfiW;)d!^1;0L*?4x1gsy~42FDF8~DYB9XOCwZe`FQj!z73)q2I3RtJlj zMxk(M&49xvf@O#FZn6U6lChEfTM6~fkqnhlQkcH|{oET|WXHZ|t~=L60LIY{cFlW! zucxmzwmI_@+YgQRX<8i!hdYyqi%m{+)AEyM*0yDC&JDilgs<5>x&TUEwQ zQ771BzG>=cNShdIGL<-#w0Ye&UzGeH_W_dg{Am`NZ2*3i6ZD6_V8;SJbk%{ZK)U14wSa$; z$N)`k!u3({en97tE0RTEzmh);`(|Z-Zqo)_UIj|HrY`D;9RQ*Y{HKZ>|3@Cc>0##l zT#Urr4Yj{}i*X3AZO2YFvdhY|TpL=d*C8Maav_z`#yxg`MxJOcC=x8!+sGHzvwMlS##`xV6B6rYqePi z8(1K2iRD#4ur{1&UU@iF<0n`w1feS&u8sI+U8)4biXilfdz8J_gO8HAnOH*4NA z{0b{&-{q6O484=V)8BGwyjY%2(}_!_B3eOAQ2{N>G)@ogm7MohS=g8gGYFnMN@a@Y z_Or@Z!fIC~B+Wd&|Et1(O|=ur&9TiA80tj$_`k1;s=@YmLq*cSP!j7^<^H7~on|F= zR(!`A2^XzH&&Q+n2A)1uj*xo#Og70cl6+$wrQcO8H(kH|xj(HHMXXBccF*Wn)2lv9 z=I|73{mDb3eIDz;G9lZdb^DeBO8E9a<~Kp*EAXlsI%rthmgH7{E@v9)uhxQi_V5$Z zhY)nHNz3U5(VR4}aHS2T1&KYA5Rmfk)m5jwm{p1!7k8A%K6y$wBe2$mqy%%lz@LfL zXJJodz-Vi6bstrI4n-Lw4cc+>s5ILfKy~ol-<-`^5?v;)E#PFTfZ@cOPfzUA>Okye z^^Y{luQ}{y(OIT{ou)0T%5Jw)I?31K00Qc@5K$=}^NtplnVUExWs1SmjkXoSa+xeS zYKPr-C0!!+i{9@g_ySX943??%k((mmGb4f#Omdub-Qd}=TmH+E8>BXrl6rq9=UNw& z!QJVMYtJr{7gPu}zXv}&)otZij4y7{t^2Z9z3@k1UI<`+cbb$2=e}$icML(xXPNgk zb<39=;K_Gr`N}}0HqO2OV4n?3lv!^vjg9gmn*C?!POjL6F#?QyMuKrMA3uBIY_Yif zN4V7l%@xa;*oRo1hB{P%@kdHuxqdp?U{XxBB{fU0ZTC&=QnEBKew7%)dYIkLAAO0L zS(5boM>HgVwu2~_B&a^S(w{z>TRZ(UuzP%j+s9bhrqZG&d56UvilL!}B2;=Dr{f4S zxv26Ab35Z=?bh>sc(2rXWs}RHscj zJSu}L{Cl~KUST~=PPh47{v8%>r9mJ&LUA;+!LcU*VCOqN*jvoPR!69?n5V)P3*1E>Bl8w;Wt5|d*wtx?49W^zM zE4UJSAbGkQcKo*4@zZhbUCtPgow`&D)Okw7mSMV{fzYFm=gYXia{=u1w-@+J@FEm5 zW9=JG+jM^I$GEFbk?xo)-}3ax{3wWOi#9`lXzn)M_|oV-m@Z zpnYg5XP@&UkFpZK;=hOcl=&AN6;GiGeE}oZf@9hECRgwxJI4fIJzTbSu!CMvZ&l6_ z#g>3JF$r(SnH5)q##jb|R=graUw{CH;Ind@^+yCxW(`y8CNFHOem8~Qw2UVx%*M5U z=M=E%l;Ww7F~%sH<|A{=ORa-gRCpI&sk6^rL*zy(Y?H&##S{PQ*EjiSPR8@d+$GG4 zXK_eN=eD-XyE`_S^kwbcVHaYRGuX~Qt~VGQHM7G7f1|)}Eq}08&MDEvKuJ<0!sm$L zzI+1Z#Hk;Qt+Rg7Z0fs8AhUk5lXxY6H4Q~yr<))Ebn@z6F03sbG zO%JE{Np0^Y3X9`&nYCT~s#Hp6E^Te#YU|co=!CfY*2&P&5#KOjon}2*7?h=dUPEQQ ziH5LcxI^n#xA#tWbjC68q4yYgnKdW$ab$NS+Pka6Gk7Upq*lRgmFKyxjU>~()chK}Az-f;E49SW65ZciKuHzz9OA6LE5HwJ%QS1?d8 zi=6`C*lFIH8)suuuZwV6*KdS>VDi~hjnfOnlaWtSrc}6Elm=+Zl;+qORy@#ITG};6 zYX&rx5v^oTx-RDp5&p!bOfkl*`g@q2SsDwCG>ui}K+_=)1cPd1EY1%^JsZ`&%hLGS zj(Hc56R%PYl3txD5{ZXq>%w6A2h0$IFMu9^r2*>&vj)e-lSaTr3Jphpjk^z6OAbjR z8&};Cy2e}WS3B`z3M1IYSj$JveE*sCkdv;~`_1Zs0p9>vGLu_LO90uA;A66Kh-qt) z{Ahiya#rEu_4B1f7vL%7sidSjV=FX3-tgQd@=Oiz=3^_c`I?ylRc=!uv-7cwkjvrd z;N>1@>N4?of<#7LACR|ySxXRf0qOoa5uw_6rvGH031oO-!@Tw0E#wHNOg>vHioArw zNV4X4x8a^M`~eY`TSt%u@7W>;MXwQJKP`3Cvk1$^l|;=E)!x7!%4oODQ;M8y{nRBw zKf|TKSaO{1k;c6KY*QIX;nx$YMUpw*37n}nnN@#YvO;Uv8IS3IA6M^qvdxK`I zLFOeiox;FHj_6sum$*YURJkNvBbRx!;1+|UFukAH?x+{_pod#rL$K+krnQ-cqO)){ zxwfz3o}Ds@XIM>tzSlNa{KP$yn8{K_QOg9=0g2IcvNXg^yBs7;tedr6^jS&q32MJE zyb9o`sWEK%4%vD8SzUdA-nvmqW}(L^>e<621@-A;n*g1xZZ}zbZs3|$ej?NftIhobcU4M$+hXvydNkPU1IfRV z-bU#H1?u+K`!Oy)pH8&V@+-F?x4$b}XmBh0rm|;$vADdtYBv_rgZE!k$85|#VZ4u6 zCv&(`eotk8dBXW=)C*O`gRx%KtDRj^+W(JT@6FV@iFFRz5_Mg8L#MSZlq?$&v0ju= zQ(7P3@(ex_1^gF9%D<&q5V(%;npNfVRP=}#A0%^zZNl3#Rg$1pev zw!Z6PpQ&NI?tb@71z)LPD02u4 zgImxb!{b&OnYAfzNZVXS@JudX(%q?0L62t@L9j(kl6W+5#$RK+?OK7={Rt*w3In&9 zlF3+qROT|Rv<#EL_L6fl8Cb0>{M{*z)k;ce>Jz{NSVRRAz3JMu&Wh9%y0SyL(GXHrH&;Wu6AwcxF zlTTtF!%HaX?osT87_Wr>e++Jz*du_`?gutbH$$PsQ?Mu@F;!56r@+JQ2rBM~Jbj;* zV)R3iLVkG>!P?8>@UsgcVQ9d0t?o6DDe#o{>zw8(r|(g%$}5WsE)JA`N?LHvW1;ec zhq4IJRe=n5bN^I^q-Dy-J&p<8!?{_S9HLHYYDV|*mq`l!-poWg6VWJ@fXJY+o)H8? zEH$zT+cNu(*gOr$mc)(xBs@1fS{s_QH5LA#Z+(iSS{u&^Bkx%O@;4|06j~!5ZW=$; z!})!h#CibxrF}V?Q#7}KTmgg}pBV_>u&Lx=RZNsq3thT>TS7{Rt*}g`FJy>Y(VwUPC^ASjTUpZGyifQ{ zB9l~;j@+BWo=N2l`mUX{gOw9?|#!xJ%o9oda-ZZg3omr7%@ z!)XMsfxNp(#4w*2t70oKx;+}H;`)#=SW=T2c*Qc#J%_V_jwh6wmfq-d41h2`P`F;p zZn#^WDYw=smT_Cq;D>hl+(J>4q3P3Oi<*1YGW4H(bM#$#W61YbNpvt z8$r>)ZNo8%-LcncsMg((w&DQC_)yr!o$!U#hcdXS}m)+m@5pLCR-CtS1Nc!Drl^y&~rCT|}>exf!n1d3`6w z6rjF0o0k%g0SU3m7G;-}YUd8z&tRL;dyE%$QdkwE=0gf#Vp+?U9(w22`>7%;Mlh9l zX1s+8;+kTAlLcD`UmQeXZowflHU%T>oq>RP>3Nv)^X^Ob0|{oh<=o+xt7#XYrW=)b zJLzo&ztNeIU^eYzc?bEGgsj+sIh@Z6+*K_u>!jbMiij5oOl6DDefypvWB z;eRb^QOOin)emJ(+s^mBH@m{vC!4~5RZ6I}WMqBo@j&EZe#WNv_hg;AK}?i}LgYa| zrukns(Sa_P8tD@_{>ot*XImaOtd#vd$?X5I&opMq(Wo1nR$a7h%hhb^q zwMG(<>^AzV1R>iVFOm{Rpo$X#3@nOM#Zvu`E*ku%6xp9&_V`WG&1R-XX@fuUb-5kC zO`Umvtd#iP#cn`g{$rM4954J_5p3xiJ!f5iP0`=QMpwrrPl<<9ueedz@KZ3Th|w1e zQ5YFOtXO071;@{I?uF!fE=*A_->j6#Un75KV{*IVK9-;6@k?4(<~ z?%@Cc%k=wf+!O;j1o6DE)RTfvk2}m~*>|=wwEh1+c;v-ER}WVA&%H7nf?h9wLkND1 zt;=P(8;3gt`yPgkl#E-T1N*{9`O~e2hOdH$OC%&gd}&d~&Qd#pOwr9Eap+ zjik$6w1d9?|3*e#9W{i0#onL^hR)nXD&T`4Lr(y>EV=u{K+R9p=r5;sMD$Z{P&`im z*3aU_l-6=9%RhrAGvrQe4M;hq(^)XP=K{?NaP}tK(j1an<(J}qK*+G8q2E;2!=48 zd0uTERrR)7N7ik8=D|9?U1l~)6mMk&2#7Hd`%8Y;ZXqM z3{t&d%&D6#p&?Q#|7JK`h+^z2B2+&Ew#!u8&mEn=HIyp-w#i+anTZsacL-&ru&*AV(uQWkY zPKsgcssj3Aw13^CHrCT4A)PWqka2PCfNV11|0DJ!ASGhHE<5*81TA3#c@KY>qxiaBc_$y!&Ax_;7jJEZ*30E44xYTi>5E1pkJ>1T~6gRt}yb zEKYvmCp95|?D7yPi@ckwV>!9+G@|DoPJJMRTEnjF(E7tMgpEBBk@ynLdL|3moo*Am?q4?3Rudyo>?K>1T)Xg{b0R%YV z$ZcwWioYvQ2S|r8^^0iiF3hUk1XA(W)cD*Si>>aU?VeuhTMM7&*LPC>kfFVO^mov% zVH9~N*@zl3+rQ|&Tdn47*B&|Y+t=f|UFYZJSZrKQ1bJO4WY%)g>OZ)OzVN{uvrx*f=EUp=zc}`VHEOz zGxnTMbUhrUd8@Z)r9ne)fiSE50i}juyGdJ9blIC7kcAezegua;O1}^YMQXqP=Cha! z0j`-OnZh?Xh3}<w?MkVEBi;S%)xuIWsoM4Par z3V#R9Qz3;+?d{oEy;nDjG9`4J7k6~Yg-<|2$!Vu{tCFI z49Um8)aOzrFEdE6xS2FfC|5|nWm~z_QJ1uZQz~Xt67?~E8sh!p&vaK*A04`Xq$++3 zLgwAXE+!)-U|afF`PsI=su9qDMRm*Jj>EVuF$8*;)i10g@E;d-Yup zk@G53f3n^4&s4tqZ#qy+CzZ^9(LQYz-cxGJobUbtww{=xf!-z>0Pa%#)l#)5l~?zE z7{R{l0_~J%=!3}7Ppv3z1b$>SG#|{PUCT>BU%G>i83HW0u+NBB%CUMZz z^`jC|Pv#DO

~BbC{ekhjJ;D@RXYnt0BP;|e$g8zSu5Oc=g`jgxesGGkvb;vj;5l6SOx>) zCu&7GI^I|P>}116ol`lMw5=&pkJV|5k}NN}bkgx4c-K5U)Pz7-0I!GW-!T_V=-k5a z>x9piLR?Z>3@#W{e^=|lxEw15|H>r+qjYu^e|Ofr5N2b4vF(X(HqT zvfrePfLY{!*K~}C3k!^df!MDw8)6n!oGO#rX|p{#KY_CpeL{y{&#%wwQj>&3E;YoK z6wMfS4ry!?U~0jn+|Ts;FK$=1_G8@jcStgm&zz(g`0*+t;<|C)9IV*)hM-FBgg9yB zwE4AtX{v{$d051Lkf;D$tg6pw1)U9u$RH12ZT?PE z0)w$xCQb4j^v--SLi}=ykZLF4U5KQ+2lZ==@b-N*VKYU73T(><;vHKMq}7Yv@T}>1 zYA0KE@UdXj@DEM3wR=)<05t9_s}{aw!lC2dt4TlSgR&HmEofkY_Cbac>yjdI8BUaR zf>Ydo`VoPvUnT39C*S%WbVf$h#XkFJkGn)R>=C|v{HXl^?s-?N*tiqdfE};EWY8eQ zutst#Y_@8HZ+b9++^ZvQV(_8@zxftdM737wJXkkiC_yQ7k`abfTXKzMc9caS7CBLw zc$+1gO-DB19bmKFq^aeTv}nhEBptG4Fw`v_&n(kIMoXmnsRU| zDX?P#U(q|GC{u$=RHIH!kn*HtRmQ~2aHc&?k0>}+ZU5c=br;cNhy^aH4?!Iz-Lz-- zHjV200IfO37M%cO(B*K6v{H%!#_TMp2QJzn3TZi6W%tr5{ZA)BCiX2<$Vp_KDvjlT zQCrs&+SDXuu=}z*>M}&zH*B{~;vNGg7E6iuN(RiarGAAEZkNSsN%wE;%A@mMaeAq* zjLE}6#8QcBJ56Pw1!$;)?X2cm@+=4JD2HkycfEIUIR{Soq^3VmKrDS9omw%_kdn;O z_A1l?-7l3nl2M2Zua@ZulT)P|H}xQY)t{iaA`)R%>megB_hiu{OE6;xKvGU!hSA=i zgKPCnqwf>$f)Y6)q zR~io(S-@t<`0t%i-KElE9+4O*Um;PTyFcS{PX+L4F;_Rxhy}Ca#JKb`L?pjBh5~r| zIx=4>!)UJhiiUIp#N@&$v{C{a9$-;R883BTQGMgVp&rev(!q9raUFv7qAnib^4W9+ z3?IvVAg3F#F&XQNB)M;~J?rd7c?^>XF+u=?o892K^h2}t=S^lP5{GkUrAYi>=$Gu> z+b&c=aDQ-FXAFDR>p`@C$2Q{}?l*WW^MC&3Z_D^bc4n;jMy;`~+oSYWtj$g0`E|-K z4iBw*SMsWrBpW}~BoiemZ>w!CI#3hs477~wG`ff{h^NRrGZ7i_O z_{}-Ahz?|o_kOX$9|`M@1rl;oL09D(hIRfH(D%02TEQW!&*kL1cSw){$EnydJD#{_ zFK?@uyxn9*y$-uG1h46LvP}99(o4!6(?FFLTlTKoljHDLI}ojO>~Pnhx$iDMVeCVj z!zrq40&C4X;IA@&hAl2+-M5S%nRDr$WgETO8%hUj#Yk6jDSzSOm}OX4Nugn-W53^knEs1IL!S(>>GO}z6y(-RbO)MMx7c}LV42nGI3zS=~eZt2&J~6cMmr88L z9Jmvgs&XL9sNUT2%cm^Yc8&3vx=0T+=)D~**-(l2S+O9i;D0aBOsJjWIseY0xd-=B zVz2E|`t~n>aEJCEJ`}VB9HGv9%1`z_*famJrG^u%W%3LG!J5YjZkHnj)=8hNMy&3D`8?fVYzKK=N|rf9tHwGVj!L9#V(5s! zo+XNmb>s!Ehc_H&40C2zY0PgjI(dl`Vkz#Lf_BCz?74QgW?`3hRy!g|EU@3PwBSy- zoe9i;1I?XJZTs8mPB(}O=%!fBYsNQ!bW}}Fr)7B>BYPtp!D$G4DaJhV)kc*fv|KNo zg>tb0(~2u0(n-00B3SM8@eB(r;!qf%Ju^(J7MmLbar8x2S$?eZyf0O93ld~|EeaUl z^>x57NrWM4fvI-pyXt<``eN4;Q?jwDGFMQ4F4B*j81Wb$hPB?a@rX0H25tuocHSH% zZ!K9DS5gGWf^O;7DpA8S6f;4BQnJH-jS8}En72m)Ro8xhu^8wt=mBeZFR-BDoG`hd z=uJMKxIUaF_8auLG!a^*gri!_HHqVlm+Wd+q&5<&(sB4KWavVTdI3Bb#5u|Rv-o9y zlsgb1f;Zwd%DasUf^^Cptc^oR(8Ra58G#Wk=GVkitwZZiV=J(<1MH zXZpdG_Ap(^mMwHkZ;Qs!OBLuDzCs{z2m}dZKfF$w%;9I-@YgWtX9<+GA{rq{xM#4# zI-II=g)jiMz<9VmYzIi9qkYGu7ostLAcR`3ZdQ=8E448P2dmfDH)uRGQ%58gZe-j< zb4>8>`Gz!dgp{=}b_uSONuZ(oOU;(csKOv>uy8A9q`((FT6sF<7R11tIb)y!{DOMp zpR~Ar2R4K18?mT0O?rlrsLuO=Yg2yTzA+t0N-~bt;V)8Q8??w#tHY-{E#}gHsGFlI zm6%C(!|e%{Wwo-cr@l`THKSeHXjHDHYw6*(Q$x1VRBRthw2UlC&{tuetZyA9v-mRs zs89cm2#-HM&2Lk{7ow2wj)M!Ea9$S#vS-hzKFU{NNG|CsNcx{zT{Zb|J=l(f4O290gXx}1SNZ=Qc()Frh=9FV?(l&Or>CZw`kl?YR$>}uqLHf;C} zpc7zWhbi64-{v>tlUOr(E-USb<+UqR;F$gR2i6a!fUKu$I$NxWD8ku!pE#HU4j##{xGN<`kz|d zT(buM?BlWe#i=q)z2|dOnySW(c=sb4QC;+3dJ|RdeF5T##0*1!1}6iEOX|4Bsd=Ra zGlL57KA^_`8E2SuH>^j9BLRssm25b_pb$EyzmCeX!V@y-_P!d1(C@5Bp%4)D_|XdX z0vW;^x6l)aqo+XM51DT($an5Ej^B{{6yd7qHRKe?*6Ez<2MaG z;KJ&pTi+Is=CVqd#s!Li<*BJHMiR-A9mwdI*Uhh(EaF~&XrOyW36ed=xG16Q8`#RY? z(_rwOHSrvOYo}{NZyA5CFKAqAHsO!;067F=i^z~N!(|! zKx@>UZtoxNTB`dw4OEX1UjeC&`Ly5mDQ9W?Dn6v@v-ffAy||xoPQWNe6-wO+7QH9S zqXzxCbvdW|vkaOJ4kCgncYobURCE@+e?r#$^jbcD7wt3xem&XB_?|O)K>*=Ijw<@* z7#JW3ZIqn2PbI1;=T`~c!x&&1jBVOA765_IAKI9^Jbp#nct2%pR*4V8fUPBwnUpO~ zb80NEteqJEnv*Gn{&uYZR_&v1t-)=Bf#9kUac^#0v@~+!v#Bfl1w(O4t4+S;&@tm9 zllZiMe!8M)&~DvWL~&w0>46KsIL*uux@A^n0Z*W=sy89NY%Pq|F_f4B`^`9Bj;$Z! z-OJEZ8Bw?ey6di45D+D+CN4O44ZdK9IwTJgVHg`pS!F*WC4{xIb)zt1*?EY&Dr(-j z@i@bCN={=ZcRnZkdPzDPN$V>*4JG6#mb&YIhz(qErkhWUI23Jn31-OT^9KFmXUbxY z?Nua3sQ_r1Vk{0jzRk87UDGE65UFb6i}6}ZoD}`LUg44=!PM=I{FSb$+(h~ix; z7$j44hup3`tS(8+C#Enje!aEOllvn{Z}C7ChW>!dS*41DabpXknr`2Ov0cp)jYsEy zCod4g!L{FE|EK2}w7{)jIJAkx8VuRM(;OKr0W)V$%l{gMib{A?$GF;(>>bvm`|A*x z&!emCVjw%S%aAPRn)utQ*v6Y6qT!bJGg0V;9UHKEU?hq?RbQnpTsE2|HRMU6Q&CDO zk8go302lNyy>8 zX37dyj(}NSN(tK;I|1YC*%fwGR3htx%pRamC-j*aTR85CafjrAoZ0=#rPXk;WNB{yQh!3)bOK2)9t>;I;;rJs3dX>2z8tlZ?8NuA^zsO zC|&koNk79`j6%|1Dj^l+fGiU)ICg;+ti`04l-u~N zxeYZWAl`xZ{(c3HxGZrdzGJr6MA+bGbZk$xPmp`qJDABUZ-?QKdz>s(flo$yn7Qo) zeo;+@fiCpU!LYxuc&ab^-)@#=uf(f5;m9%Y@tx$!+d#Lt^ZNescQ&i-@v!qYbrH1G z%V4hVI^inLTV=kepRpZ(LLmoij!k^Ia4{7)K&u37QL-Ld%99K0_!c@>zl-9+o8ta} zSVICcfR09mUJDo`8u(28jpfxsAxK)Wi-E43Gi2ez_t5j$aG`N zyI!3kJ4zSFhi-&_Wi)=Hx$dMfjtZl3UE{;^qENZsH2b?lOVFY0h96jrNeyn>g(=sq8_;oOe0Bw7$8#RNPax+eRFsiEX8hF9#0 zmx;7j(KAYv!J!cXQiE*dYDKZjKWxY+Lhu9nC=KoWZK1jET^}f?%TtZF_k=$azOKoG zuqQcoOVX&l*U^J)IxgRt{BhslFvxX}ax1OqT^&&wx_TFXO41s)Y8ZRkELm06{%Hob zAuAGSVz6xLmqhQ_j6*ar5THk7#Mva&47BR`Qe; z(v4DCvHx2%A?3IWf8Afdxlc#*pHrX{t>@)~;s(WkMU`AG0z?+zgEAWJP?LX@_v*Yg z^}a{_D+xk<5=YAjuvJMY`y)IaaGIdW(zG1&!)6gv@`?|YS<@*oQ}e2Ge-`TyLQGEQ zO468Gu~2HS1@G#o%xnn*o0)0)K$=$N!v|fkpyT94;Qlo>{mW2o7TBI!{f@#z5DgR#w_n=t`HACzejOp0{vt0w70bumq{) zy7^)}N-92Zw?7Y!F*6xA`>HoMH$UCI9+IoLlc5lf_$vE=3KjFJsubSEQHBI|>(F6$ zxt-8b6Mc^45DT3h2@`nZvg8(XrVKq00uI@KFQ@J5=&szM=xWq4iG9sXvz1qT+w3&A zRY_bxa>G!!Ow$eRhEs8vnh@Oyi{AI73jc=O<)!>kt094jYs)7IhXsVq3xuVe&F(C~ zaBtY~PrgK(LHy;jGs^>K_Li_r_B=#^&8^G?Ot4?7E}2d>e1Fvouzhc0^!xEa_^Vb15roEnW@k@kQ}dhA1%eGK;f!ZSbI8OW2~#?jv$7$?|+FV4>t|aU^D#=KRWD1 zAfQauB}eiE3q%eeblRzSY#DMJ_BLNDWd`6of?M90m0Y1sY{V{Ch+PIJ>;Vsd6sMuP zfx6L?#D>-|3Ydr>f(_`ocrL5Oo$v$HdbmYGBPHArUUK!k%>O<%Cv8U##^|9g?Cs%A6e zyiR6W_}((o@GFzZ0Xz07@JTj*Y=EN6;oQWJsEPVE)_2&F>HWeU0)rNXPHRNb!Gof- zTR{UVmL{+BF3;*B@v zX@*uOer3JK?&=T-+pdcp3K{_E5E(V1Erst^(;B89boj{zdcftbG) zCsUaF`Ib{dqWj&WyzLP_^N_MLAWT%iRW~#C$fLYb>8xs~{G7jYM@f)SospUwpyiG}Wyr!;kzE(R|a>OJ@vty$+jl?V!FwC7tdA za^j!Y2E!PzaOTb2}-DeJS^_l{rSW76on{YP|7FLm#2e9HuF+xtPTm6!*0up68!k)v4)k- z5;tJQUJtV!dS%c9+CQG;(Jt>~zFKGZ?j`#R-23wbRc?KuQpf>+Sm&zk09|yJQ;82< zWoLmqG-Qg`nf1oSZTt`a^8s#LTeVwxPjN!;5# zkRJY07Fu(2cD&P0{Y5yXsmXdFx!+8uyRh-NW2SuX{sbz)DNW$(8q>VZTkGU@QX32c zX19-O$)+A&V}G6twz^73c4qDEj+r5bvY^Qv{e1s#khE@p`9fVncoPlvRQjan(lAjhL>*QO#s#Z*6Np{&8lq=chpE| z^|t9sB$!rzUFbo3r#qEX;}jeGwYr<9d@Ng&N|5jNl{Odm;I<@e6d-HH$OsBA&`5>( zw@k-7$FYzh1vDfzD8)S!pY1kRis1}Hv8aFsvVZXx+^3j9;eFVQuTrREh`9oK$^pj&v_Qrfb0%k`hmpe$YQri36Mw}JvpyOAWZ|AbC~_W#-rG;P@Dh1DV+ zlsMFX7uG_HS^3J-T2t8YSs03Q^J3D1*tf1)b`N_C96%bNGO519YiNQ)IBVjm(d@c- z3c4Ue3)J5yoygy^KV-m&I*AR#;u7|XRPqK&Qbi0Z{*ykO8d8mk_3{5PQ{eC_T75QsfGD} zTj4^czDf)K1)rN|IQF*{cUN2VcVf@tzLD@XcC21v)Hdyylhv}%#>0<)HpH3bJ8Q%C zntJ$8dd{-5JRuH%r6#d)q}PPjoWbi#Cx*altLq>TlVhdNaD zNieT)qFABHxIk!rJcVM{KpGqsTB%$-w#CAEW?`6c*{6Y5I`;aZg0s%Nb!8~MP<^IzE;0D$e zW1tb;7X*!5(WW8TSgEd+vWB1xPo3WmacH%TgFNSn6yL$Q3~NfujejtIsQ`;tecQ|m zZ*>$^y&I@6vQgnPEu0@BnzvhJk|{d0;_N7~oG87$>)WYrQLaz?q%{2Rd6KL^EGjzB zv?VRCh=col*_6D%6b(rNr`(r!@>M;N-zOr1s}6^>c#5x(P_h&QZ;JG-XOr=M0(kGh&<-6$lf z74B7&`ZL+EN=;$W4XeoI z{GYjzXBKsD&7=ZD^Cr?W7O`U*;HpL%wI>a134Ly%v&d`vr0|rC z=QMS6PSOyLm>hp>QHHYr85LZ$kEAqg5Y7@B&LU;v5>c4qnS0~#!}BXbl-vP#&)zfC zzlZdw+meGF)vo?xN)>5^22ifXtE>Lqugeum*5Gd zk78WeIhx5<1wvUKYltq`+kT9PqF0*tr6?xjX`{j#-~2<=;(r`qUHwB%VKU)ejDpza zkX@E_fZHX1K}$v7L90mzBpuSfKt4%A#P$XQ_J|i$C3MbJh=CX>R@Hsm%DM5$Fsii~ zV*T(Mzdn;yABozVZD_-ag%BI2O6P;@(#;^3{Etr6HdA=B2s-bsCa^h|O58wK;FLTN zgc%RIj8!nQ|4-Op?#}i$7q8!nXX5(tNTO>V@5OC@Z7M187o_s_oyxz|eP9TCH9Vk6 zXnu7-QgCZOjmfGJ*5vPqs!Ci<%0n5z&FxYOA1^UTB21e4%Q>LoS+l_%+4K%*7&?CO zF!XYJah~3g(f>6D_mV?DJiFUcZBiD-0$0x6L<^}SNu!LOMr;t4!sB9LBZh-`>@k5^ z&g~$79CU%a>W;a#;^8Ybr1isq=YzO7YbE~?)Zm!eMs5L4Uk*hGi>A{y%Q1QIh%2Xy zN2Is$NText@AD=ToNATc`T0DbeGJ8`$LBqc6i}}uMu)px=EX@tL*v6w01%mnn@HND``8K z|M5RZsCX_BdFzkPlX>QA>UFNh7W2!HR*q*k#DCjy2zpoXCN#|N{w&`^5o8fV(J9nL-}_=lo_lvXPx2= zquH_8L6}-aO<%A20@FNB|2H8VNq5?TZpU(u7zax6nKTR%w%xjQh2Q14d}}%N$of=t zqhB(~4i$TvL2XAf@NRr6;Q4`*W~P+ zhHaNHbTtQ@vz`rlw%f*2QHLwIPSr0h&s(R6r}8BPq=r>kIhs(UnSIP>kET$6c@&)R zx@YRMflb%Vz6MYA&Rih9M41Q}f!D*R%P8C|*VsEh)}U*)A}MU6K)4$Pmy$N<7@J}u z|F%^gKXZ}-06}em#J#zg$4xvBO- zy>$3Zh82iw7M<*!FfX8C`l`iU*BxQvE9?ClJ%&-jLfoSJ6<)RP7Uj5qA7Y`AZRGew zlL)KT8PNt(l{Lu{r0QQQGZoi0Mp?SN;r`T0UIASvnFk&+SO#BqL8r|i(J)sp;pOwl zBYLs1jzDCz-!q4o5-S}-BOyh}rZ5@jLR%6OjPt)*m=JN+i*T#!E22dEMcD8_6E^^X z%dq;7ki{QChDI|4K)<(ts9&m=h?SbzkkZWGZ-H4kxi% z%(8u+_+K!`rr4tBtf7suzl_@O@@e*~hZmP!(Hm^85eKxoAeRJp=qacIPq_XO&Q4kwt&CQogRDN?p>T7vgd)reHgzDsZ2Rgplx-%gXx^$c?q_GXtqkpA^#RXlf+OtSsKN|A!NC9GKJTk4PwM=@n z;jOhGt^{A;Z~y^BZ)6akYTzV|PXSp2KXd0pQg9lZ`Q?LuWB-123OQv4=+b=eg3Kj; z+>$~MqHy2ss&~X5zWKSS-!{n^F-GcPN4beFB76&oio#p4hmONjm^+OqHUm5SDjnI9 zcc-Mv*&XjV;Q{Pu@5Th*CB;OSc}Pa*S9oBzNV)rnk7w*naU*)sOOpsX-`Vmj=Zlw1 zDW-cD!zz7$sa`$m!8Z1BrJEIo0-tNG<4M{fe*c3$ZF2;z5hv}ebjeOY@l_MVaC7bm z+3EQg;isz$2dj2q$3-`A#{~xbZ3VS5L+M{R(SVFZBUh(%V_o2+%YG9 z0o2(7qqgE$0>&S-fP%A(NRKq-+u#TD?670@8l_xkV5FO77azsEu$aJ_u6k}jhAv@n zkwMemF-fhkB^h*E^0eTDtRs2$ug$u@(W*}(bD-aE96fBNVJ;y1OVk*^HB zD{~&%i^3J16CUEWhp>7kN6g{f#gJV-Z~&HnfTx|VrNr7>2YAMRs||T(h}6%FT?_p` z%7p2nxwsbGxx7_v&1NNd`uY7@I);T7B&W=506KR@>a^=k>>toa!`eR2Yw@E)o%!;S zVyNqsu@Dz24IeuDiGQINM4_ebNEC}EzP-S{70tzsuop)h)szIl0N+{vbuK;}o&c|Z zuvF1TzEnlkWgqL8uu_bttu(>#hj_(gPy02$F<7114$k{q2;*%ybEac7{207R<4CVKiHswkqA+IB`Vt4yDU~0 z!ZoHb#M|44>xxRXTFWz!+ZBARlOmRXC76Y4zcID#Kj9Gn!=wru)3d7cCaaLOeW)=v zG`Xe>;v?N?(#GLBd4}}B;g#c<|GE5a5DhU}<$TXvz{JyM4ptP@`4cP`*rMJk7VjUh zp(qWbfr@e1q9tG0O#QnS^Rn{}%pn9Bfe+2F?00oO`(q9G)8NId(DJm7T_vmajsupnJLvLDlsQIu9{`Pu2ympBFDhC6V_>nOedJf$Q`N!> zZf-zbnS1rC9>gU?le*HizD)VZe<49Xwso3<9;lz{4;zMZ98RPY{n>ze`m3=oPbDxT zTWW|!m^mQ+K+d3Xdk{dc-3{x1cFR+fNb|*ph=xpy&p%%c@jzO14_y~6X(q5%M+j<=)q%1U~yPgmKCvmLa<5tX&pr}gD zPXdoq8XEXwJ5ZAqelyXQE;6w%77!?9Q0#`_0r+$mphA7?a4&g%JzREwuTr7Esj9tg z6_Bd;%zyxm^ecrzJA+TsEkCj3PF%3xd_rK~IOx1~8ud~+i|YwIF$iZrLoDsjm}U*t zN^VsPP7)vl8Gn)=Q3S!wng~Z{4!~@p_tU@0Xp)M0%g%(UbEGGrqeJt;CmtUKHg7SV zPLj;YfGlGaR>~i{kZW6i8O?`(3qizXU~K5ay^>T5_bZTiGLn zX#5^LfL;uio1^__Xpt;kzaL?sL>7b3$WC@_86IzLwVh(?oR;}r7NW556wJ;q;Pwc|(!Q7_Zj^_PuUgZlfZOlcTc1+lDuTPnk_ROAbGy+Q=c`ifC9btI@sv)H=E!~EZLP`c+COtK@c2(}^f7>J zRy!Brt-7OGnY^c@&$B?o8$)|P=+K8rRD8Uo{}9O-h#zZ)(kN(Yd!4gdfE delta 11676 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 From 622b5a67c4c4df5e76b49c0df3f4c79e08dfbda1 Mon Sep 17 00:00:00 2001 From: ABBY CROSS Date: Mon, 17 Aug 2026 22:37:32 -0400 Subject: [PATCH 5/8] npm run gen-addon -- -p qiskit-addon-sqd --- .../qiskit-addon-sqd/guides/integrate-dice-solver.ipynb | 2 +- docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb | 4 ++-- docs/addons/qiskit-addon-sqd/index.mdx | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb b/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb index d346fc30054..9aada239aed 100644 --- a/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb +++ b/docs/addons/qiskit-addon-sqd/guides/integrate-dice-solver.ipynb @@ -18,7 +18,7 @@ "source": [ "# Scale SQD chemistry workflows with Dice solver\n", "\n", - "This guide shows how to use the Dice solver as an alternative SCI solver to diagonalize larger Fermionic problems beyond what the default PySCF solver can support. For information on how to install and use ``qiskit-addon-dice-solver``, [visit the documentation](https://qiskit.github.io/qiskit-addon-dice-solver/). For more details on the SQD code used in this example, see the [chemistry Hamiltonian tutorial](/docs/en/tutorials/sample-based-quantum-diagonalization)." + "This guide shows how to use the Dice solver as an alternative SCI solver to diagonalize larger Fermionic problems beyond what the default PySCF solver can support. For information on how to install and use ``qiskit-addon-dice-solver``, [visit the documentation](https://qiskit.github.io/qiskit-addon-dice-solver/). For more details on the SQD code used in this example, see the [chemistry Hamiltonian tutorial](/docs/tutorials/sample-based-quantum-diagonalization)." ] }, { diff --git a/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb b/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb index 7c5b12b9ad1..28405de7690 100644 --- a/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb +++ b/docs/addons/qiskit-addon-sqd/guides/quickstart.ipynb @@ -22,8 +22,8 @@ "\n", "For more explanatory end-to-end workflows that run on quantum hardware, check out the tutorials:\n", "\n", - "* [Sample-based quantum diagonalization](/docs/en/tutorials/sample-based-quantum-diagonalization): chemistry Hamiltonian workflow\n", - "* [Sample-based Krylov quantum diagonalization](/docs/en/tutorials/sample-based-krylov-quantum-diagonalization): fermionic lattice model workflow" + "* [Sample-based quantum diagonalization](/docs/tutorials/sample-based-quantum-diagonalization): chemistry Hamiltonian workflow\n", + "* [Sample-based Krylov quantum diagonalization](/docs/tutorials/sample-based-krylov-quantum-diagonalization): fermionic lattice model workflow" ] }, { diff --git a/docs/addons/qiskit-addon-sqd/index.mdx b/docs/addons/qiskit-addon-sqd/index.mdx index 1b2065261b0..6e50339f19e 100644 --- a/docs/addons/qiskit-addon-sqd/index.mdx +++ b/docs/addons/qiskit-addon-sqd/index.mdx @@ -11,9 +11,9 @@ SQD-based workflows involve first preparing one or more quantum states on a quan `qiskit-addon-sqd` can be used to classically process samples drawn from a variety of quantum circuits in practice. For example: -> 1. A variational circuit ansatz with parameters chosen such that sampling the circuit produces electronic configurations on which the target wavefunction (for example, the ground state) has significant support. This is appealing for chemistry applications where Hamiltonians can have millions of interaction terms [\[1\]](#ref1). For an example of this approach applied to chemistry using an LUCJ circuit, see the [tutorial for approximating the ground state energy of the N2 molecule](/docs/tutorials/sample-based-quantum-diagonalization). -> 2. A set of Krylov basis states are prepared over increasing time intervals. Assuming a good initial state and sparsity of the ground state, this approach is proven to converge efficiently. As one needs to prepare Trotterized time evolution circuits on a quantum device, this approach is best for applications to lattice models [\[2\]](#ref2) instead of complex many-body Hamiltonians like those for quantum chemistry. For an example of this approach applied to Fermionic lattice Hamiltonians, see the [tutorial for approximating the ground state energy of a simplified single-impurity Anderson model](/docs/tutorials/sample-based-krylov-quantum-diagonalization). -> 3. A set of Krylov basis states implemented with qDRIFT randomized compilation of the time evolution operator. This approach yields shorter-depth circuits compared to Trotter-based decompositions of the time evolution and so can be used for quantum chemistry Hamiltonians. This technique has been applied to the ground state energy of polycyclic aromatic hydrocarbons [\[6\]](#ref6). +> 1. A variational circuit ansatz with parameters chosen such that sampling the circuit produces electronic configurations on which the target wavefunction (for example, the ground state) has significant support. This is appealing for chemistry applications where Hamiltonians can have millions of interaction terms [\[1\]](#references). For an example of this approach applied to chemistry using an LUCJ circuit, see the [tutorial for approximating the ground state energy of the N2 molecule](/docs/tutorials/sample-based-quantum-diagonalization). +> 2. A set of Krylov basis states are prepared over increasing time intervals. Assuming a good initial state and sparsity of the ground state, this approach is proven to converge efficiently. As one needs to prepare Trotterized time evolution circuits on a quantum device, this approach is best for applications to lattice models [\[2\]](#references) instead of complex many-body Hamiltonians like those for quantum chemistry. For an example of this approach applied to Fermionic lattice Hamiltonians, see the [tutorial for approximating the ground state energy of a simplified single-impurity Anderson model](/docs/tutorials/sample-based-krylov-quantum-diagonalization). +> 3. A set of Krylov basis states implemented with qDRIFT randomized compilation of the time evolution operator. This approach yields shorter-depth circuits compared to Trotter-based decompositions of the time evolution and so can be used for quantum chemistry Hamiltonians. This technique has been applied to the ground state energy of polycyclic aromatic hydrocarbons [\[6\]](#references). ## Getting started From 99d7a1897c8dadb72ff91d47153edf19e1131534 Mon Sep 17 00:00:00 2001 From: ABBY CROSS Date: Mon, 17 Aug 2026 22:51:15 -0400 Subject: [PATCH 6/8] fix two straggler links --- docs/api/qiskit-addon-sqd/release-notes.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/qiskit-addon-sqd/release-notes.mdx b/docs/api/qiskit-addon-sqd/release-notes.mdx index ba5d4f59ed9..4c1883eef21 100644 --- a/docs/api/qiskit-addon-sqd/release-notes.mdx +++ b/docs/api/qiskit-addon-sqd/release-notes.mdx @@ -22,7 +22,7 @@ in_page_toc_max_heading_level: 2 * Added support for Python 3.13 and Python 3.14. No code changes were necessary, so older releases are expected to work on Python 3.13 and 3.14 too. -* [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") can now be called collectively from all processes of a multi-process (SPMD) execution, for example under MPI. When invoked this way, the `sci_solver` step runs on every process, so a custom, distributed `sci_solver` can spread each diagonalization across the available processes; the rest of the configuration-recovery loop runs on the control process alone, and the return value is the same on every process. Single-process behavior is unchanged. See [Support for multi-process and multi-threaded acceleration](guides/hpc-acceleration) for details on the package’s support for multi-process and multi-threaded acceleration. +* [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") can now be called collectively from all processes of a multi-process (SPMD) execution, for example under MPI. When invoked this way, the `sci_solver` step runs on every process, so a custom, distributed `sci_solver` can spread each diagonalization across the available processes; the rest of the configuration-recovery loop runs on the control process alone, and the return value is the same on every process. Single-process behavior is unchanged. See [Support for multi-process and multi-threaded acceleration](/docs/guides/hpc-acceleration) for details on the package’s support for multi-process and multi-threaded acceleration. @@ -98,7 +98,7 @@ in_page_toc_max_heading_level: 2 ### New Features -* Added a new function [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") to serve as the main entrypoint to the SQD algorithm. See the updated [tutorials](/docs/addons/qiskit-addon-sqd/tutorials/index) for a demonstration of how to use this function. +* Added a new function [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") to serve as the main entrypoint to the SQD algorithm. * [`qiskit_addon_sqd.fermion.solve_fermion()`](/docs/api/qiskit-addon-sqd/fermion#solve_fermion "qiskit_addon_sqd.fermion.solve_fermion") now accepts a `shift` argument used to shift states which have the wrong spin, $(H + shift * S^2)|ψ> = E|ψ>$. From a68c8326eed0110db2354e8d82c55aa4ee062ca1 Mon Sep 17 00:00:00 2001 From: abbycross Date: Mon, 17 Aug 2026 23:04:34 -0400 Subject: [PATCH 7/8] Apply suggestions from code review --- docs/api/qiskit-addon-sqd/release-notes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/qiskit-addon-sqd/release-notes.mdx b/docs/api/qiskit-addon-sqd/release-notes.mdx index 4c1883eef21..ec0adbc2279 100644 --- a/docs/api/qiskit-addon-sqd/release-notes.mdx +++ b/docs/api/qiskit-addon-sqd/release-notes.mdx @@ -22,7 +22,7 @@ in_page_toc_max_heading_level: 2 * Added support for Python 3.13 and Python 3.14. No code changes were necessary, so older releases are expected to work on Python 3.13 and 3.14 too. -* [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") can now be called collectively from all processes of a multi-process (SPMD) execution, for example under MPI. When invoked this way, the `sci_solver` step runs on every process, so a custom, distributed `sci_solver` can spread each diagonalization across the available processes; the rest of the configuration-recovery loop runs on the control process alone, and the return value is the same on every process. Single-process behavior is unchanged. See [Support for multi-process and multi-threaded acceleration](/docs/guides/hpc-acceleration) for details on the package’s support for multi-process and multi-threaded acceleration. +* [`qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()`](/docs/api/qiskit-addon-sqd/fermion#diagonalize_fermionic_hamiltonian "qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian") can now be called collectively from all processes of a multi-process (SPMD) execution, for example under MPI. When invoked this way, the `sci_solver` step runs on every process, so a custom, distributed `sci_solver` can spread each diagonalization across the available processes; the rest of the configuration-recovery loop runs on the control process alone, and the return value is the same on every process. Single-process behavior is unchanged. See [Support for multi-process and multi-threaded acceleration](/docs/addons/qiskit-addon-sqd/guides/hpc-acceleration) for details on the package’s support for multi-process and multi-threaded acceleration. From 57c8cb30f9b4cbb148cf66677e5e5518dc8577a2 Mon Sep 17 00:00:00 2001 From: ABBY CROSS Date: Mon, 17 Aug 2026 23:19:24 -0400 Subject: [PATCH 8/8] add to cspell ignore --- scripts/config/cspell/dictionaries/qiskit.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/config/cspell/dictionaries/qiskit.txt b/scripts/config/cspell/dictionaries/qiskit.txt index f82d5392db3..900a6afd75f 100644 --- a/scripts/config/cspell/dictionaries/qiskit.txt +++ b/scripts/config/cspell/dictionaries/qiskit.txt @@ -454,3 +454,11 @@ postselect postselected postselecting postselects +textrm +walltime +hcore +myci +mcscf +ncas +nelecas +binom \ No newline at end of file