From cbcfd5fae0b4c7a0d6e6d10c69d74f3925b051e9 Mon Sep 17 00:00:00 2001 From: Caleb Johnson Date: Fri, 13 Sep 2024 11:02:27 -0500 Subject: [PATCH] Adjust API to be more consistent in specifying the numbers of spin electrons and target hamming weights. Co-authored-by: Kevin J. Sung --- docs/tutorials/01_chemistry_hamiltonian.ipynb | 6 ++- qiskit_addon_sqd/configuration_recovery.py | 26 +++++------ qiskit_addon_sqd/subsampling.py | 4 +- .../subsample-hamming-76674dbaf6f411c2.yaml | 44 +++++++++++++++++++ 4 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 releasenotes/notes/subsample-hamming-76674dbaf6f411c2.yaml diff --git a/docs/tutorials/01_chemistry_hamiltonian.ipynb b/docs/tutorials/01_chemistry_hamiltonian.ipynb index 9e452ce..acb3e7f 100644 --- a/docs/tutorials/01_chemistry_hamiltonian.ipynb +++ b/docs/tutorials/01_chemistry_hamiltonian.ipynb @@ -315,7 +315,11 @@ "id": "851bc98e-9c08-4e78-9472-36301abc11d8", "metadata": {}, "source": [ - "First, we will transform the counts into a bitstring matrix and probability array for post-processing. Each row in the matrix represents one unique bitstring. Since qubits are normally indexed from the right of a bitstring, column ``0`` of the matrix represents qubit ``N``, and column ``N`` represents qubit ``0``." + "First, we will transform the counts into a bitstring matrix and probability array for post-processing.\n", + "\n", + "Each row in the matrix represents one unique bitstring. Since qubits are normally indexed from the right of a bitstring, column ``0`` represents qubit ``N-1``, and column ``N-1`` represents qubit ``0``, where ``N`` is the number of qubits.\n", + "\n", + "The alpha particles are represented in the column range ``[N / 2, N]``, and the beta particles are represented in the column range ``[0, N / 2)``." ] }, { diff --git a/qiskit_addon_sqd/configuration_recovery.py b/qiskit_addon_sqd/configuration_recovery.py index f8fa7cc..9d75fc3 100644 --- a/qiskit_addon_sqd/configuration_recovery.py +++ b/qiskit_addon_sqd/configuration_recovery.py @@ -30,7 +30,7 @@ def post_select_by_hamming_weight( - bitstring_matrix: np.ndarray, hamming_left: int, hamming_right: int + bitstring_matrix: np.ndarray, hamming_right: int, hamming_left: int ) -> np.ndarray: """ Post-select bitstrings based on the hamming weight of each half. @@ -38,8 +38,8 @@ def post_select_by_hamming_weight( Args: bitstring_matrix: A 2D array of ``bool`` representations of bit values such that each row represents a single bitstring - hamming_left: The target hamming weight of the left half of bitstrings hamming_right: The target hamming weight of the right half of bitstrings + hamming_left: The target hamming weight of the left half of bitstrings Returns: A mask signifying which samples were selected from the input matrix. @@ -60,8 +60,8 @@ def recover_configurations( bitstring_matrix: np.ndarray, probabilities: Sequence[float], avg_occupancies: np.ndarray, - hamming_left: int, - hamming_right: int, + num_elec_a: int, + num_elec_b: int, *, rand_seed: int | None = None, ) -> tuple[np.ndarray, np.ndarray]: @@ -78,15 +78,15 @@ def recover_configurations( avg_occupancies: A 1D array containing the mean occupancy of each orbital. It is assumed that ``avg_occupancies[i]`` corresponds to the orbital represented by column ``i`` in ``bitstring_matrix``. - hamming_left: The target hamming weight used for the left half of the bitstring - hamming_right: The target hamming weight used for the right half of the bitstring + num_elec_a: The number of spin-up electrons in the system. + num_elec_b: The number of spin-down electrons in the system. rand_seed: A seed to control random behavior Returns: A corrected bitstring matrix and an updated probability array """ - if hamming_left < 0 or hamming_right < 0: - raise ValueError("Hamming weights must be non-negative integers.") + if num_elec_a < 0 or num_elec_b < 0: + raise ValueError("The numbers of electrons must be specified as non-negative integers.") # First, we need to flip the orbitals such that @@ -95,8 +95,8 @@ def recover_configurations( bs_corrected = _bipartite_bitstring_correcting( bitstring, avg_occupancies, - hamming_left, - hamming_right, + num_elec_a, + num_elec_b, rand_seed=rand_seed, ) bs_str = np.array2string(bs_corrected.astype(int), separator="")[1:-1] @@ -170,8 +170,8 @@ def _p_flip_1_to_0(ratio_exp: float, occ: float, eps: float = 0.01) -> float: def _bipartite_bitstring_correcting( bit_array: np.ndarray, avg_occupancies: np.ndarray, - hamming_left: int, hamming_right: int, + hamming_left: int, rand_seed: int | None = None, ) -> np.ndarray: """ @@ -180,8 +180,8 @@ def _bipartite_bitstring_correcting( Args: bit_array: A 1D array of ``bool`` representations of bit values avg_occupancies: A 1D array containing the mean occupancy of each orbital. - hamming_left: The target hamming weight used for the left half of the bitstring - hamming_right: The target hamming weight used for the right half of the bitstring + hamming_right: The target hamming weight used for the left half of the bitstring + hamming_left: The target hamming weight used for the right half of the bitstring rand_seed: A seed to control random behavior Returns: diff --git a/qiskit_addon_sqd/subsampling.py b/qiskit_addon_sqd/subsampling.py index 67c1c88..0a68ca6 100644 --- a/qiskit_addon_sqd/subsampling.py +++ b/qiskit_addon_sqd/subsampling.py @@ -32,8 +32,8 @@ def postselect_and_subsample( bitstring_matrix: np.ndarray, probabilities: np.ndarray, - hamming_left: int, hamming_right: int, + hamming_left: int, samples_per_batch: int, num_batches: int, rand_seed: int | None = None, @@ -52,8 +52,8 @@ def postselect_and_subsample( bitstring_matrix: A 2D array of ``bool`` representations of bit values such that each row represents a single bitstring. probabilities: A 1D array specifying a probability distribution over the bitstrings - hamming_left: The target hamming weight for the left half of sampled bitstrings hamming_right: The target hamming weight for the right half of sampled bitstrings + hamming_left: The target hamming weight for the left half of sampled bitstrings samples_per_batch: The number of samples to draw for each batch num_batches: The number of batches to generate rand_seed: A seed to control random behavior diff --git a/releasenotes/notes/subsample-hamming-76674dbaf6f411c2.yaml b/releasenotes/notes/subsample-hamming-76674dbaf6f411c2.yaml new file mode 100644 index 0000000..253e6c1 --- /dev/null +++ b/releasenotes/notes/subsample-hamming-76674dbaf6f411c2.yaml @@ -0,0 +1,44 @@ +--- +upgrade: + - | + The :func:`qiskit_addon_sqd.subsampling.postselect_and_subsample` and :func:`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 + + .. code-block:: python + + from qiskit_addon_sqd.configuration_recovery import post_select_by_hamming_weight + from qiskit_addon_sqd.subsampling import postselect_and_subsample + + bs_mat = post_select_by_hamming_weight(bs_mat_full, num_elec_b, num_elec_a) + + ... + + batches = postselect_and_subsample( + bs_mat, + probs_arr, + num_elec_b, + num_elec_a, + samples_per_batch, + n_batches, + ) + + should be changed to + + .. code-block:: python + + from qiskit_addon_sqd.configuration_recovery import post_select_by_hamming_weight + from qiskit_addon_sqd.subsampling import postselect_and_subsample + + bs_mat = post_select_by_hamming_weight(bs_mat_full, num_elec_a, num_elec_b) + + ... + + batches = postselect_and_subsample( + bs_mat, + probs_arr, + num_elec_a, + num_elec_b, + samples_per_batch, + n_batches, + )