diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 2a5e77a..2686af4 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -12,9 +12,9 @@ on:
branches:
- main
- 'stable/**'
-
jobs:
- build_and_deploy_docs:
+ build:
+ name: Build docs
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
@@ -34,21 +34,24 @@ jobs:
shell: bash
run: |
tox -edocs
- - name: Prepare docs artifact
- if: always()
- shell: bash
- run: |
- mkdir artifact
- cp -a docs/_build/html artifact/addon_sqd_html_docs
- name: Upload docs artifact
if: always()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-pages-artifact@v3
with:
- name: addon_sqd_html_docs
- path: ./artifact
- - name: Deploy docs
- if: ${{ github.ref == 'refs/heads/stable/0.3' }}
- uses: peaceiris/actions-gh-pages@v4
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ./docs/_build/html/
+ path: docs/_build/html
+
+ deploy:
+ name: Deploy docs
+ if: ${{ github.ref == 'refs/heads/stable/0.3' }}
+ needs: build
+ permissions:
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/test_development_versions.yml b/.github/workflows/test_development_versions.yml
deleted file mode 100644
index 9b4b6b4..0000000
--- a/.github/workflows/test_development_versions.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: Development version tests
-
-on:
- push:
- branches:
- - main
- - 'stable/**'
- pull_request:
- branches:
- - main
- - 'stable/**'
- schedule:
- - cron: '0 1 * * *'
-
-jobs:
- tests:
- runs-on: ubuntu-latest
- timeout-minutes: 30
- strategy:
- max-parallel: 4
- matrix:
- python-version: '3.10'
- steps:
- - uses: actions/checkout@v4
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v5
- with:
- python-version: ${{ matrix.python-version }}
- - name: Install dependencies (development versions)
- shell: bash
- run: |
- python -m pip install --upgrade pip tox
- python -m pip install extremal-python-dependencies==0.0.3
- extremal-python-dependencies pin-dependencies \
- "qiskit @ git+https://github.com/Qiskit/qiskit.git" \
- "pyscf @ git+https://github.com/pyscf/pyscf.git" \
- --inplace
- - name: Test using tox environment
- shell: bash
- run: |
- toxpyversion=$(echo ${{ matrix.python-version }} | sed -E 's/^([0-9]+)\.([0-9]+).*$/\1\2/')
- tox -epy${toxpyversion}
- tox -epy${toxpyversion}-notebook
diff --git a/.github/workflows/test_minimum_versions.yml b/.github/workflows/test_minimum_versions.yml
deleted file mode 100644
index 9fe0dd2..0000000
--- a/.github/workflows/test_minimum_versions.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Minimum version tests
-
-on:
- push:
- branches:
- - main
- - 'stable/**'
- pull_request:
- branches:
- - main
- - 'stable/**'
-
-jobs:
- tests:
- runs-on: ubuntu-latest
- timeout-minutes: 30
- strategy:
- max-parallel: 4
- matrix:
- python-version: '3.12'
- steps:
- - uses: actions/checkout@v4
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v5
- with:
- python-version: ${{ matrix.python-version }}
- - name: Install dependencies (minimum versions)
- shell: bash
- run: |
- python -m pip install --upgrade pip
- python -m pip install extremal-python-dependencies==0.0.3
- pip install "tox==$(extremal-python-dependencies get-tox-minversion)"
- extremal-python-dependencies pin-dependencies-to-minimum --inplace
- - name: Test using tox environment
- shell: bash
- run: |
- toxpyversion=$(echo ${{ matrix.python-version }} | sed -E 's/^([0-9]+)\.([0-9]+).*$/\1\2/')
- tox -epy${toxpyversion}
- tox -epy${toxpyversion}-notebook
diff --git a/.mergify.yml b/.mergify.yml
new file mode 100644
index 0000000..899cc69
--- /dev/null
+++ b/.mergify.yml
@@ -0,0 +1,8 @@
+pull_request_rules:
+ - name: backport
+ conditions:
+ - label=stable backport potential
+ actions:
+ backport:
+ branches:
+ - stable/0.3
diff --git a/README.md b/README.md
index e84493a..1662d09 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ Qiskit addons are a collection of modular tools for building utility-scale workl
This package contains the Qiskit addon for sample-based quantum diagonalization (SQD) -- a technique for finding eigenvalues and eigenvectors of quantum operators, such as a quantum system Hamiltonian, using quantum and distributed classical computing together.
-Classical distributed computing is used to process samples obtained from a quantum processor, and to project and diagonalize a target Hamiltonian in a subspace spanned by them. This allows SQD to be robust to samples corrupted by quantum noise and deal with large Hamiltonians, such as chemistry Hamiltonians with millions of interaction terms, beyond the reach of any exact diagonalization methods.
+Classical distributed computing is used to process samples obtained from a quantum processor and to project and diagonalize a target Hamiltonian in a subspace spanned by them. This allows SQD to be robust to samples corrupted by quantum noise and deal with large Hamiltonians, such as chemistry Hamiltonians with millions of interaction terms, beyond the reach of any exact diagonalization methods.
The SQD tool can target Hamiltonians expressed as linear combination of Pauli operators, or second-quantized fermionic operators. The input samples are obtained by quantum circuits defined by the user, which are believed to be good representations of eigenstates (e.g. the ground state) of a target operator. The convergence rate of SQD as a function of the number of samples improves with the sparseness of the target eigenstate.
@@ -53,11 +53,11 @@ The [`qiskit_addon_sqd.fermion.solve_fermion()`](qiskit_addon_sqd/fermion.py) fu
##### Choosing subspace dimensions
-The choice of the subspace dimension affects the accuracy and runtime of the eigenstate solver. The larger the subspace the more accurate the calculation, at the cost of increasing the runtime and memory requirements. It is not known *a priori* the optimal subspace size, thus a convergence study with the subspace dimension may be performed, as described in this [example](docs/how_tos/choose_subspace_dimension.ipynb).
+The choice of the subspace dimension affects the accuracy and runtime of the eigenstate solver. The larger the subspace the more accurate the calculation, at the cost of increasing the runtime and memory requirements. The optimal subspace size for a given system is not known, thus a convergence study with the subspace dimension may be performed as described in this [example](docs/how_tos/choose_subspace_dimension.ipynb).
##### The subspace dimension is set indirectly
-In this package, the user controls the number of bitstrings (see the `samples_per_batch` argument in [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](qiskit_addon_sqd/subsampling.py)) contained in each subspace. The value of this argument determines an upper bound to the subspace dimension in the case of quantum chemistry applications. See this [example](docs/how_tos/select_open_closed_shell.ipynb) for more details.
+In this package, the user controls the number of bitstrings (see the `samples_per_batch` argument in [`qiskit_addon_sqd.subsampling.postselect_and_subsample()`](qiskit_addon_sqd/subsampling.py)) contained in each subspace. The value of this argument sets an upper bound to the subspace dimension in the case of quantum chemistry applications. See this [example](docs/how_tos/select_open_closed_shell.ipynb) for more details.
----------------------------------------------------------------------------------------------------
diff --git a/docs/_static/images/qiskit-dark-logo.svg b/docs/_static/images/qiskit-dark-logo.svg
new file mode 100644
index 0000000..b520890
--- /dev/null
+++ b/docs/_static/images/qiskit-dark-logo.svg
@@ -0,0 +1,178 @@
+
+
diff --git a/docs/_static/images/qiskit-light-logo.svg b/docs/_static/images/qiskit-light-logo.svg
new file mode 100644
index 0000000..25b27dd
--- /dev/null
+++ b/docs/_static/images/qiskit-light-logo.svg
@@ -0,0 +1,178 @@
+
+
diff --git a/docs/how_tos/benchmark_pauli_projection.ipynb b/docs/how_tos/benchmark_pauli_projection.ipynb
index 68f6b17..8221444 100644
--- a/docs/how_tos/benchmark_pauli_projection.ipynb
+++ b/docs/how_tos/benchmark_pauli_projection.ipynb
@@ -64,19 +64,25 @@
"$1\\rightarrow \\textrm{True}$.\n",
"\n",
"To represent the action of each Pauli operator in a computational basis state\n",
- "we will assign three variables to it: `diag`, `sign`, `imag`. \n",
+ "we will assign three variables to it: `diag`, `sign`, `imag`.\n",
+ "\n",
"- `diag` labels whether the operator is diagonal:\n",
+ "\n",
" - $\\textrm{diag}(I) = \\textrm{True}$\n",
" - $\\textrm{diag}(\\sigma_x) = \\textrm{False}$\n",
" - $\\textrm{diag}(\\sigma_y) = \\textrm{False}$\n",
" - $\\textrm{diag}(\\sigma_z) = \\textrm{True}$\n",
+ "\n",
"- `sign` Identifies if there is a sign change in the matrix element connected \n",
"to either 0 or 1:\n",
+ "\n",
" - $\\textrm{diag}(I) = \\textrm{False}$\n",
" - $\\textrm{diag}(\\sigma_x) = \\textrm{False}$\n",
" - $\\textrm{diag}(\\sigma_y) = \\textrm{True}$\n",
" - $\\textrm{diag}(\\sigma_z) = \\textrm{True}$\n",
+ "\n",
"- `imag` Identifies if there is a complex component to the matrix element:\n",
+ "\n",
" - $\\textrm{diag}(I) = \\textrm{False}$\n",
" - $\\textrm{diag}(\\sigma_x) = \\textrm{False}$\n",
" - $\\textrm{diag}(\\sigma_y) = \\textrm{False}$\n",
diff --git a/docs/how_tos/choose_subspace_dimension.ipynb b/docs/how_tos/choose_subspace_dimension.ipynb
index 8bbfbc5..bb9557f 100644
--- a/docs/how_tos/choose_subspace_dimension.ipynb
+++ b/docs/how_tos/choose_subspace_dimension.ipynb
@@ -17,9 +17,7 @@
"id": "a6755afb-ca1e-4473-974b-ba89acc8abce",
"metadata": {},
"source": [
- "### First we will specify the molecule and its properties\n",
- "\n",
- "In this example, we will approximate the ground state energy of an $\\textrm{N}_{2}$ molecule."
+ "Specify the molecule and its properties."
]
},
{
@@ -57,9 +55,7 @@
"id": "c58e988c-a109-44cd-a975-9df43250c318",
"metadata": {},
"source": [
- "### Generate a dummy counts dictionary to proxy samples taken from a QPU\n",
- "\n",
- "Here, we randomly generate bitstrings sampled from the uniform distribution. SQD can effectively estimate the ground state of $N_2$ using uniformly sampled bitstrings; however, that is not the case for more complex molecules."
+ "Generate some dummy counts to proxy QPU samples."
]
},
{
@@ -83,9 +79,7 @@
"id": "851bc98e-9c08-4e78-9472-36301abc11d8",
"metadata": {},
"source": [
- "### Transform the counts dict into a bitstring matrix and probability array for post-processing\n",
- "\n",
- "In order to speed up the bitwise processing required in this workflow, we use Numpy arrays to hold representations of the bitstrings and sampling frequencies."
+ "Convert the counts to a bitstring matrix"
]
},
{
@@ -107,16 +101,7 @@
"id": "eb704101-0fe8-4d12-b572-b1d844e35a90",
"metadata": {},
"source": [
- "### Iteratively refine the samples using SQD and approximate the ground state\n",
- "\n",
- "\n",
- "Let's wrap the self-consisten configuration recovery loop into a function\n",
- "\n",
- "There are a few user-controlled options which are important for this technique:\n",
- "- ``iterations``: Number of self-consistent configuration recovery iterations\n",
- "- ``n_batches``: Number of batches of configurations used by the different calls to the eigenstate solver\n",
- "- ``samples_per_batch``: Number of unique configurations to include in each batch\n",
- "- ``max_davidson_cycles``: Maximum number of Davidson cycles to run during ground state approximation"
+ "Define an SQD function, which we will call in a loop with increasing batch sizes."
]
},
{
@@ -223,6 +208,14 @@
" return e_hist.flatten(), d_hist.flatten()"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "82b062a3-d4ca-41e2-9b00-4a394f83cbdd",
+ "metadata": {},
+ "source": [
+ "Call SQD with increasing batch sizes."
+ ]
+ },
{
"cell_type": "code",
"execution_count": 5,
diff --git a/docs/how_tos/integrate_dice_solver.ipynb b/docs/how_tos/integrate_dice_solver.ipynb
new file mode 100644
index 0000000..02417e5
--- /dev/null
+++ b/docs/how_tos/integrate_dice_solver.ipynb
@@ -0,0 +1,168 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "65adf860-4443-494f-ad90-5d8ea444ac4e",
+ "metadata": {},
+ "source": [
+ "# Scale past 30 orbitals with Dice solver\n",
+ "\n",
+ "For information on how to install and use ``qiskit-addon-dice-solver``, [visit the docs](https://qiskit.github.io/qiskit-addon-dice-solver/).\n",
+ "\n",
+ "For more details on the SQD code used in this example, check out [tutorial 1](https://qiskit.github.io/qiskit-addon-obp/tutorials/01_chemistry_hamiltonian.html)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "baf7d074-4443-4695-875e-65f7fb8cef25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%%capture\n",
+ "\n",
+ "import os\n",
+ "\n",
+ "import numpy as np\n",
+ "from pyscf import ao2mo, tools\n",
+ "from qiskit_addon_dice_solver import solve_dice\n",
+ "from qiskit_addon_sqd.configuration_recovery import recover_configurations\n",
+ "from qiskit_addon_sqd.counts import counts_to_arrays, generate_counts_uniform\n",
+ "from qiskit_addon_sqd.fermion import (\n",
+ " bitstring_matrix_to_sorted_addresses,\n",
+ " flip_orbital_occupancies,\n",
+ ")\n",
+ "from qiskit_addon_sqd.subsampling import postselect_and_subsample\n",
+ "\n",
+ "# Specify molecule properties\n",
+ "num_orbitals = 16\n",
+ "num_elec_a = num_elec_b = 5\n",
+ "open_shell = False\n",
+ "spin_sq = 0\n",
+ "\n",
+ "# Read in molecule from disk\n",
+ "active_space_path = os.path.abspath(os.path.join(\"..\", \"molecules\", \"n2_fci.txt\"))\n",
+ "mf_as = tools.fcidump.to_scf(active_space_path)\n",
+ "hcore = mf_as.get_hcore()\n",
+ "eri = ao2mo.restore(1, mf_as._eri, num_orbitals)\n",
+ "nuclear_repulsion_energy = mf_as.mol.energy_nuc()\n",
+ "\n",
+ "# Create a seed to control randomness throughout this workflow\n",
+ "rand_seed = 42\n",
+ "\n",
+ "# Generate random samples\n",
+ "counts_dict = generate_counts_uniform(10_000, num_orbitals * 2, rand_seed=rand_seed)\n",
+ "\n",
+ "# Convert counts into bitstring and probability arrays\n",
+ "bitstring_matrix_full, probs_arr_full = counts_to_arrays(counts_dict)\n",
+ "\n",
+ "# SQSD options\n",
+ "iterations = 5\n",
+ "\n",
+ "# Eigenstate solver options\n",
+ "n_batches = 5\n",
+ "samples_per_batch = 300\n",
+ "max_davidson_cycles = 200\n",
+ "\n",
+ "# Self-consistent configuration recovery loop\n",
+ "occupancies_bitwise = None # orbital i corresponds to column i in bitstring matrix\n",
+ "e_hist = np.zeros((iterations, n_batches))\n",
+ "for i in range(iterations):\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 occupancies_bitwise 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",
+ " occupancies_bitwise,\n",
+ " num_elec_a,\n",
+ " num_elec_b,\n",
+ " # rand_seed=rand_seed,\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",
+ " num_elec_a,\n",
+ " num_elec_b,\n",
+ " samples_per_batch,\n",
+ " n_batches,\n",
+ " # rand_seed=rand_seed,\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_occs = np.zeros((n_batches, 2 * num_orbitals))\n",
+ " for j in range(n_batches):\n",
+ " addresses = bitstring_matrix_to_sorted_addresses(batches[j], open_shell=open_shell)\n",
+ " energy_sci, wf_mags, avg_occs = solve_dice(\n",
+ " addresses,\n",
+ " active_space_path,\n",
+ " os.path.abspath(\".\"),\n",
+ " spin_sq=spin_sq,\n",
+ " max_davidson=max_davidson_cycles,\n",
+ " clean_working_dir=True,\n",
+ " mpirun_options=[\"-n\", \"8\"],\n",
+ " )\n",
+ " int_e[j] = energy_sci\n",
+ " int_occs[j, :num_orbitals] = avg_occs[0]\n",
+ " int_occs[j, num_orbitals:] = avg_occs[1]\n",
+ "\n",
+ " # Combine batch results\n",
+ " avg_occupancy = np.mean(int_occs, axis=0)\n",
+ " # The occupancies from the solver should be flipped to match the bits in the bitstring matrix.\n",
+ " occupancies_bitwise = flip_orbital_occupancies(avg_occupancy)\n",
+ "\n",
+ " # Track optimization history\n",
+ " e_hist[i, :] = int_e"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "99709a88-f9ec-4dbc-a561-e682f90aa4c5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Exact energy: -109.10288938\n",
+ "Estimated energy: -109.06093312312994\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"Exact energy: -109.10288938\")\n",
+ "print(f\"Estimated energy: {np.min(e_hist[-1]) + nuclear_repulsion_energy}\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/index.rst b/docs/index.rst
index 820e255..217155e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -39,12 +39,12 @@ The :func:`qiskit_addon_sqd.fermion.solve_fermion` function is multithreaded and
Choosing subspace dimensions
----------------------------
-The choice of the subspace dimension affects the accuracy and runtime of the eigenstate solver. The larger the subspace the more accurate the calculation, at the cost of increasing the runtime and memory requirements. It is not known *a priori* the optimal subspace size, thus a convergence study with the subspace dimension may be performed, as described in this `guide `_.
+The choice of the subspace dimension affects the accuracy and runtime of the eigenstate solver. The larger the subspace the more accurate the calculation, at the cost of increasing the runtime and memory requirements. The optimal subspace size of a given system is not known, thus a convergence study with the subspace dimension may be performed, as described in this `guide `_.
The subspace dimension is set indirectly
----------------------------------------
-In this package, the user controls the number of bitstrings contained in each subspace with the `samples_per_batch` argument in :func:`.qiskit_addon_sqd.subsampling.postselect_and_subsample`. The value of this argument determines an upper bound to the subspace dimension in the case of quantum chemistry applications. See this `example `_ for more details.
+In this package, the user controls the number of bitstrings contained in each subspace with the `samples_per_batch` argument in :func:`.qiskit_addon_sqd.subsampling.postselect_and_subsample`. The value of this argument sets an upper bound to the subspace dimension in the case of quantum chemistry applications. See this `example `_ for more details.
Deprecation Policy
------------------
diff --git a/docs/install.rst b/docs/install.rst
index cac7005..1b77a89 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -3,7 +3,7 @@ Installation Instructions
Let's see how to install the package. The first
thing to do is choose how you're going to run and install the
-packages. There are two primary ways to do this:
+package. There are two primary ways to do this:
- :ref:`Option 1`
- :ref:`Option 2`
@@ -23,13 +23,6 @@ Activate your new environment.
source /path/to/virtual/environment/bin/activate
-Note: If you are using Windows, use the following commands in PowerShell:
-
-.. code:: pwsh
-
- python3 -m venv c:\path\to\virtual\environment
- c:\path\to\virtual\environment\Scripts\Activate.ps1
-
.. _Option 1:
diff --git a/docs/tutorials/01_chemistry_hamiltonian.ipynb b/docs/tutorials/01_chemistry_hamiltonian.ipynb
index d300233..3db838b 100644
--- a/docs/tutorials/01_chemistry_hamiltonian.ipynb
+++ b/docs/tutorials/01_chemistry_hamiltonian.ipynb
@@ -340,6 +340,7 @@
"### Iteratively refine the samples using configuration recovery and approximate the ground state at each iteration\n",
"\n",
"There are a few user-controlled options which are important for this technique:\n",
+ "\n",
"- ``iterations``: Number of self-consistent configuration recovery iterations\n",
"- ``n_batches``: Number of batches of configurations used by the different calls to the eigenstate solver\n",
"- ``samples_per_batch``: Number of unique configurations to include in each batch\n",
diff --git a/pyproject.toml b/pyproject.toml
index 39294e3..12b33d4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,7 +13,6 @@ classifiers = [
"License :: OSI Approved :: Apache Software License",
"Natural Language :: English",
"Operating System :: POSIX :: Linux",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
@@ -27,25 +26,22 @@ dependencies = [
"qiskit>=1.2",
"numpy>=1.26",
"pyscf>=2.5",
- "jaxlib>=0.4.17",
- "jax>=0.4",
- "scipy>=0.13",
+ "jaxlib>=0.4.31",
+ "jax>=0.4.31",
+ "scipy>=1.14.1",
]
[project.optional-dependencies]
dev = [
"qiskit-addon-sqd[test,nbtest,lint,docs]",
]
-basetest = [
+test = [
"tox>=4.0",
"pytest>=8.0",
"pytest-cov>=5.0",
]
-test = [
- "qiskit-addon-sqd[basetest]",
-]
nbtest = [
- "qiskit-addon-sqd[basetest]",
+ "qiskit-addon-sqd[test]",
"nbmake>=1.5.0",
]
style = [
@@ -69,7 +65,7 @@ notebook-dependencies = [
"qiskit-ibm-runtime",
]
docs = [
- "qiskit-addon-sqd[basetest,notebook-dependencies]",
+ "qiskit-addon-sqd[test,notebook-dependencies]",
"qiskit-sphinx-theme~=2.0.0",
"jupyter-sphinx",
"sphinx-design",
diff --git a/qiskit_addon_sqd/configuration_recovery.py b/qiskit_addon_sqd/configuration_recovery.py
index f2040bb..e2ba2ae 100644
--- a/qiskit_addon_sqd/configuration_recovery.py
+++ b/qiskit_addon_sqd/configuration_recovery.py
@@ -62,6 +62,7 @@ def recover_configurations(
avg_occupancies: np.ndarray,
hamming_left: int,
hamming_right: int,
+ *,
rand_seed: int | None = None,
) -> tuple[np.ndarray, np.ndarray]:
"""
diff --git a/qiskit_addon_sqd/counts.py b/qiskit_addon_sqd/counts.py
index b4063e1..1a1d453 100644
--- a/qiskit_addon_sqd/counts.py
+++ b/qiskit_addon_sqd/counts.py
@@ -31,10 +31,10 @@
def counts_to_arrays(counts: dict[str, float | int]) -> tuple[np.ndarray, np.ndarray]:
"""
- Convert a counts dictionary into arrays.
+ Convert a counts dictionary into a bitstring matrix and a probability array.
Args:
- counts: The dictionary to convert
+ counts: The counts dictionary to convert
Returns:
A tuple containing:
diff --git a/qiskit_addon_sqd/fermion.py b/qiskit_addon_sqd/fermion.py
index 9ffeb78..2d278ce 100644
--- a/qiskit_addon_sqd/fermion.py
+++ b/qiskit_addon_sqd/fermion.py
@@ -42,6 +42,7 @@ def solve_fermion(
addresses: tuple[np.ndarray, np.ndarray],
hcore: np.ndarray,
eri: np.ndarray,
+ *,
spin_sq: int | None = None,
max_davidson: int = 100,
verbose: int | None = None,
@@ -242,11 +243,11 @@ def flip_orbital_occupancies(occupancies: np.ndarray) -> np.ndarray:
This function reformats a 1D array of spin-orbital occupancies formatted like:
- ``[occ_a_0, occ_a_1, occ_a_N, occ_b_0, ..., occ_b_N]``
+ ``[occ_a_1, occ_a_2, ..., occ_a_N, occ_b_1, ..., occ_b_N]``
To an array formatted like:
- ``[occ_a_N, ..., occ_a_0, occ_b_N, ..., occ_b_0]``
+ ``[occ_a_N, ..., occ_a_1, occ_b_N, ..., occ_b_1]``
where ``N`` is the number of spatial orbitals.
"""
@@ -264,11 +265,12 @@ def bitstring_matrix_to_sorted_addresses(
bitstring_matrix: np.ndarray, open_shell: bool = False
) -> tuple[np.ndarray, np.ndarray]:
"""
- Convert a bitstring matrix into base-10 address representation.
+ Convert a bitstring matrix into a sorted array of unique, unsigned base-10 representations.
- This function separates each bitstring in ``bitstring_matrix`` in half, translates
- each set of bits into integer representations, and appends them to their respective
- lists. Those lists are sorted and output from this function.
+ This function separates each bitstring in ``bitstring_matrix`` in half, flips the
+ bits and 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.
Args:
bitstring_matrix: A 2D array of ``bool`` representations of bit
@@ -280,7 +282,7 @@ def bitstring_matrix_to_sorted_addresses(
and right bitstrings.
Returns:
- A length-2 tuple of sorted, base-10 determinant addresses representing the left
+ A length-2 tuple of sorted, unique base-10 determinant addresses representing the left
and right halves of the bitstrings, respectively.
"""
num_orbitals = bitstring_matrix.shape[1] // 2
diff --git a/qiskit_addon_sqd/qubit.py b/qiskit_addon_sqd/qubit.py
index f639349..f58efb0 100644
--- a/qiskit_addon_sqd/qubit.py
+++ b/qiskit_addon_sqd/qubit.py
@@ -38,6 +38,7 @@
def solve_qubit(
bitstring_matrix: np.ndarray,
hamiltonian: SparsePauliOp,
+ *,
verbose: bool = False,
**scipy_kwargs,
) -> tuple[np.ndarray, np.ndarray]:
@@ -82,6 +83,7 @@ def solve_qubit(
def project_operator_to_subspace(
bitstring_matrix: np.ndarray,
hamiltonian: SparsePauliOp,
+ *,
verbose: bool = False,
) -> spmatrix:
"""
@@ -163,8 +165,9 @@ def matrix_elements_from_pauli(
.. note::
The bitstrings in the ``bitstring_matrix`` must be sorted and unique according
to their base-10 representation. Otherwise the projection will return wrong
- results. We do not explicitly check for uniqueness and order because this
- can be rather time consuming.
+ results. This function does not explicitly check for uniqueness and order because
+ this can be rather time consuming. See :func:`qiskit_addon_sqd.qubit.sort_and_remove_duplicates`
+ for a simple way to ensure your bitstring matrix is well-formatted.
.. note::
This function relies on ``jax`` to efficiently perform some calculations. ``jax``
@@ -180,9 +183,9 @@ def matrix_elements_from_pauli(
pauli: A Pauli operator.
Returns:
- First array corresponds to the nonzero matrix elements
- Second array corresponds to the row indices of the elements
- Third array corresponds to the column indices of the elements
+ A 1D array corresponding to the nonzero matrix elements
+ A 1D array corresponding to the row indices of the elements
+ A 1D array corresponding to the column indices of the elements
Raises:
ValueError: Bitstrings (rows) in ``bitstring_matrix`` must have length < ``64``.