Drop the HF initial_occupancies seed; ship a curated H2O counts file - #13
Merged
Conversation
initial_occupancies was passed unconditionally, which is not the inert
"insurance" its comment claimed. qiskit_addon_sqd._prepare_ci_strings
branches on it:
None -> postselect_by_hamming_right_and_left(): keep only the
bitstrings that already have the target Hamming weights.
provided -> recover_configurations(): take the full noisy set and
bit-flip every string toward the target.
So supplying it replaced postselection with configuration recovery in
every run, including --counts runs. At iteration 1 the only occupancies
available are Hartree-Fock (all virtuals exactly 0.0), so the subspace
was largely synthesised by bit-flips against a mean-field prior instead
of built from sampled configurations. Published SQD postselects at
iteration 1 and uses solver-derived occupancies from iteration 2 on,
which is what qiskit-addon-dice-solver's test_n2_sbd.py already does.
Changes:
- run_sqd_sbd.py: drop the HF occupancy block and the
initial_occupancies= argument.
- run_sqd_sbd.py: the --samples fallback now uses
generate_counts_bipartite_hamming() instead of
generate_bit_array_uniform(), so generated bitstrings carry the target
Hamming weights. Uniform strings are postselected away except near half
filling: the survival rate is C(norb,ne)^2 / 4^norb, i.e. 0 of 3000 for
H2O (5 of 24) versus 3000 of 3000 with this generator.
- Add python/examples/count_dict_h2o.json: 275 bitstrings in
[beta | alpha] layout, from the vendored h2o-1em3-alpha.txt list with
each alpha half-determinant reused for both spin sectors. Counts are
all 1 -- a curated determinant list, not a shot histogram.
- Notebook: load that file instead of generating random bitstrings, and
drop initial_occupancies. Previously it reached ~-76.2 only because the
HF seed pulled uniform-random strings toward HF.
Validated (GB200, --device gpu, notebook's settings: samples_per_batch
300, 1 batch, 2 iterations): -76.2359466308 Ha, matching the -76.23594663
that vendor/sbd-upstream/data/h2o/README.md reports for the 1.0e-3 /
275-bitstring / 7.56e4-determinant subspace. All 275 bitstrings survive
postselection, so no occupancy seed is required.
hfwen0502
force-pushed
the
remove-hf-occupancy-seed
branch
from
September 1, 2026 19:01
1b44081 to
49eb23e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
run_sqd_sbd.pypassedinitial_occupanciesunconditionally, described in a comment as"cheap insurance … harmless if the bit_array is already valid". It is not harmless.
qiskit_addon_sqd.fermion._prepare_ci_stringsbranches on it:So supplying it replaced postselection with configuration recovery in every run,
--countsruns included. At iteration 1 the only occupancies available areHartree–Fock (every virtual exactly 0.0), so the subspace was largely synthesised
by bit-flips against a mean-field prior rather than built from sampled
configurations.
Published SQD postselects at iteration 1 and uses solver-derived occupancies from
iteration 2 onward.
qiskit-addon-dice-solver'stest_n2_sbd.pyalready doesexactly that — it passes no
initial_occupancies.Changes
run_sqd_sbd.py: drop the HF occupancy block and theinitial_occupancies=argument.
run_sqd_sbd.py: the--samplesfallback now usesgenerate_counts_bipartite_hamming()instead ofgenerate_bit_array_uniform(),so generated bitstrings carry the target Hamming weights. Uniform strings are
postselected away except near half filling — survival is
C(norb,ne)^2 / 4^norb:test_n2_sbddata/h2o)data/n2)Measured: 0 of 3000 uniform vs 3000 of 3000 with the new generator (H2O).
Three stale "uniform random" descriptions (docstring,
--sampleshelp, runtimeprint) are corrected.
New
python/examples/count_dict_h2o.json(15 KB): 275 bitstrings in[beta | alpha]layout, built from the vendoredh2o-1em3-alpha.txtlist witheach alpha half-determinant reused for both spin sectors — the same
tensor-product subspace
run_sbd_diag.pybuilds from--adetfile. Counts areall 1: a curated determinant list, not a shot histogram.
Notebook: loads that file instead of generating random bitstrings, and drops
initial_occupancies. It previously reached ~-76.2 only because the HF seedpulled uniform-random strings toward HF; with the seed removed and random
samples it would land near -31 Ha. Also relabels the callback's
subspace dim->carryover dim, which reports the 27x27 carryover set ratherthan the 75,625 determinants actually diagonalized.
Validation
The notebook was executed locally with the same tooling CI uses
(
pytest --nbmake,cpubackend, stockqiskit-addon-sqd 0.13.1,pyscf 2.14.0, python 3.13.5):
SBD's own output reads
Energy = -76.23594663084391, matching the-76.23594663 that
vendor/sbd-upstream/data/h2o/README.mdpublishes for the1.0e-3 / 275-bitstring / 7.56e4-determinant row.
Runtime on an M1 Max: 7.8 s total (0.5 s kernel, 1.7 s imports, 5.0 s for the two
SQD iterations; Davidson is 2.34 s + 2.31 s).
All 275 bitstrings survive postselection, so no occupancy seed is needed. Also
verified end-to-end on GB200 with
--device gpu:-76.2359466308.Notes for review
in the repo, and inventing plausible-looking weights would misrepresent the file.
samples_per_batch=300 >= 275,subsample()returns the full set, soboth iterations diagonalize the same subspace and return the same energy. That
makes the notebook deterministic and exactly reproducible against the upstream
number, but it does mean the loop does not visibly improve across iterations.