sbd-eigensolver 1.6.0__tar.gz → 1.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. sbd_eigensolver-1.7.0/INSTALL.md +205 -0
  2. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/MANIFEST.in +2 -1
  3. sbd_eigensolver-1.7.0/PKG-INFO +397 -0
  4. sbd_eigensolver-1.7.0/README.md +349 -0
  5. sbd_eigensolver-1.7.0/examples/gdb/README.md +511 -0
  6. sbd_eigensolver-1.7.0/examples/gdb/run_gdb_diag.py +568 -0
  7. sbd_eigensolver-1.7.0/examples/gdb/run_gdb_heatbath.py +608 -0
  8. sbd_eigensolver-1.7.0/examples/tpb/README.md +507 -0
  9. sbd_eigensolver-1.7.0/examples/tpb/count_dict_h2o.json +277 -0
  10. {sbd_eigensolver-1.6.0/python/examples → sbd_eigensolver-1.7.0/examples/tpb}/run_sbd_diag.py +125 -15
  11. sbd_eigensolver-1.7.0/examples/tpb/run_sqd_enlarge_subspace_sbd.py +569 -0
  12. {sbd_eigensolver-1.6.0/python/examples → sbd_eigensolver-1.7.0/examples/tpb}/run_sqd_sbd.ipynb +37 -21
  13. sbd_eigensolver-1.7.0/examples/tpb/run_sqd_sbd.py +655 -0
  14. sbd_eigensolver-1.7.0/pyproject.toml +86 -0
  15. sbd_eigensolver-1.7.0/python/__init__.py +833 -0
  16. sbd_eigensolver-1.7.0/python/bindings.cpp +1235 -0
  17. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/python/device_config.py +129 -44
  18. sbd_eigensolver-1.7.0/python/sbd_solver.py +775 -0
  19. sbd_eigensolver-1.7.0/sbd_eigensolver.egg-info/PKG-INFO +397 -0
  20. sbd_eigensolver-1.7.0/sbd_eigensolver.egg-info/SOURCES.txt +130 -0
  21. sbd_eigensolver-1.7.0/sbd_eigensolver.egg-info/requires.txt +25 -0
  22. sbd_eigensolver-1.7.0/setup.py +1095 -0
  23. sbd_eigensolver-1.7.0/test/test_gdb_drivers.py +372 -0
  24. sbd_eigensolver-1.7.0/test/test_gdb_equivalence.py +668 -0
  25. sbd_eigensolver-1.7.0/test/test_reference_energies.py +139 -0
  26. sbd_eigensolver-1.7.0/test/test_sqd_integration.py +524 -0
  27. sbd_eigensolver-1.7.0/vendor/sbd-upstream/LICENSE.txt +206 -0
  28. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/arithmetic.h +587 -0
  29. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/basis.h +759 -0
  30. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/carryover.h +81 -0
  31. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/davidson.h +452 -0
  32. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/expansion.h +237 -0
  33. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/generalop.h +871 -0
  34. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/generalop_flatdata.h +139 -0
  35. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/helper.h +59 -0
  36. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/inc_all.h +20 -0
  37. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/lanczos.h +322 -0
  38. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/loadmodel.h +359 -0
  39. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/mkham.h +195 -0
  40. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/mult.h +233 -0
  41. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/mult_thrust.h +744 -0
  42. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/restart.h +151 -0
  43. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/basic/sbdiag.h +634 -0
  44. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/caop/inc_all.h +6 -0
  45. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/correlation.h +355 -0
  46. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/correlation_thrust.h +145 -0
  47. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/davidson_thrust.h +681 -0
  48. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/determinants.h +653 -0
  49. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/determinants_thrust.h +276 -0
  50. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/excitation.h +87 -0
  51. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/helpers.h +244 -0
  52. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/inc_all.h +23 -0
  53. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/integrals.h +115 -0
  54. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/integrals_thrust.h +127 -0
  55. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/lanczos_thrust.h +168 -0
  56. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/makedeterminants.h +195 -0
  57. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/makeintegrals.h +179 -0
  58. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/mult.h +108 -0
  59. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/omp_offload.h +358 -0
  60. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/basic/qcham.h +447 -0
  61. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/carryover.h +120 -0
  62. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/correlation.h +308 -0
  63. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/correlation_thrust.h +448 -0
  64. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/davidson.h +623 -0
  65. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/davidson_thrust.h +367 -0
  66. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/exact_external_observable.h +93 -0
  67. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/expansion.h +834 -0
  68. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/grid_distribution.h +436 -0
  69. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/hash_owned_external_observable.h +113 -0
  70. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/heatbath_lookup.h +142 -0
  71. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/helper.h +818 -0
  72. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/helper_thrust.h +768 -0
  73. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/inc_all.h +31 -0
  74. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/mult.h +272 -0
  75. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/mult_thrust.h +1097 -0
  76. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/occupation.h +52 -0
  77. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/parent_sampling.h +115 -0
  78. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/qcham.h +406 -0
  79. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/restart.h +10 -0
  80. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/sbdiag.h +786 -0
  81. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/stat_evaluator.h +230 -0
  82. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/statistical_contribution_expansion.h +205 -0
  83. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/gdb/u_statistic_external_observable.h +154 -0
  84. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/inc_all.h +8 -0
  85. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/correlation.h +647 -0
  86. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/correlation_thrust.h +734 -0
  87. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/davidson.h +976 -0
  88. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/davidson_thrust.h +319 -0
  89. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/extend.h +324 -0
  90. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/helper.h +1252 -0
  91. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/helper_thrust.h +620 -0
  92. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/inc_all.h +25 -0
  93. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/lanczos.h +327 -0
  94. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/lanczos_thrust.h +177 -0
  95. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/mult.h +887 -0
  96. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/mult_thrust.h +1667 -0
  97. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/occupation.h +99 -0
  98. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/qcham.h +347 -0
  99. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/rdmat.h +267 -0
  100. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/restart.h +785 -0
  101. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/chemistry/tpb/sbdiag.h +948 -0
  102. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/bit_manipulation.h +1854 -0
  103. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/cublas_utility.h +235 -0
  104. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/cuda_reduce.h +179 -0
  105. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/cuda_utility.h +63 -0
  106. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/det_vector.h +818 -0
  107. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/determinant_distribution_round_robin.h +179 -0
  108. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/determinant_initialization.h +67 -0
  109. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/distributed_alias_sampling.h +225 -0
  110. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/dm_vector.h +296 -0
  111. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/fcidump.h +262 -0
  112. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/hip_reduce.h +173 -0
  113. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/hp_numeric.h +575 -0
  114. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/jacobi.h +104 -0
  115. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/mpi_utility.h +708 -0
  116. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/mpi_utility_thrust.h +484 -0
  117. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/murmurhash_basis_distribution.h +418 -0
  118. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/nccl_utility.h +146 -0
  119. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/nvtx.h +179 -0
  120. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/sort_array.h +356 -0
  121. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/ssutils.h +27 -0
  122. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/stat/stat_evaluator_batch.h +260 -0
  123. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/thrust_kernels.h +761 -0
  124. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/timestamp.h +31 -0
  125. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/framework/type_def.h +85 -0
  126. sbd_eigensolver-1.7.0/vendor/sbd-upstream/include/sbd/sbd.h +7 -0
  127. sbd_eigensolver-1.6.0/PKG-INFO +0 -473
  128. sbd_eigensolver-1.6.0/README.md +0 -444
  129. sbd_eigensolver-1.6.0/pyproject.toml +0 -44
  130. sbd_eigensolver-1.6.0/python/__init__.py +0 -495
  131. sbd_eigensolver-1.6.0/python/bindings.cpp +0 -607
  132. sbd_eigensolver-1.6.0/python/examples/README.md +0 -211
  133. sbd_eigensolver-1.6.0/python/examples/run_sqd_sbd.py +0 -330
  134. sbd_eigensolver-1.6.0/python/sbd_solver.py +0 -484
  135. sbd_eigensolver-1.6.0/sbd_eigensolver.egg-info/PKG-INFO +0 -473
  136. sbd_eigensolver-1.6.0/sbd_eigensolver.egg-info/SOURCES.txt +0 -20
  137. sbd_eigensolver-1.6.0/sbd_eigensolver.egg-info/requires.txt +0 -3
  138. sbd_eigensolver-1.6.0/setup.py +0 -458
  139. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/LICENSE.txt +0 -0
  140. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/python/sbd_nvhpc_compat.h +0 -0
  141. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/sbd_eigensolver.egg-info/dependency_links.txt +0 -0
  142. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/sbd_eigensolver.egg-info/not-zip-safe +0 -0
  143. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/sbd_eigensolver.egg-info/top_level.txt +0 -0
  144. {sbd_eigensolver-1.6.0 → sbd_eigensolver-1.7.0}/setup.cfg +0 -0
