Release Notes¶
0.14.0¶
New Features¶
qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()now accepts sampled bitstrings as a two-dimensional NumPy boolean array in addition to a QiskitBitArray.
Adds a guide showing how to use fulqrum as a subspace solver for fermionic systems. To install the optional dependency, use the
fulqrumextra:pip install 'qiskit-addon-sqd[fulqrum]'
Adds a guide showing how to use the SBD eigensolver as a subspace solver for fermionic systems. To install the optional dependency, use the
sbdextra:pip install 'qiskit-addon-sqd[sbd]'
Adds the
qiskit_addon_sqd.trimmodule, containingTrimPolicy. This implements trim SQD, a schedule that treats the subsampled batches as candidates to be screened rather than as independent estimates: each batch is diagonalized and trimmed down to the CI strings carrying the largest weight, and the survivors of all the batches are merged and diagonalized together. The merged diagonalization is what the iteration reports, and its own trimmed strings seed the next one.An iteration therefore costs
num_batches + 1diagonalizations rather thannum_batches. Screening only selects among batches that differ, soTrimPolicydraws them as a single pool ofsamples_per_batch * num_batchesbitstrings divided among the batches, leaving no bitstring in more than one. That follows from what the schedule does and is not separately configurable.
Adds a guide covering trim SQD, including how to bound the subspace that trimming produces and how to check whether the screening step is helping on a given system.
diagonalize_fermionic_hamiltonian()has a newpolicyargument, which selects the schedule each iteration follows: how the sampled configurations become subspaces, whether one round of diagonalizations leads to another, which result the iteration reports, and which CI strings seed the next one. Trim SQD is chosen by passing aTrimPolicy. The argument defaults toStandardPolicy, the behavior this function has always had, so omitting it changes nothing.A policy is described by the
SubspacePolicyprotocol and receives its inputs as aSubspaceRequest. It returns the subspaces and the loop callssci_solverwith them, so a schedule and an eigensolver are chosen independently and any combination works.A policy chooses which strings a subspace holds. The constraints on the shape of a subspace remain the caller’s: the configurations requested through
include_configurationsgo into every subspace, spin symmetrization is enforced where it was asked for, and each spin sector is truncated tomax_dim.
An
sci_solvermay now report the configurations it wants carried into the next iteration, and may skip returning the eigenvector altogether. This is what lets trim SQD scale: an eigensolver that ranks and trims its own subspace already knows which configurations survive, and the eigenvector it would otherwise have to hand back is of sizelen(strings_a) * len(strings_b)– the one quantity a large distributed calculation cannot afford to move between processes.Two additions to
SCIResultprovide this. The new optional fieldcarryoverholds a pair(strings_a, strings_b)of CI strings; when a solver sets it, those strings are used in place of the ones that would otherwise be selected from the eigenvector amplitudes usingcarryover_threshold. Andsci_statemay now beNone, so that a solver which never materializes the eigenvector does not have to fabricate one. Such a solver must setcarryover, since there would otherwise be nothing to build the next subspace from; a result with neither now raisesValueError.The solvers built into this package always return an eigenvector, so nothing changes for callers using them.
Adds
partition_subsample(), which draws a pool of bitstrings and divides it among the batches so that they are disjoint. This is whatTrimPolicyuses, exposed for callers writing a policy of their own.
Adds
batch_to_ci_strings(), which converts a batch of bitstrings into a pair of per-spin CI string arrays ranked by the number of times each string was sampled. This is the step that turns subsampled bitstrings into a subspace, exposed so that a policy does not have to reimplement it.
Upgrade Notes¶
NumPy 2.0 and SciPy 1.14.1 are now the minimum required versions. Support for NumPy 1.x has been dropped, following Qiskit’s adoption of SPEC 0.
The minimum version of Qiskit is now 2.0.
Code that reads
sci_statefrom a result produced by a customsci_solvershould be prepared forNone, as the field is now optional. Results from the solvers built into this package always populate it, so callers using the default solver are unaffected.
carryover_thresholdis now a setting of the default policy, which is what chooses the carryover by thresholding amplitudes. It remains an argument ofdiagonalize_fermionic_hamiltonian()with the same meaning and the same default, but passing it together with an explicitpolicyraisesValueErrorrather than being silently ignored, since another policy chooses the carryover in its own way. Pass the threshold toStandardPolicywhen constructing one explicitly.
Bug Fixes¶
Fixed the ranking of sampled CI strings when
symmetrize_spin=Trueinqiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian(). If the same string was sampled in both spin sectors, its alpha and beta counts were previously ranked separately rather than being added together. This could cause a lower-weight string to be retained whenmax_dimtruncated the subspace.
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()can now be called collectively from all processes of a multi-process (SPMD) execution, for example under MPI. When invoked this way, thesci_solverstep runs on every process, so a custom, distributedsci_solvercan 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 this guide for details on the package’s support for multi-process and multi-threaded acceleration.
Deprecation Notes¶
The
qiskit_addon_sqd.fermion.optimize_orbitals()andqiskit_addon_sqd.fermion.rotate_integrals()functions are now deprecated. Refer to the orbital optimization guide for how to optimize the Hamiltonian basis with the ffsim package instead.
0.12.1¶
Upgrade Notes¶
Python 3.10 is now the minimum required version. Support for Python 3.9 has been dropped.
0.12.0¶
New Features¶
Added the
max_dimargument to theqiskit_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()function.
Upgrade Notes¶
qiskit_addon_sqd.fermion.SCIStatenow takes two additional required arguments,norbandnelec. This is a breaking change.
Deprecation Notes¶
Bug Fixes¶
Fixed a bug in
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.SCIStateobjects resulted in an error.
Added a release note to version 0.11 for a breaking change involving
qiskit_addon_sqd.fermion.SCIState.
0.11.0¶
New Features¶
Added a new function
qiskit_addon_sqd.fermion.diagonalize_fermionic_hamiltonian()to serve as the main entrypoint to the SQD algorithm.
qiskit_addon_sqd.fermion.solve_fermion()now accepts ashiftargument used to shift states which have the wrong spin, \((H + shift * S^2)|ψ> = E|ψ>\).
Upgrade Notes¶
qiskit_addon_sqd.fermion.solve_fermion()andqiskit_addon_sqd.fermion.optimize_orbitals()now accept trailingkwargs, which will be passed directly to pyscf.fci.selected_ci.kernel_fixed_space under the hood to calculate the target state. Themax_davidsonargument should now be passed asmax_cyclein both functions.
Bug Fixes¶
Fixed a float to integer type conversion affecting the
qubitmodule
0.10.0¶
Upgrade Notes¶
Removed
qiskit_addon_sqd.fermion.flip_orbital_occupancies(). Users no longer need to flip the orbital occupancies output fromqiskit_addon_sqd.fermion.solve_fermion()andqiskit_addon_sqd.fermion.optimize_orbitals(); they will be output in the order expected byqiskit_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_occupanciesargument toqiskit_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])New format:
tuple(array([occ_a_0, ..., occ_a_N]), array([occ_b_0, ..., occ_b_N]))
Bug Fixes¶
Fixed a bug which would cause the energy output from
qiskit_addon_sqd.fermion.solve_fermion()to be incorrect when the inputspin_sqdeviates from the spin^2 of the output wavefunction.
0.9.0¶
Upgrade Notes¶
qiskit_addon_sqd.fermion.optimize_orbitals()andqiskit_addon_sqd.fermion.rotate_integrals()now requirek_flatto 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()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¶
Added support for Python 3.9.
All functions which take a
rand_seedargument now also accept anumpy.random.Generatorinstance as therand_seed.
Upgrade Notes¶
The ground state returned by
qiskit_addon_sqd.fermion.solve_fermion()will now be an instance ofqiskit_addon_sqd.fermion.SCIState, rather than a PySCFSCIVectorinstance.
0.7.0¶
Bug Fixes¶
Fixed a bug in
qiskit_addon_sqd.fermion.solve_fermion()andqiskit_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()to crash with amallocerror.
0.6.0¶
Upgrade Notes¶
Specifying
addressesas a keyword argument toqiskit_addon_sqd.fermion.solve_fermion()andqiskit_addon_sqd.fermion.optimize_orbitals()is no longer supported. Users may still passaddressesas 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
# DEPRECATED CODE from qiskit_addon_sqd.fermion import ( bitstring_matrix_to_sorted_addresses, solve_fermion, optimize_orbitals, ) bitstring_matrix = ... addresses = bitstring_matrix_to_sorted_addresses(bitstring_matrix, open_shell=open_shell) energy, coeffs, occs, spin = solve_fermion( addresses=addresses, hcore=hcore, eri=eri, ) ... e_oo, rotation, occs_oo = optimize_orbitals( addresses=addresses, hcore=hcore, eri=eri, ) ### SHOULD BECOME ### # NEW CODE from qiskit_addon_sqd.fermion import solve_fermion, optimize_orbitals bitstring_matrix = ... energy, coeffs, occs, spin = solve_fermion( bitstring_matrix, hcore=hcore, eri=eri, ) ... e_oo, rotation, occs_oo = optimize_orbitals( bitstring_matrix, hcore=hcore, eri=eri, )
Deprecation Notes¶
The
qiskit_addon_sqd.fermion.bitstring_matrix_to_sorted_addresses()function has been deprecated in favor ofqiskit_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 astuple(spin_dn, spin_up); whereas,qiskit_addon_sqd.fermion.bitstring_matrix_to_ci_strs()returns the configurations astuple(spin_up, spin_dn).To migrate
from qiskit_addon_sqd.fermion import ( bitstring_matrix_to_sorted_addresses, bitstring_matrix_to_ci_strs, ) # DEPRECATED CODE bs_matrix = ... addr_dn, addr_up = bitstring_matrix_to_sorted_addresses(bs_matrix, open_shell=True) ### SHOULD BECOME ### # NEW CODE bs_matrix = ... ci_strs_up, ci_strs_dn = bitstring_matrix_to_ci_strs(bs_matrix, open_shell=True)
The
addressesargument toqiskit_addon_sqd.fermion.solve_fermion()andqiskit_addon_sqd.fermion.optimize_orbitals()has been deprecated in favor ofbitstring_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()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(),qiskit_addon_sqd.subsampling.postselect_and_subsample(), andqiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()now require thehamming_rightandhamming_leftarguments to be specified as keyword arguments. Additionally, thesamples_per_batchandn_batchesarguments toqiskit_addon_sqd.subsampling.postselect_and_subsample()should now be passed as keyword arguments.To upgrade
from qiskit_addon_sqd.configuration_recovery import post_select_by_hamming_weight from qiskit_addon_sqd.subsampling import postselect_and_subsample from qiskit_addon_sqd.counts import generate_counts_bipartite_hamming counts = generate_counts_bipartite_hamming(num_samples, num_bits, num_elec_a, num_elec_b) ... 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, num_batches, )
should be changed to
from qiskit_addon_sqd.configuration_recovery import post_select_by_hamming_weight from qiskit_addon_sqd.subsampling import postselect_and_subsample from qiskit_addon_sqd.counts import generate_counts_bipartite_hamming counts = generate_counts_bipartite_hamming(num_samples, num_bits, hamming_right=num_elec_a, hamming_left=num_elec_b) ... bs_mat = post_select_by_hamming_weight(bs_mat_full, hamming_right=num_elec_a, hamming_left=num_elec_b) ... batches = postselect_and_subsample( bs_mat, probs_arr, hamming_right=num_elec_a, hamming_left=num_elec_b, samples_per_batch=samples_per_batch, num_batches=num_batches, )
0.4.0¶
Prelude¶
This is a minor release which introduces a couple of small, but important, breaking changes to to the API. These changes allow for a more consistent pattern in specifying the number of alpha and beta electrons throughout both the chemistry and non-chemistry functions in the API.
Upgrade Notes¶
The
qiskit_addon_sqd.counts.generate_counts_bipartite_hamming(),qiskit_addon_sqd.subsampling.postselect_and_subsample(), andqiskit_addon_sqd.configuration_recovery.post_select_by_hamming_weight()now take thehamming_rightpositional argument before thehamming_leftargument to better match the rest of the workflow.To upgrade
from qiskit_addon_sqd.configuration_recovery import post_select_by_hamming_weight from qiskit_addon_sqd.subsampling import postselect_and_subsample from qiskit_addon_sqd.counts import generate_counts_bipartite_hamming counts = generate_counts_bipartite_hamming(num_samples, num_bits, num_elec_b, num_elec_a) ... 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
from qiskit_addon_sqd.configuration_recovery import post_select_by_hamming_weight from qiskit_addon_sqd.subsampling import postselect_and_subsample from qiskit_addon_sqd.counts import generate_counts_bipartite_hamming counts = generate_counts_bipartite_hamming(num_samples, num_bits, num_elec_a, num_elec_b) 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, )