Skip to content

Unrestricted (UHF) FCIDUMPs through TPB and GDB; README restructured - #91

Merged
Sophia Wen (hfwen0502) merged 40 commits into
mainfrom
uhf-on-pin
Nov 6, 2026
Merged

Sophia Wen (hfwen0502) merged 40 commits into
mainfrom
uhf-on-pin

Conversation

@hfwen0502

Copy link
Copy Markdown
Member

Adds unrestricted (UHF) Hamiltonians to the TPB and GDB solvers, and restructures the top-level README, which had grown past 400 lines.

Unrestricted (UHF) FCIDUMPs

  • Same calls, layout read from the file. An FCIDUMP in SBD's unrestricted layout — NORB spatial orbitals, integrals indexed by interleaved spin orbitals — goes through sbd.LoadFCIDump, tpb_diag, gdb_diag and tpb_diag_from_files exactly like a restricted one, and through the TPB and GDB drivers. Each call reads the layout from the integrals and runs the matching build.
  • Built by default. The cpu and gpu (Thrust) backends are each also built with upstream's -D_UHF, as sbd._core_cpu_uhf and sbd._core_gpu_thrust_uhf. SBD_BUILD_UHF=0 skips them; an unrestricted file is then refused with an error naming that variable. gpu-omp has no unrestricted build, since its offload kernels read only the restricted layout, and refuses such a file.
  • New API: sbd.fcidump_format() says whether a file is 'restricted' or 'uhf'; sbd.has_uhf(device) whether a device has an unrestricted build; LoadFCIDump(..., uhf=True|False) states the layout and raises if the file is the other one. available_backends() is unchanged and lists the restricted backends only.
  • Checks. A file in neither layout is refused rather than diagonalized: an index above 2 * NORB, unrestricted indices whose pairs mix spins (usually a wrong NORB), or a UHF/IUHF header flag from another program's layout. run_sbd_diag.py checks the determinant files' electron counts against NELEC and MS2: in its default symmetric mode it reused the alpha list as the beta one, so an open-shell system diagonalized a different charge state without an error.
  • Variance and PT2. sbd.analysis.variance() accepts a UHF state: its stochastic method runs upstream's evaluator from the unrestricted build, as upstream's gdb-stat-evaluator-uhf does. The exact method is restricted-only and says so.
  • examples/tools/make_uhf_fcidump.py writes unrestricted FCIDUMPs from PySCF, and its write_uhf_fcidump any spin-resolved integrals in SBD's layout. No generated data is shipped beyond the unit tests' fixtures; users make their own with the script.
  • Also: LoadFCIDump and tpb_diag_from_files accept pathlib.Path names.

A fix found while testing this branch. loaded_backends() lists the unrestricted builds, which are not device names, and the variance evaluator's search passed every loaded name to get_backend. Variance of a restricted state, run after a UHF solve on gpu in the same process, raised 'gpu-uhf' is not a device name. The search now skips them.

README restructured

The README is now a front page: what the package does, its backends, installation, the SQD integration and the examples, with the rest linked.

  • API reference: removed; it repeated docs/apidocs by hand and had drifted. The backend and MPI helpers the API page lacked (loaded_backends, print_info, barrier, …) are added there.
  • Backend architecture: the GPU-aware MPI fallbacks and the architecture check move to INSTALL.md (new GPU-aware MPI section, and Verify, which now also shows how to check the UHF builds).
  • Troubleshooting: moves to TROUBLESHOOTING.md, grouped by severity, with entries for the one-thread Thrust refusal and for what gpu-omp does not support.
  • Wording: where docs say what a backend supports, gpu-omp "does not support" GDB, CAOP and UHF files, and asking for one raises an error.
  • Links into the removed sections are updated, and pyproject.toml's Documentation URL now points at the docs site.

Tests

  • test_uhf.py: TPB and GDB on upstream's H3 UHF fixture and its ROHF twin, against PySCF's FCI energy; how files are classified; the refusals, on every rank under MPI; sharded GDB on both layouts under MPI.
  • test_uhf_analysis.py: the variance and PT2 of a UHF subspace of stretched H4, whose alpha and beta orbitals differ, against exact values from PySCF's direct_uhf, in one process and with the state saved over every rank under MPI; upstream's evaluator fixture classified as restricted; and the fix above: a UHF solve, then restricted variance, in one process.
  • test_analysis.py: the evaluator-selection test covers loaded unrestricted builds.

