sbd-eigensolver 1.7.0__tar.gz → 1.7.1__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 (133) hide show
  1. {sbd_eigensolver-1.7.0/sbd_eigensolver.egg-info → sbd_eigensolver-1.7.1}/PKG-INFO +35 -1
  2. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/README.md +34 -0
  3. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/pyproject.toml +1 -1
  4. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/python/__init__.py +150 -20
  5. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/python/bindings.cpp +6 -1
  6. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/python/device_config.py +13 -23
  7. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/python/sbd_solver.py +46 -14
  8. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1/sbd_eigensolver.egg-info}/PKG-INFO +35 -1
  9. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/sbd_eigensolver.egg-info/SOURCES.txt +1 -0
  10. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/setup.py +23 -8
  11. sbd_eigensolver-1.7.1/test/test_sci_state.py +126 -0
  12. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/INSTALL.md +0 -0
  13. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/LICENSE.txt +0 -0
  14. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/MANIFEST.in +0 -0
  15. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/gdb/README.md +0 -0
  16. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/gdb/run_gdb_diag.py +0 -0
  17. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/gdb/run_gdb_heatbath.py +0 -0
  18. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/tpb/README.md +0 -0
  19. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/tpb/count_dict_h2o.json +0 -0
  20. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/tpb/run_sbd_diag.py +0 -0
  21. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/tpb/run_sqd_enlarge_subspace_sbd.py +0 -0
  22. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/tpb/run_sqd_sbd.ipynb +0 -0
  23. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/examples/tpb/run_sqd_sbd.py +0 -0
  24. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/python/sbd_nvhpc_compat.h +0 -0
  25. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/sbd_eigensolver.egg-info/dependency_links.txt +0 -0
  26. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/sbd_eigensolver.egg-info/not-zip-safe +0 -0
  27. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/sbd_eigensolver.egg-info/requires.txt +0 -0
  28. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/sbd_eigensolver.egg-info/top_level.txt +0 -0
  29. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/setup.cfg +0 -0
  30. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/test/test_gdb_drivers.py +0 -0
  31. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/test/test_gdb_equivalence.py +0 -0
  32. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/test/test_reference_energies.py +0 -0
  33. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/test/test_sqd_integration.py +0 -0
  34. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/LICENSE.txt +0 -0
  35. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/arithmetic.h +0 -0
  36. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/basis.h +0 -0
  37. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/carryover.h +0 -0
  38. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/davidson.h +0 -0
  39. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/expansion.h +0 -0
  40. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/generalop.h +0 -0
  41. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/generalop_flatdata.h +0 -0
  42. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/helper.h +0 -0
  43. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/inc_all.h +0 -0
  44. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/lanczos.h +0 -0
  45. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/loadmodel.h +0 -0
  46. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/mkham.h +0 -0
  47. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/mult.h +0 -0
  48. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/mult_thrust.h +0 -0
  49. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/restart.h +0 -0
  50. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/basic/sbdiag.h +0 -0
  51. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/caop/inc_all.h +0 -0
  52. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/correlation.h +0 -0
  53. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/correlation_thrust.h +0 -0
  54. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/davidson_thrust.h +0 -0
  55. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/determinants.h +0 -0
  56. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/determinants_thrust.h +0 -0
  57. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/excitation.h +0 -0
  58. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/helpers.h +0 -0
  59. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/inc_all.h +0 -0
  60. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/integrals.h +0 -0
  61. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/integrals_thrust.h +0 -0
  62. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/lanczos_thrust.h +0 -0
  63. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/makedeterminants.h +0 -0
  64. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/makeintegrals.h +0 -0
  65. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/mult.h +0 -0
  66. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/omp_offload.h +0 -0
  67. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/basic/qcham.h +0 -0
  68. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/carryover.h +0 -0
  69. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/correlation.h +0 -0
  70. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/correlation_thrust.h +0 -0
  71. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/davidson.h +0 -0
  72. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/davidson_thrust.h +0 -0
  73. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/exact_external_observable.h +0 -0
  74. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/expansion.h +0 -0
  75. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/grid_distribution.h +0 -0
  76. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/hash_owned_external_observable.h +0 -0
  77. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/heatbath_lookup.h +0 -0
  78. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/helper.h +0 -0
  79. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/helper_thrust.h +0 -0
  80. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/inc_all.h +0 -0
  81. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/mult.h +0 -0
  82. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/mult_thrust.h +0 -0
  83. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/occupation.h +0 -0
  84. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/parent_sampling.h +0 -0
  85. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/qcham.h +0 -0
  86. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/restart.h +0 -0
  87. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/sbdiag.h +0 -0
  88. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/stat_evaluator.h +0 -0
  89. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/statistical_contribution_expansion.h +0 -0
  90. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/gdb/u_statistic_external_observable.h +0 -0
  91. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/inc_all.h +0 -0
  92. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/correlation.h +0 -0
  93. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/correlation_thrust.h +0 -0
  94. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/davidson.h +0 -0
  95. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/davidson_thrust.h +0 -0
  96. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/extend.h +0 -0
  97. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/helper.h +0 -0
  98. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/helper_thrust.h +0 -0
  99. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/inc_all.h +0 -0
  100. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/lanczos.h +0 -0
  101. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/lanczos_thrust.h +0 -0
  102. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/mult.h +0 -0
  103. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/mult_thrust.h +0 -0
  104. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/occupation.h +0 -0
  105. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/qcham.h +0 -0
  106. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/rdmat.h +0 -0
  107. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/restart.h +0 -0
  108. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/chemistry/tpb/sbdiag.h +0 -0
  109. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/bit_manipulation.h +0 -0
  110. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/cublas_utility.h +0 -0
  111. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/cuda_reduce.h +0 -0
  112. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/cuda_utility.h +0 -0
  113. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/det_vector.h +0 -0
  114. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/determinant_distribution_round_robin.h +0 -0
  115. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/determinant_initialization.h +0 -0
  116. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/distributed_alias_sampling.h +0 -0
  117. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/dm_vector.h +0 -0
  118. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/fcidump.h +0 -0
  119. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/hip_reduce.h +0 -0
  120. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/hp_numeric.h +0 -0
  121. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/jacobi.h +0 -0
  122. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/mpi_utility.h +0 -0
  123. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/mpi_utility_thrust.h +0 -0
  124. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/murmurhash_basis_distribution.h +0 -0
  125. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/nccl_utility.h +0 -0
  126. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/nvtx.h +0 -0
  127. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/sort_array.h +0 -0
  128. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/ssutils.h +0 -0
  129. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/stat/stat_evaluator_batch.h +0 -0
  130. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/thrust_kernels.h +0 -0
  131. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/timestamp.h +0 -0
  132. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/framework/type_def.h +0 -0
  133. {sbd_eigensolver-1.7.0 → sbd_eigensolver-1.7.1}/vendor/sbd-upstream/include/sbd/sbd.h +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sbd-eigensolver
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary: Python bindings for Selected Basis Diagonalization (SBD) library
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/Qiskit/sbd-eigensolver-python
@@ -272,6 +272,7 @@ config = sbd.TPB_SBD()
272
272
  | `adet_comm_size` | 1 | Alpha determinant communicator size |