@@ -0,0 +1,205 @@
1
+ # Installing sbd-eigensolver
2
+
3
+ Every install compiles the extension modules on the target machine — no wheels are
4
+ published — so which backends you end up with depends on the toolchain the build
5
+ finds. The quickstart in the [README](README.md#installation) covers the common CPU
6
+ case; this page is the full matrix: prerequisites, the environment variables the build
7
+ reads, building against a host MPI, and how to verify what you got.
8
+
9
+ ## Prerequisites
10
+
11
+ **Required:** Python 3.10+, MPI (OpenMPI/MPICH), BLAS (OpenBLAS/MKL), pybind11, mpi4py, numpy, compiler with OpenMP.
12
+
13
+ **On macOS:** Apple clang ships without OpenMP, so add `llvm-openmp` to the conda
14
+ environment. Homebrew's `libomp` is used as a fallback if the env has none. Pin the
15
+ compiler with `CC`/`CXX` as well — a bare `clang++` is resolved through `PATH`, so a
16
+ Homebrew LLVM silently wins over both Apple clang and a conda toolchain. The build
17
+ prints which compiler and which libomp it chose.
18
+
19
+ **For the GPU backends** — optional; without them you get a CPU-only install:
20
+
21
+ ***On NVIDIA*** (both the Thrust and the OpenMP-offload backend):
22
+
23
+ - *to build:* [NVIDIA HPC SDK](https://developer.nvidia.com/hpc-sdk) (`nvc++`).
24
+ `SBD_GPU_ARCH` is **optional**: unset, nvc++ targets the GPU of the machine
25
+ the toolchain was installed on; set, it is honored exactly and may name
26
+ several generations at once (`cc80,cc90,cc100`) — see
27
+ [Environment Variables](#environment-variables).
28
+
29
+ ***On AMD*** (the OpenMP-offload backend only):
30
+
31
+ - *to build:* ROCm LLVM toolchain (`amdclang++`).
32
+ `SBD_GPU_ARCH` is optional here on a GPU system and is **detected** with
33
+ ROCm's `amdgpu-arch` (e.g. `gfx90a` on MI250X, `gfx942` on MI300X). However, on a GPU-less build host, you must
34
+ set it. see [Environment Variables](#environment-variables).
35
+
36
+ Either install path compiles the C++ extension on the target machine;
37
+ no pre-built wheels are published. The resulting binary depends on the
38
+ local MPI and BLAS, so both must be installed first.
39
+
40
+ ## Install from PyPI
41
+
42
+ **A self-contained conda environment** is the quickest way to get those
43
+ dependencies in place for the CPU backend:
44
+ ```bash
45
+ conda create -y -n sbd -c conda-forge \
46
+ python=3.13.12 pybind11 numpy setuptools wheel openblas pyscf pip mpi4py
47
+ # ...plus llvm-openmp on macOS
48
+ ```
49
+
50
+ ```bash
51
+ conda activate sbd
52
+ ```
53
+
54
+ Now install the sbd-eigensolver-python package
55
+ ```
56
+ pip install sbd-eigensolver
57
+ ```
58
+
59
+ The published source distribution (sdist) bundles the sbd header files, so this
60
+ needs no git checkout and no submodule step.
61
+
62
+ ## Install from git checkout
63
+
64
+ Here the headers come from upstream
65
+ [r-ccs-cms/sbd](https://github.com/r-ccs-cms/sbd) via a git submodule at
66
+ `vendor/sbd-upstream/`, **pinned at a specific upstream commit**. Run `git submodule status` to see the pinned SHA.
67
+
68
+ When installing from a git checkout, it is important to make sure the
69
+ sbd submodule is cloned, too:
70
+
71
+ ```bash
72
+ git clone --recurse-submodules https://github.com/Qiskit/sbd-eigensolver-python.git
73
+ # or, if you cloned without --recurse-submodules:
74
+ git submodule update --init --recursive
75
+ ```
76
+
77
+ If you need a newer upstream revision (for a recently-landed GPU fix
78
+ etc.), advance the local submodule and rebuild:
79
+
80
+ ```bash
81
+ git submodule update --remote vendor/sbd-upstream
82
+ ```
83
+
84
+ After the upstream sbd code is cloned, run:
85
+ ```
86
+ pip install -e . --no-build-isolation --force-reinstall --no-deps
87
+ ```
88
+
89
+ ## Environment Variables
90
+
91
+ ```bash
92
+ # --- NVIDIA GPU backends (Thrust and OpenMP target-offload): point at NVHPC.
93
+ # Only needed if nvc++ is not already on PATH. Adjust the path.
94
+ # Either the compilers directory or the version root above it works, and
95
+ # NVHPC_ROOT -- which NVIDIA's own modulefile sets to the version root -- is
96
+ # read too, so `module load nvhpc` alone is enough.
97
+ export NVHPC_HOME=/opt/nvidia/hpc_sdk/Linux_x86_64/2025/compilers
98
+
99
+ # --- AMD GPU backend (OpenMP target-offload): point at ROCm LLVM toolchain
100
+ # amdclang++ is found on $ROCM_HOME/bin
101
+ export ROCM_HOME=/opt/rocm
102
+
103
+ # --- OPTIONAL. Only for a host with BOTH GPU toolchains installed, where the
104
+ # auto-answer would be an accident of probe order: nvidia | amd | none
105
+ export SBD_GPU_VENDOR=amd
106
+
107
+ # --- OPTIONAL GPU architecture, spelled per vendor.
108
+ # NVIDIA: unset, nvc++ targets the GPU of the machine this toolchain was
109
+ # installed on. Set it to pin the target, including SEVERAL at once:
110
+ # A100: cc80 H100: cc90 GB200 / B200: cc100
111
+ # ccall-major one target per major generation
112
+ # AMD: unset, the arch is DETECTED with ROCm's `amdgpu-arch`. Set it to pin,
113
+ # or when building on a host with no GPU (where detection cannot work and
114
+ # the build stops asking for it):
115
+ # MI250X: gfx90a MI300X: gfx942 (several: gfx90a,gfx942)
116
+ export SBD_GPU_ARCH=cc80,cc90,cc100 # NVIDIA
117
+ export SBD_GPU_ARCH=gfx90a # AMD
118
+
119
+ # --- optional overrides; each has a working default ---
120
+ # Which backends to build: defaults to CPU always, plus every GPU backend the
121
+ # detected toolchain supports -- Thrust AND OpenMP-offload under nvc++,
122
+ # OpenMP-offload only under amdclang++ (there is no rocThrust path).
123
+ # Set it only to narrow that:
124
+ # cpu CPU only -- skip GPU even if a GPU compiler is present
125
+ # gpu Thrust GPU only, no CPU -- NVIDIA only, errors on AMD
126
+ # gpu_omp_offload OpenMP target-offload GPU only (either vendor)
127
+ export SBD_BUILD_BACKEND=cpu
128
+
129
+ # MPI: defaults to whatever mpi4py is linked against. Set this only
130
+ # for layouts that cannot be inferred.
131
+ # NOTE: Every GPU backend hands MPI device pointers, so use a GPU-aware MPI:
132
+ # CUDA-aware on NVIDIA, ROCm-aware on AMD.
133
+ export MPI_HOME=/path/to/mpi
134
+
135
+ # BLAS: defaults to whatever the linker finds, including a
136
+ # conda-installed OpenBLAS in $CONDA_PREFIX/lib. Set these to select
137
+ # a specific build (e.g. an arch-tuned OpenBLAS)
138
+ export BLAS_LIB_PATH=/path/to/blas/lib
139
+ export BLAS_LIBS=openblas # or mkl_rt
140
+
141
+ # these are read while COMPILING, so set them first, then install
142
+ pip install sbd-eigensolver # from PyPI
143
+ pip install -e . --no-build-isolation --no-deps # from a git checkout
144
+ ```
145
+
146
+ ## Build Using the Host MPI
147
+ ```bash
148
+ # Create a conda env
149
+ conda create -y -n sbd -c conda-forge \
150
+ python=3.13.12 pybind11 numpy setuptools wheel openblas pyscf pip
151
+ # ...plus llvm-openmp on macOS
152
+
153
+ conda activate sbd # always activate first
154
+
155
+ # Install mpi4py against the host MPI
156
+ # For any GPU backend the host MPI must be GPU-aware:
157
+ # CUDA-aware on NVIDIA, ROCm-aware on AMD.
158
+ export MPI_HOME=/path/to/mpi
159
+ MPICC=$MPI_HOME/bin/mpicc python -m pip install --no-binary=mpi4py --no-cache-dir mpi4py
160
+ # NOTE: If no host MPI is available, let conda pick a compatible one with the
161
+ # command below. A default conda-forge MPI is not GPU-aware, which is fine for the
162
+ # CPU backend; for the GPU backends either install mpi4py against a GPU-aware MPI
163
+ # as above, or see the README's Backend Architecture section for the two build-time options that
164
+ # let the Thrust backend run without one.
165
+ # conda install -y -c conda-forge mpi4py
166
+
167
+ # confirm which MPI mpi4py uses -- setup.py builds against exactly this
168
+ python -c "from mpi4py import MPI; print(MPI.Get_library_version())"
169
+
170
+ # only for the SQD examples (examples/tpb/run_sqd_sbd.py and .ipynb)
171
+ pip install "qiskit-addon-sqd>=0.13.1"
172
+
173
+ # install sbd-eigensolver
174
+ pip install sbd-eigensolver
175
+
176
+ ```
177
+
178
+ ## Verify
179
+
180
+ ```bash
181
+ python -c "import sbd; print(sbd.available_backends())"
182
+ # CPU only: ['cpu']
183
+ # NVIDIA, default build: ['cpu', 'gpu', 'gpu-omp']
184
+ # AMD, default build: ['cpu', 'gpu-omp']
185
+ # OMP-offload-only install: ['gpu-omp']
186
+ ```
187
+
188
+ On a GPU build, confirm which vendor and architecture the offload backend
189
+ targets — one `'gpu-omp'` device serves both vendors, so the name alone does not
190
+ say:
191
+
192
+ ```bash
193
+ python -c "import sbd; print(sbd.get_backend('gpu-omp').__sbd_offload_target__)"
194
+ # amdgcn-amd-amdhsa:gfx90a AMD MI250X
195
+ # nvptx64-nvidia-cuda:cc90 NVIDIA H100
196
+ ```
197
+
198
+ The Thrust backend is stamped too (`cuda:cc90`); the CPU backend reports `None`.
199
+
200
+ ## See Also
201
+
202
+ - [README](README.md) — what the package is, the API, and the SQD integration
203
+ - [`examples/tpb/README.md`](examples/tpb/README.md) — backend selection at runtime,
204
+ bundled test data and performance notes
205
+ - [Troubleshooting](README.md#troubleshooting) — build and runtime symptoms
@@ -16,4 +16,5 @@ recursive-include vendor/sbd-upstream/include *.h
16
16
  include vendor/sbd-upstream/LICENSE.txt
17
17
 
18
18
  # Example scripts and notebook, referenced by the README.
19
- recursive-include python/examples *.py *.ipynb *.md
19
+ recursive-include examples *.py *.ipynb *.md *.json
20
+ include INSTALL.md
@@ -0,0 +1,397 @@
1
+ Metadata-Version: 2.4
2
+ Name: sbd-eigensolver
3
+ Version: 1.7.0
4
+ Summary: Python bindings for Selected Basis Diagonalization (SBD) library
5
+ License-Expression: Apache-2.0
6
+ Project-URL: Homepage, https://github.com/Qiskit/sbd-eigensolver-python
7
+ Project-URL: Documentation, https://github.com/Qiskit/sbd-eigensolver-python
8
+ Project-URL: Repository, https://github.com/Qiskit/sbd-eigensolver-python
9
+ Project-URL: Issues, https://github.com/Qiskit/sbd-eigensolver-python/issues
10
+ Keywords: quantum chemistry,diagonalization,tensor product basis,MPI
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Operating System :: MacOS :: MacOS X
15
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
16
+ Classifier: Topic :: Scientific/Engineering :: Physics
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Programming Language :: C++
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE.txt
27
+ Requires-Dist: mpi4py>=4.0.0
28
+ Requires-Dist: numpy>=1.26.0
29
+ Provides-Extra: basetest
30
+ Requires-Dist: pytest>=8.0; extra == "basetest"
31
+ Provides-Extra: test
32
+ Requires-Dist: sbd-eigensolver[basetest]; extra == "test"
33
+ Requires-Dist: pytest-mpi>=0.6; extra == "test"
34
+ Requires-Dist: qiskit-addon-sqd>=0.13.1; extra == "test"
35
+ Requires-Dist: pyscf>=2.9; extra == "test"
36
+ Provides-Extra: nbtest
37
+ Requires-Dist: sbd-eigensolver[basetest]; extra == "nbtest"
38
+ Requires-Dist: nbmake>=1.5.0; extra == "nbtest"
39
+ Provides-Extra: docs
40
+ Requires-Dist: sbd-eigensolver[test]; extra == "docs"
41
+ Requires-Dist: qiskit-sphinx-theme~=2.1.0; extra == "docs"
42
+ Requires-Dist: sphinx-copybutton; extra == "docs"
43
+ Requires-Dist: reno>=4.1; extra == "docs"
44
+ Provides-Extra: notebook-dependencies
45
+ Requires-Dist: qiskit-addon-sqd>=0.13.1; extra == "notebook-dependencies"
46
+ Requires-Dist: pyscf>=2.9; extra == "notebook-dependencies"
47
+ Dynamic: license-file
48
+
49
+ # SBD Python Bindings
50
+
51
+ Python bindings for the Selected Basis Diagonalization (SBD) library, with CPU and GPU backends.
52
+
53
+ ## Overview
54
+
55
+ SBD (Selected Basis Diagonalization) is a high-performance library for quantum
56
+ chemistry calculations. These bindings expose two of its diagonalization methods on CPU
57
+ and GPU. They differ in the shape of the subspace they span, which is what decides
58
+ which one you want:
59
+
60
+ - **Tensor-Product Basis (TPB)** — the subspace is the Cartesian product of an alpha
61
+ and a beta determinant list, so its dimension is `|adet| × |bdet|`. The mature path,
62
+ and the one the qiskit-addon-sqd integration uses.
63
+ - **General-Determinant Basis (GDB)** — the subspace is the explicit determinant list
64
+ you pass, so it can be an arbitrary *sparse* set rather than a product. Experimental:
65
+ newer, a smaller tested surface, and still evolving as upstream SBD does.
66
+
67
+ If your subspace is a product, prefer TPB — it represents that case with two
68
+ half-determinant lists instead of every product element, and needs no extra
69
+ constraints. Reach for GDB when the subspace is not a product.
70
+
71
+ **Key Features:**
72
+ - **TPB and GDB diagonalization** for quantum chemistry Hamiltonians
73
+ - Three backends, selected per call at runtime via `device=`:
74
+ `'cpu'` (host OpenMP), `'gpu'` (NVHPC Thrust/CUDA, NVIDIA only) and
75
+ `'gpu-omp'` (OpenMP target offload, **NVIDIA or AMD**). All the backends your
76
+ toolchain supports can be built into one install; each is imported only when
77
+ first used. **TPB runs on all three; GDB has Thrust kernels only**, so GDB on a
78
+ GPU is NVIDIA-only and under `'gpu-omp'` it falls back to the host — see
79
+ [`examples/gdb/README.md`](examples/gdb/README.md)
80
+ - MPI parallelization
81
+ - Integration with [qiskit-addon-sqd](https://github.com/Qiskit/qiskit-addon-sqd) for SQD workflows
82
+
83
+ SBD's **Creation/Annihilation operator (CAOP)** method is not supported by this
84
+ wrapper; users who need it should reference and use the C++ CLI apps in the upstream
85
+ submodule (`vendor/sbd-upstream/apps/`).
86
+
87
+ > [!NOTE]
88
+ > This package is newly open-sourced. The Python API follows semantic versioning, but the build configuration and GPU backends have been exercised on a limited set of platforms — please report issues.
89
+
90
+ ## Installation
91
+
92
+ The extension modules are compiled on your machine — no wheels are published — so the
93
+ backends you get depend on the toolchain the build finds. For the common CPU case:
94
+
95
+ ```bash
96
+ conda create -y -n sbd -c conda-forge \
97
+ python=3.13.12 pybind11 numpy setuptools wheel openblas pyscf pip mpi4py
98
+ # ...plus llvm-openmp on macOS
99
+ conda activate sbd
100
+
101
+ pip install sbd-eigensolver
102
+ ```
103
+
104
+ Then check what was built:
105
+
106
+ ```bash
107
+ python -c "import sbd; print(sbd.available_backends())"
108
+ # CPU only: ['cpu']
109
+ # NVIDIA, default build: ['cpu', 'gpu', 'gpu-omp']
110
+ # AMD, default build: ['cpu', 'gpu-omp']
111
+ ```
112
+
113
+ **See [INSTALL.md](INSTALL.md)** for the rest: prerequisites per platform, installing
114
+ from a git checkout with the submodule, every environment variable the build reads
115
+ (GPU toolchains, architectures, MPI and BLAS selection, narrowing which backends get
116
+ built), building against an existing host MPI, and fuller verification.
117
+
118
+ ## Examples
119
+
120
+ Located in `examples/`, organized by basis type since the solvers take different
121
+ subspaces and decompose over MPI differently. Each folder's README is the authoritative
122
+ guide to what it contains, how to run it, and the backend and threading settings that
123
+ matter for it.
124
+
125
+ - [`examples/tpb/`](examples/tpb/README.md) — tensor-product basis: standalone TPB
126
+ diagonalization, the SQD loops, and the subspace-enlargement driver.
127
+ - [`examples/gdb/`](examples/gdb/README.md) — general determinant basis: standalone
128
+ GDB diagonalization over an explicit determinant list, and an iterative
129
+ heatbath-expansion driver.
130
+
131
+ ## Integration with qiskit-addon-sqd
132
+
133
+ SBD can serve as the eigensolver backend for qiskit-addon-sqd's SQD workflow.
134
+
135
+ > [!NOTE]
136
+ > This integration is **TPB-only**, and not merely for want of plumbing.
137
+ > `solve_sci`/`solve_sci_batch` call `tpb_diag`, and the addon's interface describes a
138
+ > product subspace by construction: `ci_strings` is a `(strings_a, strings_b)` pair and
139
+ > `SCIState.amplitudes` is an `|a| × |b|` matrix. A sparse determinant list cannot be
140
+ > expressed that way without padding back up to the full product, which discards the
141
+ > reason to use GDB. For GDB, call `gdb_diag` directly or use the drivers in
142
+ > [`examples/gdb/`](examples/gdb/README.md).
143
+
144
+ **Note:** Requires [qiskit-addon-sqd](https://github.com/Qiskit/qiskit-addon-sqd) with distributed (SPMD) support — `diagonalize_fermionic_hamiltonian` calling `sci_solver` on every MPI rank. This is available in `qiskit-addon-sqd` version `0.13.1` or higher. SBD-selected carryover and subspace policies need `0.14.0` or higher.
145
+
146
+ ### Plain SQD
147
+
148
+ ```python
149
+ from functools import partial
150
+ from sbd.sbd_solver import solve_sci_batch
151
+ from sbd.device_config import DeviceConfig
152
+ from qiskit_addon_sqd.fermion import diagonalize_fermionic_hamiltonian
153
+
154
+ # No sbd.init() and no explicit mpi_comm needed — solve_sci_batch
155
+ # auto-initializes the SBD backend on first call and falls back to
156
+ # MPI.COMM_WORLD when mpi_comm is not provided.
157
+ sbd_solver = partial(
158
+ solve_sci_batch,
159
+ sbd_config={"method": 0, "eps": 1e-5, "max_it": 10, "max_nb": 10},
160
+ device_config=DeviceConfig.gpu(), # or .cpu(), .gpu_omp()
161
+ fcidump_path="data/h2o/fcidump.txt", # optional: reuse one FCIDUMP across batches
162
+ )
163
+
164
+ result = diagonalize_fermionic_hamiltonian(
165
+ hcore, eri, bit_array,
166
+ sci_solver=sbd_solver, # SBD plugs in here
167
+ norb=norb, nelec=nelec,
168
+ samples_per_batch=3000, num_batches=3, max_iterations=5,
169
+ symmetrize_spin=True,
170
+ )
171
+ ```
172
+
173
+ See [SQD Parameters](examples/tpb/README.md#sqd-parameters) for how each
174
+ parameter feeds the loop, and
175
+ [examples/tpb/run_sqd_sbd.py](examples/tpb/run_sqd_sbd.py) for a
176
+ complete example.
177
+
178
+ qiskit-addon-sqd is the orchestrator in that recipe: it owns the loop
179
+ (sampling, configuration recovery, subsampling), and SBD is plugged in as the
180
+ per-batch eigensolver (`sci_solver=sbd_solver` above). By default SBD has no say
181
+ in how the subspace grows between iterations: SQD chooses the carryover from the
182
+ amplitudes SBD returns.
183
+
184
+ With `qiskit-addon-sqd >= 0.14.0`, SBD can choose the carryover itself instead:
185
+ set `"carryover_type"` in `sbd_config` and SQD takes SBD's selection as given. With
186
+ type 1, the amplitudes never leave SBD, which saves a full wavefunction write and
187
+ read every iteration. See
188
+ [SBD-selected carryover](examples/tpb/README.md#sbd-selected-carryover) for what
189
+ each type does and costs, and the section after it for running the loop with a
190
+ different subspace policy such as Trim SQD.
191
+
192
+ ### SQD with subspace enlargement
193
+
194
+ [`run_sqd_enlarge_subspace_sbd.py`](examples/tpb/run_sqd_enlarge_subspace_sbd.py)
195
+ builds on the same recipe, but grows its own subspace between rounds: after
196
+ each solve, it expands the dominant determinant pairs via qiskit-addon-sqd's
197
+ own `enlarge_batch_from_transitions` (same-spin single excitations, both
198
+ alpha and beta) and feeds the result forward as the next round's
199
+ `include_configurations`. Concretely, it calls
200
+ `diagonalize_fermionic_hamiltonian` with `max_iterations=1` itself, in its
201
+ own outer Python loop, rather than delegating the whole multi-iteration loop
202
+ to one call — that is what makes injecting a step between rounds possible.
203
+
204
+ On the bundled H2O pool ([`count_dict_h2o.json`](examples/tpb/count_dict_h2o.json),
205
+ 275 bitstrings), plain SQD reaches ≈ -76.236 Ha and stops there; this driver
206
+ keeps going past that fixed pool on its own and converges to
207
+ **-76.2421767512 Ha**.
208
+
209
+ ## Backend Architecture
210
+
211
+ - **The Thrust build assumes a GPU-aware MPI** and hands MPI device pointers directly. Two upstream escape hatches exist for an MPI that cannot address device memory. Both are **off by default**, and both are **compile-time** — set them before installing `sbd-eigensolver`, rebuild to change them, and they do nothing if set at run time:
212
+ ```
213
+ SBD_NON_CUDA_AWARE_MPI=1 stage every device buffer through host memory
214
+ SBD_THRUST_SAFE_MPI_ALLREDUCE=1 stage only the allreduce (a subset of the above)
215
+ ```
216
+ Both make the Thrust path stage device buffers through host memory instead of handing MPI device pointers, so they add copies whose cost grows with how much data crosses MPI. Treat them as a compatibility fallback rather than a tuning knob: reach for them when a GPU backend crashes inside the MPI itself rather than in SBD.
217
+ - GPU device assignment: `gpu_id = mpi_rank % num_gpus` (set per `tpb_diag()` call in `bindings.cpp`); same logic for both Thrust and OMP-offload paths.
218
+ - **`'gpu-omp'` is vendor-neutral by design:** one module, one device string, for both NVIDIA and AMD. It is the same source with the same macros and only the compiler differs, and since no wheels are published — every install compiles on the target machine — an install serves one GPU vendor. `__sbd_offload_target__` records which one. Aliases (`gpu-amd-omp`, `gpu-rocm-omp`, `rocm`, `gpu-nvidia-omp`, …) resolve to it so a vendor-flavoured guess lands correctly.
219
+ - Verify what GPU architecture is supported in the binary:
220
+ ```
221
+ NVIDIA: cuobjdump --list-elf <the built _core_gpu_thrust*.so>
222
+ AMD: llvm-objdump --offloading <the built _core_gpu_omp_offload*.so>
223
+ ```
224
+ Or just ask the module what it was built for:
225
+ ```
226
+ python -c "import sbd; \
227
+ print(sbd.get_backend('gpu-omp').__sbd_offload_target__)"
228
+ -> amdgcn-amd-amdhsa:gfx90a
229
+ ```
230
+
231
+ ## API Reference
232
+
233
+ ### Initialization
234
+
235
+ | Function | Description |
236
+ |----------|-------------|
237
+ | `sbd.init(device, comm_backend)` | **Optional.** Initialize MPI, set default device (`'cpu'`, `'gpu'`, `'gpu-omp'`, `'auto'`). Auto-called on first use with defaults. |
238
+ | `sbd.finalize()` | Sync GPU, reset state. Does not call `MPI_Finalize` |
239
+ | `sbd.is_initialized()` | Check init status |
240
+
241
+ ### Backend Access
242
+
243
+ | Function | Description |
244
+ |----------|-------------|
245
+ | `sbd.get_backend(device=None)` | Get the pybind11 backend module for the named device. `None` = default device. |
246
+ | `sbd.available_backends()` | List of compiled backends, e.g. `['cpu']`, `['cpu', 'gpu']`, `['gpu-omp']` |
247
+
248
+ ### Query
249
+
250
+ | Function | Description |
251
+ |----------|-------------|
252
+ | `sbd.get_device()` | Default device name |
253
+ | `sbd.get_rank()` | MPI rank |
254
+ | `sbd.get_world_size()` | MPI world size |
255
+ | `sbd.get_comm()` | MPI communicator |
256
+ | `sbd.barrier()` | MPI barrier |
257
+
258
+ ### Configuration
259
+
260
+ ```python
261
+ config = sbd.TPB_SBD()
262
+ ```
263
+
264
+ | Attribute | Default | Description |
265
+ |-----------|---------|-------------|
266
+ | `method` | 0 | 0=Davidson, 1=Davidson+Ham, 2=Lanczos, 3=Lanczos+Ham |
267
+ | `max_it` | 1 | Max iterations |
268
+ | `eps` | 1e-4 | Convergence tolerance |
269
+ | `max_nb` | 10 | Max basis vectors |
270
+ | `do_rdm` | 0 | 0=density only, 1=full RDM |
271
+ | `bit_length` | 20 | Bit length for determinants |
272
+ | `adet_comm_size` | 1 | Alpha determinant communicator size |
273
+ | `bdet_comm_size` | 1 | Beta determinant communicator size |
274
+ | `task_comm_size` | 1 | Task communicator size |
275
+
276
+ Total MPI ranks = `task_comm_size × adet_comm_size × bdet_comm_size`.
277
+
278
+ ```python
279
+ config = sbd.GDB_SBD()
280
+ ```
281
+
282
+ Shares `max_it`, `max_nb`, `eps`, `max_time`, `init`, `do_rdm`, `carryover_type`,
283
+ `ratio`, `threshold` and `bit_length` with `TPB_SBD`, and replaces the determinant
284
+ communicators with a single basis communicator:
285
+
286
+ | Attribute | Default | Description |
287
+ |-----------|---------|-------------|
288
+ | `method` | 0 | 0=Davidson, 1=Davidson+Ham. GDB has no Lanczos, so TPB's 2 and 3 are rejected |
289
+ | `b_comm_size` | 1 | Basis communicator size — how many shards the determinant list is split into |
290
+ | `t_comm_size` | 1 | Task communicator size — must not exceed `b_comm_size` |
291
+ | `seed` | 1729 | Seed for the initial vector |
292
+ | `heatbath_cutoff` | 1e-4 | Heatbath expansion cutoff |
293
+ | `heatbath_truncation` | 0.0 | Weight truncation applied before heatbath expansion |
294
+ | `heatbath_batch_size` | 200000000 | Heatbath expansion batch size |
295
+
296
+ Total MPI ranks = `t_comm_size × b_comm_size × helper`, where the helper dimension is
297
+ the derived quotient and is not settable. With `b_comm_size > 1` each rank passes its
298
+ own shard of the determinant list rather than the whole list.
299
+
300
+ See [`examples/gdb/README.md`](examples/gdb/README.md) for the decomposition, the shard
301
+ contract, the six determinant-placement schemes, and why the helper dimension must be 1
302
+ on the Thrust backend.
303
+
304
+ ### Diagonalization
305
+
306
+ ```python
307
+ # From files
308
+ results = sbd.tpb_diag_from_files(fcidumpfile, adetfile, sbd_data,
309
+ loadname="", savename="", device=None)
310
+
311
+ # From data structures
312
+ results = sbd.tpb_diag(fcidump, adet, bdet, sbd_data,
313
+ loadname="", savename="", device=None)
314
+ ```
315
+
316
+ **Returns:** `dict` with keys `energy`, `density`, `carryover_adet`, `carryover_bdet`, `one_p_rdm`, `two_p_rdm`.
317
+
318
+ ```python
319
+ # GDB: over an explicit list of full determinants rather than a product space
320
+ results = sbd.gdb_diag(fcidump, det, sbd_data,
321
+ loadname="", savename="", device=None,
322
+ determinant_distribution="", determinant_grid_a=0,
323
+ determinant_grid_b=0)
324
+ ```
325
+
326
+ **Returns:** `dict` with keys `energy`, `density`, `carryover_det`, `one_p_rdm`,
327
+ `two_p_rdm`, `local_dim`, `global_dim` and `determinant_distribution`; the last three
328
+ are this rank's determinant count, the whole basis's, and the placement scheme that
329
+ ran. Each determinant is a `2 * norb`-bit configuration in which bit
330
+ `2 * i` is the occupation of spin-alpha orbital `i` and bit `2 * i + 1` that of
331
+ spin-beta orbital `i`. The determinants must be distinct; they are sorted into
332
+ SBD's canonical order internally, which `sort_bitarray` reproduces.
333
+
334
+ `det` may be a single `(ndets, words)` array or **this rank's shard of one**:
335
+ `sbd_data.b_comm_size` decides which. At `1` every rank passes the whole basis; above
336
+ `1` every rank passes its own shard, the union over b_comm positions being the basis.
337
+ Sharded input must be globally sorted and disjoint; that and the rank-layout constraints
338
+ are checked, and raise rather than silently diagonalizing the wrong subspace.
339
+ `determinant_distribution` chooses how determinants are placed across ranks (default
340
+ `equal-bra-a`), and the two grid arguments size the grid for the grid-cyclic schemes.
341
+ [`examples/gdb/README.md`](examples/gdb/README.md) has the shard contract, the
342
+ placement schemes, and which returned values are replicated versus sharded.
343
+
344
+ `gdb_diag` returns no wavefunction amplitudes — `gdb::diag` has no in-memory output for
345
+ them — and for most uses none are needed: the energy, density and RDMs come back
346
+ directly, and an iterative heatbath run gets its next subspace from `carryover_det`. If
347
+ you do want the amplitudes, `savename` writes them to disk; the file layout is in
348
+ [`examples/gdb/README.md`](examples/gdb/README.md).
349
+
350
+ The optional `device` parameter overrides the default set by `init()`.
351
+
352
+ ## Troubleshooting
353
+
354
+ **GPU backends silently build as host code:** a conda compiler package
355
+ (`cxx-compiler`, `gxx_linux-64`, `clangxx_osx-*`) sets `CC`/`CXX` on activation and
356
+ the build respects a caller-set compiler, so `nvc++`/`amdclang++` never run. Unset
357
+ `CC`/`CXX`, or keep conda compilers out of the build env.
358
+
359
+ **GPU not building:** On NVIDIA check `which nvc++` and set `NVHPC_HOME` (or rely on
360
+ `NVHPC_ROOT` from `module load nvhpc`; either the compilers directory or the version
361
+ root works). On AMD
362
+ check `which amdclang++` and set `ROCM_HOME`. The build prints which toolchain it
363
+ picked (`Found amdclang++ in PATH: …` / `Found NVIDIA HPC SDK at: …`) and, for
364
+ the offload backend, the resolved architecture; on a host with both toolchains
365
+ force the choice with `SBD_GPU_VENDOR=amd|nvidia`.
366
+
367
+ **`MPI_HOME=... is not the MPI that mpi4py is linked against`:** the build stops here
368
+ deliberately rather than producing extensions that link one MPI while `mpi4py` loads
369
+ another — a mismatch that surfaces later as undefined symbols or a hang inside the first
370
+ collective. `MPI_HOME` is only for layouts the build cannot infer; unset it to use
371
+ `mpi4py`'s own MPI, or reinstall `mpi4py` against the MPI you want
372
+ (`pip install --no-binary :all: mpi4py`). To see which MPI that is:
373
+ `python -c "from mpi4py import MPI; print(MPI.Get_library_version())"`.
374
+
375
+ **`OMP: Error #15: Initializing libomp.dylib, but found libomp.dylib already
376
+ initialized` on macOS:** two copies of the same LLVM OpenMP runtime in one process. It
377
+ aborts at the first parallel region, so the import succeeds and the first
378
+ diagonalization dies. Usually it means the environment provides `libomp` twice — for
379
+ example Homebrew `llvm` *and* Homebrew `libomp`, or a Homebrew copy alongside the conda
380
+ env's. Build against one only; the conda env's is the one loaded at import time, so
381
+ prefer it. Tracked as
382
+ [issue #27](https://github.com/Qiskit/sbd-eigensolver-python/issues/27).
383
+
384
+ **OMP-offload runs all land on GPU 0 in multi-GPU jobs:** symptom — every MPI rank shows large memory only on GPU 0 in `nvidia-smi` (or `rocm-smi`). The bindings call `omp_set_default_device(mpi_rank % n_dev)`, but `omp_get_num_devices()` can return 0 in some dlopen scenarios. The bindings fall back to counting the entries in the vendor's device-visibility variable — `CUDA_VISIBLE_DEVICES` on NVIDIA, `ROCR_VISIBLE_DEVICES` or `HIP_VISIBLE_DEVICES` on AMD — so make sure the relevant one is exported and lists all your GPUs (e.g. `0,1,2,3`). Slurm/`srun --gres=gpu:N` and OpenMPI's default binding policy already do this; if you've custom-restricted it to a single GPU per rank, set it manually before launch. Note the index is the **global** MPI rank, not a node-local one, so the assignment is even only when the launcher places ranks on nodes in contiguous blocks — round-robin placement leaves each node using a strided subset of its GPUs.
385
+
386
+ **Ranks die with `Bus error` or `SIGSEGV` inside the MPI's own copy path** (`MPIR_Localcopy`, `ucp_worker_progress`, ...) **on a GPU backend:** the MPI is not GPU-aware and was handed a device pointer. Rebuild UCX `--with-cuda` / `--with-rocm`, and confirm with `ucx_info -d | grep -i 'Transport: cuda'` (or `rocm`). Two things mislead here. A partly GPU-aware stack fails in only one place: an MPICH with GPU support *disabled* over a CUDA-aware UCX ran OMP-offload fine and crashed only in Thrust, because the inter-rank path went through UCX while the local-copy path did not. And on AMD a non-ROCm-aware MPI does not crash at all — ROCm maps device memory into the process address space, so the host copy succeeds and merely stages everything through the host aperture (measured on MI250X, XNACK off, 8 ranks) — so a working AMD run is not evidence that the MPI is ROCm-aware.
387
+
388
+ **GDB on more than one GPU refuses to start, naming the helper dimension:** GDB's Thrust
389
+ kernels never implemented that dimension, and it is the quotient
390
+ `ranks / (t_comm_size × b_comm_size)` — so any rank you do not assign to `t` or `b` lands
391
+ there. Give every rank to the basis: `-np 4` with `b_comm_size = 4` leaves a helper
392
+ dimension of 1. Leaving `b_comm_size` at 1 puts *all* ranks in the helper dimension,
393
+ which is why multi-GPU GDB requires a split basis. `gdb_diag` checks this before doing
394
+ any work rather than letting the kernel throw mid-launch. The CPU backend has no such
395
+ restriction, and TPB is unaffected.
396
+
397
+ **Repository:** https://github.com/Qiskit/sbd-eigensolver-python