The docs build without warnings.

🤖 Generated with Claude Code

Sophia Wen (hfwen0502) and others added 30 commits October 29, 2026 15:46
sbd.analysis.variance gives the energy variance and Epstein-Nesbet PT2
correction of a state saved with savename, by upstream SBD's stochastic
evaluator (bound as external_observables, CPU and OpenMP-offload backends)
or exactly with PySCF for small systems. state_energy, load_state and
load_gdb_shards read TPB and GDB states on any number of ranks.
examples/analysis adds variance.py, extrapolate.py and a README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PySCF's cistring.strs2addr packs a string into an int64 and raises
NotImplementedError for norb >= 64, though the FCI routines the exact method
uses (contract_2e, make_hdiag) work there. Address each string by its
position in PySCF's own make_strings list instead, which is in address
order and returns occupied-orbital lists from 64 orbitals on. method="auto"
can reach the exact method at that size, as a full space of a few electrons
in 64+ orbitals fits under exact_limit.

Tested with H2 embedded at orbitals 30 and 64 of 65 against H2 alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r floor

variance() and variance.py take observable ("both", "variance" or "pt2"),
first_batch (the first batch's ID, so a later call adds independent batches
instead of repeating them) and minimum_abs_denominator (refuse a PT2 with a
near-zero denominator), all passed straight to upstream's evaluator, which
already accepted them. Each batch's ID is recorded in the result. The README
names upstream's gdb-stat-evaluator as the method and describes the options.

Tests: the same batch ID repeats a batch and later IDs give new draws; the
unrequested observable is NaN; an impossible denominator floor is refused;
and, under MPI, a GDB state saved by every rank is analysed on half of them,
as upstream's own test reads 2 saved shards on 4 ranks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the Thrust backend, _create_sbd_config applied DeviceConfig after
sbd_config, and DeviceConfig always wrote use_precalculated_dets and
max_memory_gb_for_determinants from its own defaults. A value set in
sbd_config was reset, so run_sqd_sbd.py and run_sqd_enlarge_subspace_sbd.py
ignored --sbd_use_precalculated_dets and --sbd_max_memory_gb_for_determinants.

DeviceConfig is now applied first and writes only the arguments it was given;
those two arguments are deprecated in favour of sbd_config, which takes
precedence over them.