273
273
  | `bdet_comm_size` | 1 | Beta determinant communicator size |
274
274
  | `task_comm_size` | 1 | Task communicator size |
275
+ | `dump_matrix_form_wf` | `""` | Path to write the amplitudes to — see [Getting the TPB amplitudes](#getting-the-tpb-amplitudes) for the file format |
275
276
 
276
277
  Total MPI ranks = `task_comm_size × adet_comm_size × bdet_comm_size`.
277
278
 
@@ -315,6 +316,39 @@ results = sbd.tpb_diag(fcidump, adet, bdet, sbd_data,
315
316
 
316
317
  **Returns:** `dict` with keys `energy`, `density`, `carryover_adet`, `carryover_bdet`, `one_p_rdm`, `two_p_rdm`.
317
318
 
319
+ #### Getting the TPB amplitudes
320
+
321
+ Neither return dict holds the wavefunction amplitudes. Two separate mechanisms write them, in **different formats**, and the one named in the function signature is not the one most callers want:
322
+
323
+ | | `sbd_data.dump_matrix_form_wf` | `savename` argument |
324
+ |---|---|---|
325
+ | Writes | the full `len(adet) × len(bdet)` subspace, gathered onto one rank | one file per b_comm position, each holding **only that rank's block** |
326
+ | Path | exactly what you set | `f"{savename}{rank_b:06d}.bin"` |
327
+ | Header | **none** | three `size_t` (`adet_range`, `bdet_range`, `det_length`), then that block's alpha and beta determinant words |
328
+ | Payload | `float64`, row-major over α×β | `adet_range × bdet_range` `float64` |
329
+ | Intended for | analysis | checkpoint/restart, paired with `loadname` |
330
+
331
+ So the whole-subspace read is just:
332
+
333
+ ```python
334
+ config.dump_matrix_form_wf = "wf.bin"
335
+ results = sbd.tpb_diag(fcidump, adet, bdet, config)
336
+
337
+ amplitudes = np.fromfile("wf.bin").reshape(len(adet), len(bdet))
338
+ ```
339
+
340
+ Naming that file `.dat` or `.txt` instead writes a text table labelling every amplitude with its own alpha and beta bitstring — the easiest form to inspect by hand, and it sidesteps having to reconstruct the ordering yourself:
341
+
342
+ ```
343
+ <amplitude> # <alpha index>: <alpha bitstring> <beta index>: <beta bitstring>
344
+ ```
345
+
346
+ Be aware that this text form is written with the stream's default formatting, so amplitudes land with only ~6 significant digits; use the binary form when you need full `float64` precision.
347
+
348
+ Rows and columns follow `adet`/`bdet` as the diagonalizer saw them. `sort_bitarray` removes duplicates as well as sorting, so pass lists already in that form if you intend to label the axes yourself — `from_strings` documents the word packing.
349
+
350
+ This is the mechanism [`sbd_solver.py`](python/sbd_solver.py) uses to populate `SCIState.amplitudes` — though it skips the write entirely when SBD is picking the carryover itself (`carryover_type` 1, against a qiskit-addon-sqd that accepts it), since then the next subspace comes back in `carryover_adet`/`carryover_bdet` and the amplitudes never need to reach Python.
351
+
318
352
  ```python
319
353
  # GDB: over an explicit list of full determinants rather than a product space
320
354
  results = sbd.gdb_diag(fcidump, det, sbd_data,
@@ -224,6 +224,7 @@ config = sbd.TPB_SBD()
224
224
  | `adet_comm_size` | 1 | Alpha determinant communicator size |
225
225
  | `bdet_comm_size` | 1 | Beta determinant communicator size |
226
226
  | `task_comm_size` | 1 | Task communicator size |
227
+ | `dump_matrix_form_wf` | `""` | Path to write the amplitudes to — see [Getting the TPB amplitudes](#getting-the-tpb-amplitudes) for the file format |
227
228
 
228
229
  Total MPI ranks = `task_comm_size × adet_comm_size × bdet_comm_size`.
229
230
 
@@ -267,6 +268,39 @@ results = sbd.tpb_diag(fcidump, adet, bdet, sbd_data,
267
268
 
268
269
  **Returns:** `dict` with keys `energy`, `density`, `carryover_adet`, `carryover_bdet`, `one_p_rdm`, `two_p_rdm`.
269
270
 
271
+ #### Getting the TPB amplitudes
272
+
273
+ Neither return dict holds the wavefunction amplitudes. Two separate mechanisms write them, in **different formats**, and the one named in the function signature is not the one most callers want:
274
+
275
+ | | `sbd_data.dump_matrix_form_wf` | `savename` argument |
276
+ |---|---|---|
277
+ | Writes | the full `len(adet) × len(bdet)` subspace, gathered onto one rank | one file per b_comm position, each holding **only that rank's block** |
278
+ | Path | exactly what you set | `f"{savename}{rank_b:06d}.bin"` |
279
+ | Header | **none** | three `size_t` (`adet_range`, `bdet_range`, `det_length`), then that block's alpha and beta determinant words |
280
+ | Payload | `float64`, row-major over α×β | `adet_range × bdet_range` `float64` |
281
+ | Intended for | analysis | checkpoint/restart, paired with `loadname` |
282
+
283
+ So the whole-subspace read is just:
284
+
285
+ ```python
286
+ config.dump_matrix_form_wf = "wf.bin"
287
+ results = sbd.tpb_diag(fcidump, adet, bdet, config)
288
+
289
+ amplitudes = np.fromfile("wf.bin").reshape(len(adet), len(bdet))
290
+ ```
291
+
292
+ Naming that file `.dat` or `.txt` instead writes a text table labelling every amplitude with its own alpha and beta bitstring — the easiest form to inspect by hand, and it sidesteps having to reconstruct the ordering yourself:
293
+
294
+ ```
295
+ <amplitude> # <alpha index>: <alpha bitstring> <beta index>: <beta bitstring>
296
+ ```
297
+
298
+ Be aware that this text form is written with the stream's default formatting, so amplitudes land with only ~6 significant digits; use the binary form when you need full `float64` precision.
299
+
300
+ Rows and columns follow `adet`/`bdet` as the diagonalizer saw them. `sort_bitarray` removes duplicates as well as sorting, so pass lists already in that form if you intend to label the axes yourself — `from_strings` documents the word packing.
301
+
302
+ This is the mechanism [`sbd_solver.py`](python/sbd_solver.py) uses to populate `SCIState.amplitudes` — though it skips the write entirely when SBD is picking the carryover itself (`carryover_type` 1, against a qiskit-addon-sqd that accepts it), since then the next subspace comes back in `carryover_adet`/`carryover_bdet` and the amplitudes never need to reach Python.
303
+
270
304
  ```python
271
305
  # GDB: over an explicit list of full determinants rather than a product space
272
306
  results = sbd.gdb_diag(fcidump, det, sbd_data,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sbd-eigensolver"
7
- version = "1.7.0"
7
+ version = "1.7.1"
8
8
  description = "Python bindings for Selected Basis Diagonalization (SBD) library"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -318,8 +318,9 @@ def init(device='cpu', comm_backend='mpi'):
318
318
  first use with ``device='cpu'`` and ``comm_backend='mpi'``. Call it
319
319
  explicitly only when you need GPU or want to control startup timing.
320
320
 
321
- The device can be overridden per-call via the ``device`` parameter on
322
- ``tpb_diag()``, ``tpb_diag_from_files()``, and ``get_backend()``.
321
+ The device can be overridden per call via the ``device`` parameter of
322
+ ``tpb_diag()``, ``tpb_diag_from_files()``, ``gdb_diag()`` and
323
+ ``get_backend()``.
323
324
 
324
325
  Args:
325
326
  device: Default compute device — 'cpu', 'gpu', 'gpu-omp', or 'auto'.
@@ -413,11 +414,20 @@ def get_backend(device=None):
413
414
  Get the backend module for the given device.
414
415
 
415
416
  Auto-initializes SBD if needed. Passing ``device`` overrides the
416
- default — this is how you switch between CPU and GPU within the
417
- same process.
417
+ default, which is how you switch backends within one process. The one
418
+ combination to avoid is the CPU backend together with the OpenMP-offload
419
+ one ('gpu-omp'): they share an OpenMP runtime, and loading both leaves
420
+ offload regions running on the host. ``sbd.has_backend_conflict()``
421
+ reports it.
418
422
 
419
423
  Args:
420
- device: 'cpu', 'gpu', 'auto', or None (use default).
424
+ device: 'cpu', 'gpu' (Thrust), 'gpu-omp' (OpenMP offload), 'auto', an
425
+ alias accepted by :func:`init`, or None. None means the device set
426
+ by :func:`init`. If nothing has initialized yet it means 'auto',
427
+ which prefers Thrust, then OpenMP offload, then CPU, whereas the
428
+ first call of :func:`tpb_diag` or :func:`gdb_diag` initializes with
429
+ 'cpu'. Call :func:`init` with the device you want to avoid
430
+ depending on call order.
421
431
 
422
432
  Returns:
423
433
  The pybind11 backend module (_core_cpu, _core_gpu_thrust, or
@@ -496,13 +506,19 @@ def barrier():
496
506
  # ---------------------------------------------------------------------------
497
507
 
498
508
  def TPB_SBD(device=None):
499
- """Create TPB_SBD configuration object."""
509
+ """Create a TPB_SBD configuration object, for :func:`tpb_diag`.
510
+
511
+ Its fields are listed in the tables below.
512
+ """
500
513
  _ensure_initialized()
501
514
  return get_backend(device).TPB_SBD()
502
515
 
503
516
 
504
517
  def GDB_SBD(device=None):
505
- """Create GDB_SBD configuration object."""
518
+ """Create a GDB_SBD configuration object, for :func:`gdb_diag`.
519
+
520
+ Its fields are listed in the tables below.
521
+ """
506
522
  _ensure_initialized()
507
523
  return get_backend(device).GDB_SBD()
508
524
 
@@ -514,25 +530,65 @@ def FCIDump(device=None):
514
530
 
515
531
 
516
532
  def LoadFCIDump(filename, device=None):
517
- """Load FCIDUMP file."""
533
+ """Load an FCIDUMP file.
534
+
535
+ Args:
536
+ filename: Path to the FCIDUMP file.
537
+ device: Backend whose ``FCIDump`` type to build; None uses the default.
538
+
539
+ Returns:
540
+ The ``FCIDump`` object that :func:`tpb_diag` and :func:`gdb_diag` take.
541
+ """
518
542
  _ensure_initialized()
519
543
  return get_backend(device).LoadFCIDump(filename)
520
544
 
521
545
 
522
546
  def LoadAlphaDets(filename, bit_length, total_bit_length, device=None):
523
- """Load alpha determinants from file."""
547
+ """Load determinants from a file of bitstrings, one per line.
548
+
549
+ Each line is packed as :func:`from_strings` does. Upstream sorts the
550
+ determinants and removes duplicates, so the result is ready to use as a
551
+ TPB determinant list and may hold fewer determinants than the file has
552
+ lines.
553
+
554
+ The format is chosen by extension: ``.txt`` for one bitstring per line,
555
+ ``.bin`` for upstream's binary format. Any other extension returns an
556
+ empty list without an error.
557
+
558
+ Args:
559
+ filename: Path to the file.
560
+ bit_length: Bits per packed word. Must match the config's
561
+ ``bit_length``.
562
+ total_bit_length: Length of each bitstring, ``norb`` for the alpha or
563
+ beta strings of TPB.
564
+ device: Backend to use; None uses the default.
565
+
566
+ Returns:
567
+ A list of packed determinants, each a list of words, sorted and
568
+ distinct.
569
+ """
524
570
  _ensure_initialized()
525
571
  return get_backend(device).LoadAlphaDets(filename, bit_length, total_bit_length)
526
572
 
527
573
 
528
574
  def makestring(config, bit_length, total_bit_length, device=None):
529
- """Convert determinant to string representation."""
575
+ """Render a packed determinant as a ``total_bit_length``-character string.
576
+
577
+ The inverse of :func:`from_string`, and subject to the same right-to-left
578
+ word packing, which :func:`from_strings` describes.
579
+ """
530
580
  _ensure_initialized()
531
581
  return get_backend(device).makestring(config, bit_length, total_bit_length)
532
582
 
533
583
 
534
584
  def from_string(s, bit_length, total_bit_length, device=None):
535
- """Convert binary string to determinant format."""
585
+ """Convert a binary string to SBD's packed determinant format.
586
+
587
+ Returns a list of ``size_t`` words, e.g. ``from_string("0011", 20, 4)`` is
588
+ ``[3]``. :func:`makestring` is the inverse. See :func:`from_strings`, the
589
+ bulk form, for the word-packing convention and for why it is worth
590
+ preferring that form outside of one-off calls.
591
+ """
536
592
  _ensure_initialized()
537
593
  return get_backend(device).from_string(s, bit_length, total_bit_length)
538
594
 
@@ -540,10 +596,29 @@ def from_string(s, bit_length, total_bit_length, device=None):
540
596
  def from_strings(strings, bit_length, total_bit_length, device=None):
541
597
  """Pack many bitstrings into one ``(n, words)`` array.
542
598
 
543
- The bulk form of :func:`from_string`, looping in C++ instead of once per
599
+ The bulk form of ``sbd.from_string``, looping in C++ instead of once per
544
600
  determinant across the Python boundary. Prefer it for anything larger than a
545
601
  handful: the per-call form costs tens of thousands of round trips on the
546
602
  vendored inputs alone.
603
+
604
+ Each row holds ``total_bit_length`` bits packed ``bit_length`` to a word, so
605
+ a bitstring longer than ``bit_length`` occupies more than one word. The
606
+ packing runs from the **right end** of the string: its trailing
607
+ ``bit_length`` characters become word 0, the next ``bit_length`` to the left
608
+ become word 1, and so on, so the leading characters of a multi-word string
609
+ land in the *last* word rather than the first::
610
+
611
+ from_strings(["0011"], 20, 4) # -> array([[3]], dtype=uint64)
612
+ from_strings(["1" + "0" * 69], 62, 70) # -> array([[ 0, 128]], ...)
613
+ from_strings(["0" * 69 + "1"], 62, 70) # -> array([[1, 0]], ...)
614
+
615
+ Within a word the rightmost character is the least significant bit, which is
616
+ why ``"0011"`` packs to ``3`` rather than ``12``. Getting this backwards
617
+ produces a valid-looking but wrong subspace rather than an error, so check
618
+ round trips with ``sbd.makestring`` when building determinants by hand.
619
+
620
+ ``bit_length`` must match the ``bit_length`` of the config passed to the
621
+ diagonalizers, since it sets how many words each determinant occupies.
547
622
  """
548
623
  _ensure_initialized()
549
624
  return get_backend(device).from_strings(list(strings), bit_length, total_bit_length)
@@ -575,17 +650,27 @@ def tpb_diag_from_files(fcidumpfile, adetfile, sbd_data,
575
650
  """
576
651
  Perform TPB diagonalization from files.
577
652
 
653
+ The one determinant file supplies both the alpha and the beta list, so the
654
+ subspace is the product of that list with itself. For different alpha and
655
+ beta lists, as an open-shell case needs, load them and call :func:`tpb_diag`.
656
+
578
657
  Args:
579
658
  fcidumpfile: Path to FCIDUMP file.
580
- adetfile: Path to alpha determinants file.
659
+ adetfile: Path to the determinant file, used for both alpha and beta.
581
660
  sbd_data: TPB_SBD configuration object.
582
- loadname: Path to load initial wavefunction (optional).
583
- savename: Path to save final wavefunction (optional).
584
- device: Override device ('cpu', 'gpu', or None for default).
661
+ loadname: Path prefix to load an initial wavefunction from (optional).
662
+ savename: Path prefix to save the final wavefunction to (optional).
663
+ device: Backend to run on: 'cpu', 'gpu' (Thrust), 'gpu-omp' (OpenMP
664
+ offload), or an alias accepted by :func:`init`. None uses the
665
+ default; see :func:`get_backend`.
585
666
 
586
667
  Returns:
587
668
  dict with keys: energy, density, carryover_adet, carryover_bdet,
588
669
  one_p_rdm, two_p_rdm.
670
+
671
+ Note:
672
+ As with :func:`tpb_diag`, no amplitudes are returned in the dict; see
673
+ that function for the two ways of writing them to disk.
589
674
  """
590
675
  _ensure_initialized()
591
676
  backend = get_backend(device)
@@ -604,13 +689,54 @@ def tpb_diag(fcidump, adet, bdet, sbd_data,
604
689
  adet: Alpha determinants.
605
690
  bdet: Beta determinants.
606
691
  sbd_data: TPB_SBD configuration object.
607
- loadname: Path to load initial wavefunction (optional).
608
- savename: Path to save final wavefunction (optional).
609
- device: Override device ('cpu', 'gpu', or None for default).
692
+ loadname: Path prefix to load an initial wavefunction from (optional).
693
+ savename: Path prefix to save the final wavefunction to (optional). See
694
+ the note below: for reading amplitudes back,
695
+ ``sbd_data.dump_matrix_form_wf`` is usually the one you want.
696
+ device: Backend to run on: 'cpu', 'gpu' (Thrust), 'gpu-omp' (OpenMP
697
+ offload), or an alias accepted by :func:`init`. None uses the
698
+ default; see :func:`get_backend`.
610
699
 
611
700
  Returns:
612
701
  dict with keys: energy, density, carryover_adet, carryover_bdet,
613
702
  one_p_rdm, two_p_rdm.
703
+
704
+ Note:
705
+ The returned dict holds no wavefunction amplitudes. There are two ways
706
+ to get them, and they write *different* formats -- do not mix them up:
707
+
708
+ ``sbd_data.dump_matrix_form_wf = "wf.bin"`` writes the full
709
+ ``len(adet) x len(bdet)`` subspace, gathered onto one rank, as a bare
710
+ row-major array of ``float64`` with **no header** -- so
711
+ ``np.fromfile(path).reshape(len(adet), len(bdet))`` reads it. Naming it
712
+ ``.dat`` or ``.txt`` instead writes a text table in which every
713
+ amplitude is labelled with its own alpha and beta bitstring, which is
714
+ the easiest form to inspect by hand. This is the mechanism this
715
+ package's own SQD integration uses.
716
+
717
+ ``savename`` instead writes one file per b_comm position,
718
+ ``f"{savename}{rank_b:06d}.bin"``, each holding only **that rank's
719
+ block** of the subspace: three ``size_t`` headers
720
+ (``adet_range``, ``bdet_range``, ``det_length``), then that block's
721
+ alpha and then beta determinant words, then
722
+ ``adet_range x bdet_range`` ``float64`` amplitudes. It pairs with
723
+ ``loadname`` for restarting a run, so it is the better choice for
724
+ checkpointing and the worse one for analysis.
725
+
726
+ Amplitudes are ordered by ``adet``/``bdet`` as the diagonalizer saw
727
+ them. ``sort_bitarray`` removes duplicates as well as sorting, so pass
728
+ lists already in that form if you need to label the rows and columns
729
+ yourself.
730
+
731
+ Both files use SBD's sign convention, which orders a determinant's
732
+ creation operators orbital by orbital (alpha 0, beta 0, alpha 1, ...).
733
+ PySCF, and so qiskit-addon-sqd's ``SCIState``, puts all alpha operators
734
+ before all beta ones, so some determinants differ in sign: multiply each
735
+ amplitude by ``(-1) ** n``, where ``n`` counts, over the occupied beta
736
+ orbitals ``p``, the occupied alpha orbitals above ``p``, before handing
737
+ it to PySCF. Magnitudes, and so selection by weight, are the same either
738
+ way. :func:`sbd.sbd_solver.solve_sci` converts the amplitudes in its
739
+ ``SCIState`` already.
614
740
  """
615
741
  _ensure_initialized()
616
742
  backend = get_backend(device)
@@ -671,7 +797,11 @@ def gdb_diag(fcidump, det, sbd_data,
671
797
  writes one file per b_comm position, ``f"{savename}{rank_b:06d}.bin"``,
672
798
  each holding only that shard; rank 0's file is not the whole
673
799
  wavefunction. GDB has no combined matrix-form dump.
674
- device: Override device ('cpu', 'gpu', or None for default).
800
+ device: Backend to run on: 'cpu', 'gpu' (Thrust), 'gpu-omp' (OpenMP
801
+ offload), or an alias accepted by :func:`init`. None uses the
802
+ default; see :func:`get_backend`. 'gpu-omp' is accepted, but SBD
803
+ has no OpenMP-offload GDB code, so the run executes on the host;
804
+ use 'gpu' for GDB on GPUs.
675
805
  determinant_distribution: How to place determinants across b_comm — one
676
806
  of ``input`` (keep the shards as given), ``equal-bra-a`` (default;
677
807
  equal distinct-alpha count per rank, which is what balances the
@@ -319,7 +319,12 @@ PYBIND11_MODULE(SBD_MODULE_NAME, m) {
319
319
  .def_readwrite("bit_length", &sbd::tpb::SBD::bit_length,
320
320
  "Bit length for determinant representation")
321
321
  .def_readwrite("dump_matrix_form_wf", &sbd::tpb::SBD::dump_matrix_form_wf,
322
- "Filename to dump wavefunction in matrix form")
322
+ "Path to write the full adet x bdet amplitude matrix to, "
323
+ "gathered onto one rank. A .bin path writes a bare "
324
+ "row-major float64 array with no header; .dat/.txt write "
325
+ "a labelled text table. Distinct from tpb_diag's "
326
+ "savename, which writes per-rank blocks with a header "
327
+ "for restart -- see the tpb_diag docstring.")
323
328
  #ifdef SBD_THRUST
324
329
  .def_readwrite("use_precalculated_dets", &sbd::tpb::SBD::use_precalculated_dets,
325
330
  "Use precalculated determinants (THRUST)")
@@ -27,18 +27,14 @@ class DeviceConfig:
27
27
 
28
28
  Usage::
29
29
 
30
- # Auto-detect (uses GPU if available)
31
- config = DeviceConfig.auto()
30
+ from sbd.device_config import DeviceConfig
31
+ from sbd.sbd_solver import solve_sci_batch
32
32
 
33
- # Force CPU
34
- config = DeviceConfig.cpu()
33
+ device = DeviceConfig.auto() # best backend that is built
34
+ device = DeviceConfig.cpu() # or force one
35
+ device = DeviceConfig.gpu(max_memory_gb=16)
35
36
 
36
- # Force GPU with specific settings
37
- config = DeviceConfig.gpu(max_memory_gb=16)
38
-
39
- # Apply to SBD configuration
40
- sbd_config = sbd.TPB_SBD()
41
- config.apply(sbd_config)
37
+ results = solve_sci_batch(..., device_config=device)
42
38
  """
43
39
 
44
40
  def __init__(self, device: str = 'cpu',
@@ -72,17 +68,11 @@ class DeviceConfig:
72
68
  """
73
69
  Auto-detect the best available backend and use it.
74
70
 
75
- Resolves against the backends that were actually COMPILED, not just the
76
- hardware that is present. Detecting a GPU and returning 'gpu'
77
- unconditionally was wrong in two ways: on an AMD host it selected the
78
- Thrust/CUDA backend, which cannot exist there (upstream wires Thrust to
79
- nvc++ -cuda), so a machine that reported "GPU detected (HIP)" then failed
80
- to load a CUDA module; and on a CPU-only build with a GPU present it
81
- picked a backend that was never built.
82
-
83
- Preference order matches sbd._resolve_device(): Thrust ('gpu') first
84
- where it exists, since it is the long-validated NVIDIA default and keeps
85
- more phases on the device, then OpenMP offload ('gpu-omp'), then CPU.
71
+ Chooses among the backends that were actually built, not merely the
72
+ hardware present, so an AMD host or a CPU-only build is never handed a
73
+ backend it lacks. The preference order is Thrust ('gpu') where it exists,
74
+ then OpenMP offload ('gpu-omp'), then CPU, the same order
75
+ ``sbd.get_backend('auto')`` uses.
86
76
 
87
77
  Args:
88
78
  max_memory_gb: Maximum GPU memory in GB (-1 = auto)
@@ -158,8 +148,8 @@ class DeviceConfig:
158
148
  one combination to avoid in a single process is this backend together
159
149
  with the CPU one: they share an OpenMP runtime (``libnvomp`` on NVIDIA,
160
150
  ``libomp`` on AMD), and loading ``_core_cpu`` first leaves it initialised
161
- host-only, after which offload regions run on the host. See
162
- :func:`sbd.has_backend_conflict`.
151
+ host-only, after which offload regions run on the host.
152
+ ``sbd.has_backend_conflict()`` reports that combination.
163
153
  """
164
154
  return cls(device='gpu-omp', max_memory_gb=max_memory_gb)
165
155
 
@@ -297,8 +297,10 @@ def _solve_sci_core(
297
297
  "a different size means the dump and the subspace have diverged."
298
298
  )
299
299
 
300
+ amplitudes = flat.reshape(n_a, n_b)
301
+ _to_alpha_first_signs(amplitudes, solved_strings_a, solved_strings_b, norb)
300
302
  sci_state = SCIState(
301
- amplitudes=flat.reshape(n_a, n_b),
303
+ amplitudes=amplitudes,
302
304
  ci_strs_a=solved_strings_a,
303
305
  ci_strs_b=solved_strings_b,
304
306
  norb=norb,
@@ -470,25 +472,20 @@ def assemble_rdms(results: dict, norb: int) -> tuple[np.ndarray | None, np.ndarr
470
472
  which only computes the diagonal density, not the correlation
471
473
  functions), matching SCIResult's own ``rdm1``/``rdm2`` default.
472
474
 
473
- The reshape/transpose below is not a guess: it was verified against
474
- PySCF's ``make_rdm1``/``make_rdm2`` on a fixed subspace, on all three
475
- SBD backends (cpu, gpu-thrust, gpu-omp-offload) -- both element-wise on
476
- the full tensors and via the energy identity
475
+ The layout conversion was verified against PySCF's ``make_rdm1`` and
476
+ ``make_rdm2`` on all three backends (cpu, gpu, gpu-omp), both element-wise
477
+ and through the energy identity
477
478
  ``E = einsum("pr,pr->",rdm1,hcore) + 0.5*einsum("prqs,prqs->",rdm2,eri)``
478
- that ``SCIResult.rdm1``/``rdm2`` are contracted with everywhere else in
479
- qiskit-addon-sqd (e.g. ``fermion.py``'s own ``solve_fermion``).
479
+ with which ``qiskit-addon-sqd`` contracts ``SCIResult.rdm1`` and ``rdm2``.
480
480
 
481
- SBD's documented layout (sbd-ext docs/user-guide.md, matching the C++
482
- reference in apps/chemistry_tpb_selected_basis_diagonalization/main.cc)::
481
+ SBD's layout, as documented in upstream SBD's ``docs/user-guide.md``::
483
482
 
484
483
  one_p_rdm[s][i + L*j] = <c+_{i,s} c_{j,s}>
485
484
  two_p_rdm[s+2t][i + L*j + L^2*k + L^3*l] = <c+_{i,s} c+_{j,t} c_{l,t} c_{k,s}>
486
485
 
487
- A Fortran-order reshape implements those flat-index formulas directly
488
- (arr_F[i, j] / arr_F[i, j, k, l]); rdm1 needs no further transpose
489
- (it is symmetric here regardless), and rdm2's spin-summed block sum
490
- needs axes (0, 2, 1, 3) to land in the "prqs" slot order SCIResult's
491
- contract expects.
486
+ A Fortran-order reshape implements those flat-index formulas directly.
487
+ rdm1 needs no further transpose, and the spin-summed rdm2 is transposed
488
+ with axes ``(0, 2, 1, 3)`` into the "prqs" order ``SCIResult`` expects.
492
489
  """
493
490
  one_p_rdm = results.get("one_p_rdm")
494
491
  two_p_rdm = results.get("two_p_rdm")
@@ -693,6 +690,41 @@ def _ci_strings_to_sbd_dets(
693
690
  return backend.sort_bitarray(dets)
694
691
 
695
692
 
693
+ def _to_alpha_first_signs(amplitudes, strings_a, strings_b, norb, block_elements=1 << 24):
694
+ """Convert SBD's amplitudes, in place, to the sign convention SCIState assumes.
695
+
696
+ The two conventions order the creation operators of a determinant differently.
697
+ SBD interleaves the spins orbital by orbital (alpha 0, beta 0, alpha 1, ...);
698
+ PySCF, and so ``SCIState.rdm()`` and ``SCIState.spin_square()``, put every alpha
699
+ operator before every beta one. Moving each beta operator past the alpha
700
+ operators of higher orbitals gives the determinant the phase
701
+
702
+ (-1) ** sum over occupied beta orbitals p of (occupied alpha orbitals above p)
703
+
704
+ The magnitudes are the same, so energies, SBD's own RDMs, occupancies and any
705
+ selection by amplitude magnitude are unaffected, which is why this went unnoticed:
706
+ only what PySCF computes *from the amplitudes* was wrong -- e.g. ``spin_square()``
707
+ of 0.036 for an exact singlet, and an energy from ``rdm()`` 89 mHa off.
708
+
709
+ Args:
710
+ amplitudes: The ``(len(strings_a), len(strings_b))`` matrix, modified in place.
711
+ strings_a: Alpha CI strings labelling the rows; bit ``p`` is orbital ``p``.
712
+ strings_b: Beta CI strings labelling the columns.
713
+ norb: Number of spatial orbitals.
714
+ block_elements: Rows are converted in blocks of about this many elements, so
715
+ the temporary sign matrix stays bounded at large subspaces.
716
+ """
717
+ orbitals = np.arange(norb, dtype=np.int64)
718
+ occupied_b = ((np.asarray(strings_b, dtype=np.int64)[:, None] >> orbitals) & 1).astype(np.int32)
719
+ occupied_a = (np.asarray(strings_a, dtype=np.int64)[:, None] >> orbitals) & 1
720
+ # alpha electrons in orbitals strictly above p, kept only as a parity
721
+ above_a = ((np.cumsum(occupied_a[:, ::-1], axis=1)[:, ::-1] - occupied_a) & 1).astype(np.int32)
722
+ rows = max(1, block_elements // max(1, len(strings_b)))
723
+ for start in range(0, len(strings_a), rows):
724
+ parity = (above_a[start:start + rows] @ occupied_b.T) & 1
725
+ amplitudes[start:start + rows][parity == 1] *= -1.0
726
+
727
+
696
728
  def _sbd_dets_to_ci_strings(
697
729
  dets: list[list[int]], norb: int, backend,
698
730
  bit_length: int = SBD_DEFAULT_BIT_LENGTH,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sbd-eigensolver
3
- Version: 1.7.0
3
+ Version: 1.7.1
4
4
  Summary: Python bindings for Selected Basis Diagonalization (SBD) library
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/Qiskit/sbd-eigensolver-python
@@ -272,6 +272,7 @@ config = sbd.TPB_SBD()
272
272
  | `adet_comm_size` | 1 | Alpha determinant communicator size |
273
273
  | `bdet_comm_size` | 1 | Beta determinant communicator size |
274
274
  | `task_comm_size` | 1 | Task communicator size |
275
+ | `dump_matrix_form_wf` | `""` | Path to write the amplitudes to — see [Getting the TPB amplitudes](#getting-the-tpb-amplitudes) for the file format |
275
276
 
276
277
  Total MPI ranks = `task_comm_size × adet_comm_size × bdet_comm_size`.
277
278
 
@@ -315,6 +316,39 @@ results = sbd.tpb_diag(fcidump, adet, bdet, sbd_data,
315
316
 
316
317
  **Returns:** `dict` with keys `energy`, `density`, `carryover_adet`, `carryover_bdet`, `one_p_rdm`, `two_p_rdm`.
317
318
 
319
+ #### Getting the TPB amplitudes
320
+
321
+ Neither return dict holds the wavefunction amplitudes. Two separate mechanisms write them, in **different formats**, and the one named in the function signature is not the one most callers want:
322
+
323
+ | | `sbd_data.dump_matrix_form_wf` | `savename` argument |
324
+ |---|---|---|
325
+ | Writes | the full `len(adet) × len(bdet)` subspace, gathered onto one rank | one file per b_comm position, each holding **only that rank's block** |
326
+ | Path | exactly what you set | `f"{savename}{rank_b:06d}.bin"` |
327
+ | Header | **none** | three `size_t` (`adet_range`, `bdet_range`, `det_length`), then that block's alpha and beta determinant words |
328
+ | Payload | `float64`, row-major over α×β | `adet_range × bdet_range` `float64` |
329
+ | Intended for | analysis | checkpoint/restart, paired with `loadname` |
330
+
331
+ So the whole-subspace read is just:
332
+
333
+ ```python
334
+ config.dump_matrix_form_wf = "wf.bin"
335
+ results = sbd.tpb_diag(fcidump, adet, bdet, config)
336
+
337
+ amplitudes = np.fromfile("wf.bin").reshape(len(adet), len(bdet))
338
+ ```
339
+
340
+ Naming that file `.dat` or `.txt` instead writes a text table labelling every amplitude with its own alpha and beta bitstring — the easiest form to inspect by hand, and it sidesteps having to reconstruct the ordering yourself:
341
+
342
+ ```
343
+ <amplitude> # <alpha index>: <alpha bitstring> <beta index>: <beta bitstring>
344
+ ```
345
+
346
+ Be aware that this text form is written with the stream's default formatting, so amplitudes land with only ~6 significant digits; use the binary form when you need full `float64` precision.
347
+
348
+ Rows and columns follow `adet`/`bdet` as the diagonalizer saw them. `sort_bitarray` removes duplicates as well as sorting, so pass lists already in that form if you intend to label the axes yourself — `from_strings` documents the word packing.
349
+
350
+ This is the mechanism [`sbd_solver.py`](python/sbd_solver.py) uses to populate `SCIState.amplitudes` — though it skips the write entirely when SBD is picking the carryover itself (`carryover_type` 1, against a qiskit-addon-sqd that accepts it), since then the next subspace comes back in `carryover_adet`/`carryover_bdet` and the amplitudes never need to reach Python.
351
+
318
352
  ```python
319
353
  # GDB: over an explicit list of full determinants rather than a product space
320
354
  results = sbd.gdb_diag(fcidump, det, sbd_data,
@@ -27,6 +27,7 @@ sbd_eigensolver.egg-info/top_level.txt
27
27
  test/test_gdb_drivers.py
28
28
  test/test_gdb_equivalence.py
29
29
  test/test_reference_energies.py
30
+ test/test_sci_state.py
30
31
  test/test_sqd_integration.py
31
32
  vendor/sbd-upstream/LICENSE.txt
32
33
  vendor/sbd-upstream/include/sbd/sbd.h