Also bind upstream's Thrust-only TPB field thrust_collapse_loops, present at
the vendored pin but not exposed, with --thrust_collapse_loops in
run_sbd_diag.py and --sbd_thrust_collapse_loops in the two SQD drivers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream SBD has no OpenMP-offload GDB code, so gdb_diag on the gpu-omp
module ran entirely on the host while a GPU had been asked for; only
run_gdb_diag.py warned. gdb_diag now raises ValueError on that module, and
run_gdb_diag.py and run_gdb_heatbath.py exit with an error for
--device gpu-omp, or auto resolving to it, pointing at cpu, or gpu (Thrust,
NVIDIA GPUs only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… cpu_subspace

- vendor/sbd-upstream moves from 93ebabe to r-ccs-cms/sbd 95bf45a (25 commits):
  the opposite-spin 2-RDM sign fix (#98), Davidson/Lanczos subspace refactor and
  TPB performance work (#95, #99), the CAOP stat evaluator (#94) and the CAOP
  spectrum app (#96, #100).
- Upstream's Thrust builds now MPI_Abort the job when omp_get_max_threads() is 1,
  which ends Python with nothing to catch. tpb_diag, tpb_diag_from_files and
  gdb_diag on Thrust raise ValueError on every rank first instead.
- TPB_SBD.cpu_subspace and GDB_SBD.cpu_subspace (Thrust only, as upstream declares
  them): keep the Davidson (and TPB's Lanczos) subspace vectors in host memory
  instead of GPU memory, as upstream's apps' --cpu_subspace.
- Tests: test_rdm_open_shell.py, the opposite-spin 2-RDM block on upstream's H3
  doublet against PySCF, which fails at the old pin on every backend and passes
  now; test_openmp_threads.py, the one-thread refusal on Thrust;
  test_cpu_subspace.py, the same energy with cpu_subspace on and off for TPB and
  GDB, and the field present on the Thrust backend only.
Also expose it in the drivers as --cpu_subspace / --sbd_cpu_subspace; it is
ignored on the backends that do not have it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he FCIDUMP

Upstream SBD selects spin-dependent integrals at compile time (-D_UHF): the
FCIDUMP is read with interleaved spin-orbital indices, NORB staying the number
of spatial orbitals. A UHF build is therefore a separate module.

- setup.py builds _core_cpu_uhf and _core_gpu_thrust_uhf next to the existing
  backends: the same Extension under a new name, plus -D_UHF.
  SBD_BUILD_UHF=0 skips them. OpenMP offload gets no twin, because its device
  kernels read the restricted integral layout regardless of _UHF.
- The package registers them as 'cpu-uhf' and 'gpu-uhf' ('auto' never picks
  them). sbd.fcidump_format() tells the two layouts apart (any index above
  NORB), LoadFCIDump tags the FCIDump it returns, and tpb_diag,
  tpb_diag_from_files and gdb_diag dispatch to the matching build.
  get_backend(..., uhf=True) refuses gpu-omp.
- FCIDump and the config structs are the same C++ types in both builds, so
  configs and FCIDUMP objects pass between them. That is also why the format
  check has to live in Python: nothing at the binding level stops a UHF
  FCIDump reaching the restricted solver.

Checked against PySCF UHF-FCI: H3 doublet (9 dets) on cpu and gpu; NH2/6-31G
(920,205 dets) on cpu and gpu at 1 rank and 2x2; GDB on H3 under -D_UHF. The
existing suite still passes. SQD-loop integration (solve_sci) is not included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the stored format record with a classification computed from the
integrals each time, so it cannot go stale when a caller edits them after
loading. The check runs in C++ over the integrals in place (no copy into
Python): ~1 ms per call at 500k entries, below 0.1% of any real
diagonalization, and LoadFCIDump is back to main's cost (the Python text scan
it replaces was 0.19 s at c4h4).

- tpb_diag, gdb_diag and tpb_diag_from_files bindings each refuse integrals of
  the other layout, voting across ranks, so calling a backend module directly
  can no longer diagonalize the wrong layout silently.
- Files in neither layout are refused: an index above 2*NORB, a spin-mixed
  (ij)/(kl) pair above NORB (typically a wrong NORB), or a UHF/IUHF header flag.
- available_backends()/backend_load_errors() list devices only; the twin names
  are refused as devices; new sbd.has_uhf(device); LoadFCIDump(uhf=...) states
  the layout and raises on a mismatch.
- LoadFCIDump returns the same object as on main; no dynamic attributes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mp too

- run_sbd_diag.py checks the determinant files' electron counts against
  NELEC/MS2 before diagonalizing. Symmetric mode reuses the alpha list as beta,
  so on any open-shell system (MS2 != 0, restricted or unrestricted) it used to
  return the energy of a different charge state without an error. Rank 0
  reads, every rank raises.
- run_gdb_heatbath.py loads through sbd.LoadFCIDump, so a file in neither
  layout, or an unrestricted one on gpu-omp, fails at load; it reports the
  layout it found.
- sbd.fcidump_format() accepts a loaded FCIDump as well as a path, and
  LoadFCIDump/tpb_diag_from_files accept path-like file names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- examples/uhf/make_uhf_fcidump.py writes, from one PySCF run, a UHF FCIDUMP in
  SBD's unrestricted layout, the ROHF twin in the restricted one, the full
  alpha/beta string lists and reference.json with the exact energy. Its
  write_uhf_fcidump() is reusable for other integrals.
- examples/uhf/nh2: NH2/6-31G, 13 orbitals, 920,205 determinants, E_FCI
  -55.633361496218 (~280 KB). Both drivers run it; README shows how.
- test/data/uhf: the H3 doublet (6 KB), E_FCI -1.588486422874.
- test/test_uhf.py: layout classification and refusals, full-space TPB and GDB
  energies from both layouts, the HF determinant giving each SCF energy, edited
  integrals classified afresh, every binding refusing the other layout when
  called directly, the TPB driver's electron-count check, two MPI tests and a
  slow NH2 full-space test. Passes on cpu (laptop, h100) and gpu (h100), single
  process and 2 ranks.
- tox passes SBD_BUILD_UHF through; the sdist ships the example data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
H3's full space split over b_comm_size = the rank count, so the helper
dimension stays at 1 and the test runs on Thrust too.

Verified more widely by hand on h100 with NH2 (920,205 determinants): b = 2
and 4, t = 2, a helper dimension of 2 on CPU, and the input, equal-bra-a and
grid-cyclic distributions all give the exact energy on cpu and gpu, ranks
agreeing; and the heatbath driver from one 400-determinant seed gives an
identical dimension and energy series at b = 1, 2 and 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
variance() took the PT2 reference energy as optional and, for the stochastic
method, recomputed it from the saved state with a zero-iteration gdb_diag. That
recompute is redundant -- the diagonalization that saved the state returned the
energy -- and it ties variance() to a GDB solve, which the OpenMP-offload backend
cannot run. Upstream's evaluator takes the energy as a required input
(--reference-energy), as caop_variance does here.

The energy is now a required argument of variance() and --energy a required flag
of examples/analysis/variance.py. state_energy() stays, for checking that a
state and an FCIDUMP belong together; variance() no longer calls it.

The test helper that saves GDB states skips when gdb_diag refuses the backend,
so the tests keep running wherever GDB does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…metry test

variance() on a state solved with an unrestricted FCIDUMP now takes the
evaluator from the -D_UHF build, whose integrals are spin-resolved, as
upstream's gdb-stat-evaluator-uhf does; the CPU unrestricted build has it
(it is built without SBD_THRUST). The exact method builds restricted integrals
for PySCF, so it refuses an unrestricted FCIDUMP with a clear message.

Builds on the rebased uhf-support commits (unrestricted TPB/GDB, built by
default, SBD_BUILD_UHF=0 to skip) and on #80 (sbd.analysis).

Tests:
- A broken-symmetry UHF state, as BS-UHF-SQD starts from: stretched H4 with
  alpha and beta on alternate atoms (<S^2> checked). Its full space through the
  unrestricted solver gives PySCF's FCI energy; over a subspace, the stochastic
  variance and PT2, averaged over seeds, match the exact values from PySCF's
  fci.direct_uhf applying the same integrals.
- Upstream's own UHF evaluator fixture (make_cli_fixture.cc) never reaches a
  beta index, so it is also a valid restricted file and is classified as one;
  stating uhf=True is refused. The test pins that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream's Thrust GDB solve waits forever in its ring exchange when a b_comm shard
is empty. Placement can empty a shard the caller filled: equal-bra-a, the default,
deals out whole alpha strings, so fewer distinct alpha strings than b_comm_size
leaves ranks with nothing. Check every rank after placement and raise on all of
them together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test_sharded_gdb_is_exact passes determinant_distribution='input', as its
  docstring says: equal-bra-a deals out whole alpha strings, and the test space
  has three, so from four ranks on it emptied a shard and the Thrust solve, now
  refused, hung. It skips on every rank together when there are more ranks than
  determinants.
- Top README: UHF in the feature list. The UHF README points to the solve and
  check folders, not to a workflow page this branch does not have.
- No OpenMPI-only mpirun -x in the READMEs and driver docstrings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
run_sbd_diag.py --rdm_output saves rdm1/rdm2 summed over spin, as upstream SBD
writes them. For a UHF FCIDUMP the alpha and beta blocks are in different orbitals,
so the eigenvalues of their sum are not occupations: the driver now prints a note
pointing to the per-spin one_p_rdm/two_p_rdm of sbd.tpb_diag instead. The UHF
README's limits say the same, and the UHF driver test runs with --rdm_output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d name

The test covers a UHF state whose alpha and beta orbitals differ; to SBD that is
any UHF FCIDUMP. Drop the broken-symmetry / BS-UHF-SQD wording from it and from the
variance release note: it named another workflow's starting point rather than
anything the wrapper does differently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ves to examples/tools

Upstream organizes apps by solver and tool, and -D_UHF is a build of the TPB and GDB
apps, not an app of its own. So examples/uhf goes:

- examples/tpb/README.md and examples/gdb/README.md open with the same note: the
  FCIDUMP may be restricted or UHF, and the API picks the matching build. The TPB
  README gains one section with the layout, how to make a file, and the limits;
  the GDB README links to it and runs the heat-bath driver on a UHF file.
- make_uhf_fcidump.py moves to examples/tools/. The committed NH2 data goes: the
  script writes it (PySCF is the user's to install), and the README commands
  start by running it. test_nh2_example_full_space_is_exact, which only guarded
  that data, goes with it; the H3 tests cover the same correctness.
- MANIFEST.in, the top README, INSTALL.md, the API docs and the release note
  point to the new places.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

# Conflicts:
#	docs/apidocs/sbd.rst
#	examples/gdb/run_gdb_diag.py
#	examples/tpb/README.md
#	examples/tpb/run_sbd_diag.py
#	examples/tpb/run_sqd_enlarge_subspace_sbd.py
#	examples/tpb/run_sqd_sbd.py
#	python/bindings.cpp
# Conflicts:
#	README.md
#	examples/analysis/README.md
#	examples/analysis/variance.py
#	python/analysis.py
The stretched-H4 UHF subspace is solved with GDB over every rank and evaluated from
those shards; the result must match PySCF's exact values. Rank 0 builds the
integrals, so every rank uses the same orbitals. Its setup moves into helpers the
single-process test shares. Skipped where the device under test has no UHF build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	README.md
#	docs/apidocs/sbd.rst
…uator

loaded_backends() lists the unrestricted builds ('cpu-uhf', 'gpu-uhf'), which are
separate modules but not device names. The evaluator search passed every loaded name
to get_backend, so variance() or caop_variance() of a restricted state, run after a
UHF solve on 'gpu' in the same process, raised "'gpu-uhf' is not a device name". On
'cpu' it passed only because 'cpu' is listed first and has the evaluator.

The search now skips them; a restricted state is evaluated by a restricted module in
any case. Tests: the stand-in selection test gains loaded-UHF cases, and a subprocess
test runs a UHF solve then restricted variance in one process, against the same
variance without the UHF solve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…OTING and the API docs

The README had grown to over 400 lines, most of it reference: an API section that
repeated docs/apidocs by hand, backend internals, and troubleshooting. It now says
what the package does, its backends, how to install it, the SQD integration and where
the examples are, and links the rest.

- API Reference: removed. docs/apidocs/sbd.rst already documents every config field
  and the diagonalization functions; the backend and MPI helpers it lacked
  (is_initialized, get_device, loaded_backends, has_backend_conflict, print_info,
  get_comm, get_comm_backend, barrier) are added there. tpb_diag's docstring gains the
  text-dump precision note, print_info's says it lists the UHF builds.
- Backend Architecture: the GPU-aware MPI fallbacks and the binary architecture check
  move to INSTALL.md (a new "GPU-aware MPI" section, and "Verify"); the vendor-neutral
  gpu-omp note goes in the README's backend table; GPU assignment goes to
  TROUBLESHOOTING.md.
- Troubleshooting: moved unchanged to TROUBLESHOOTING.md.
- SQD integration: the snippet and its requirements stay, with the TPB-only reason;
  carryover, Trim SQD and the enlargement driver are linked to examples/tpb/.

Links into the removed sections (INSTALL.md, docs/index.rst, examples/tpb/README.md)
are updated, and pyproject.toml's Documentation URL now points at the docs site.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t raises

"Refused" described the error but not what the reader can do. Where a sentence says
what a backend supports, it now says "not supported", why, and that asking for it
raises an error rather than running on the host. Sentences about the error
behaviour itself keep "refused". The README's table cell also no longer says
upstream has no offload code for UHF: its offload kernels exist but read only the
restricted integral layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
available_backends() does not list the unrestricted builds, so Verify now shows
has_uhf() for each backend, with the default and SBD_BUILD_UHF=0 results, and that
print_info() reports the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fusals

Entries are now grouped from a failed build, through a crashed job and a solve that
refuses to start, to one that runs but not as intended. Two entries are added for
refusals users meet first: one OpenMP thread on the Thrust backend, and GDB, CAOP or a
UHF FCIDUMP on gpu-omp. The separate GPU-assignment note is merged into the "every
rank on GPU 0" entry it duplicated, and the bus-error entry points to INSTALL.md's
GPU-aware MPI section.

INSTALL.md's See Also no longer lists the TPB README: backend selection is now in the
top-level README, and test data and performance notes are not install topics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hfwen0502 Sophia Wen (hfwen0502) added the enhancement New feature or request label Nov 6, 2026
…s, not h2o

TPB fixes its determinant word count for the life of a process. The test solved the
H3 UHF fixture (one word per half) and then h2o (24 orbitals: two words at
bit_length 20), so the second solve failed with "det_vector: elem_size mismatch" on
a CPU-only build, before reaching the evaluator the test is about. Its docstring had
wrongly said both are one word. The restricted state is now the same molecule's
ROHF fixture, also one word. It still fails on 'gpu' without the evaluator fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hfwen0502
Sophia Wen (hfwen0502) merged commit 6351c0d into main Nov 6, 2026
20 of 23 checks passed
@hfwen0502
Sophia Wen (hfwen0502) deleted the uhf-on-pin branch November 6, 2026 21:55
Sophia Wen (hfwen0502) added a commit that referenced this pull request Nov 10, 2026
It was added in #91 and removed in #93, both after 1.7.2, so the next release
should neither introduce it nor say it is gone. setup.py no longer warns about
it, and the two unreleased notes no longer mention it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sophia Wen (hfwen0502) added a commit that referenced this pull request Nov 10, 2026
* examples: UHF on gpu, how the UHF build is chosen, a runnable --initial_det, workflow links

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* README: why the SQD integration is TPB only, citing Qiskit/qiskit-sqd#389

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* README: why use the bindings rather than upstream's apps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* READMEs: trim, launch on several ranks or GPUs, and say what the bindings pick for you

Every README from the top level down. Commands now run on several ranks or one
rank per GPU wherever the step parallelizes; single-process ones are left where
the step is serial. Long explanations of upstream internals are cut to what a
user acts on, and repeated warnings appear once.

The top-level README says the bindings choose the code path themselves -- the
UHF build from the FCIDUMP, the CPU evaluator after an offload solve -- and that
a feature a device does not support raises an error naming the device to use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* examples README: only the pinned upstream is tested; drop SBD_BUILD_UHF from INSTALL

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Drop SBD_BUILD_UHF everywhere: no release ever had it

It was added in #91 and removed in #93, both after 1.7.2, so the next release
should neither introduce it nor say it is gone. setup.py no longer warns about
it, and the two unreleased notes no longer mention it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: front page matches the README; sbd page covers CAOP and device=

The docs front page gains "What it does" and the reason for the bindings, the
README's feature-by-backend table in place of the device-only one, why the SQD
loop is TPB only (Qiskit/qiskit-sqd#389), and the pinned-upstream caveat for the
examples. Its separate TPB-or-GDB section folds into "What it does". The sbd API
page's intro now names CAOP and says what device= does and that an unsupported
device raises an error naming the ones that do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* analysis README: variance works for restricted and UHF FCIDUMPs alike

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* analysis README: organized by use case, covering both evaluators and extrapolate.py

It opened with the TPB/GDB evaluator only and reached CAOP and extrapolate.py late
or in passing. It now starts with the two tools and a table of which upstream
evaluator each kind of state uses and with which methods, then one section per
task: check a molecular state, check a CAOP state, estimate the exact energy from
a series, compare two ways of growing a subspace, and run it in the same job. How
the estimate works and its settings follow. The other READMEs' links follow the
renamed sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* examples README: a too-small CAOP basis leaves PT2 well short, not most of the way

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* analysis README: drop the TPB-vs-GDB growth comparison

It compared two solvers' expansion schemes rather than showing the analysis, and
its own notes said none of its states had converged. Its one lesson for the
analysis, comparing subspaces at matched dimension by variance and E + PT2, is
now a sentence under the series section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant