-
Notifications
You must be signed in to change notification settings - Fork 44
PR[9] (combine PR-1-PR-8) feat: combine weeks 1-9 implementations into single branch #245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
2d3fe98
feat: add Boys function APIs and validation tests
San1357 db5045e
fix: move qc-dev-env/ from.gitignore to .git/info/exclude
San1357 4824a2a
refactor: vectorize boys_function_all_orders with NumPy broadcasting
San1357 5278ebf
fix: add raise-from in mpmath ImportError (ruff B904)
San1357 c19cb89
feat: implement VRR (Eq. 65) for OS+HGP two-electron integral pipeline
San1357 2ec8140
feat: implement ETR (Eq. 66) and primitive contraction for OS+HGP pip…
San1357 6e40ec7
feat: implement HRR (Eq. 67) and complete OS+HGP pipeline
San1357 bf6e727
add test files for two elect int improved.py
San1357 8ab104e
test: add erf/erfc attenuated Boys function tests and update docstring
San1357 4347444
style: apply black/ruff formatting to test_boys_functions.py
San1357 d96fd22
style: apply black/ruff formatting fixes to test_two_elec_int_improve…
San1357 7ec98dd
style: move imports to top-level, fix ruff PLC0415 in test file
San1357 f0f57fa
style: fix black formatting
San1357 2cea131
refactor: vectorize norm computation over all 4 centers using NumPy a…
San1357 60ddebb
test: add tests for _optimized_contraction
San1357 e1612a7
fix: handle different K per center in _optimized_contraction
San1357 3411d23
style: fix black formatting and import sorting in test_electron_repul…
San1357 6314d78
feat: implement Schwarz screening to optimize two-electron integral c…
San1357 cdf9bd4
feat: add PySCF comparison tests and OS+HGP tutorial notebook
San1357 84c7511
Merge branch 'feat/VRR-two-electron-integral' into local-test-all
San1357 4ee3247
merge: resolve add/add conflicts keeping electron-repulsion-improved …
San1357 b6ff02c
Merge branch 'feat/schwarz-screening' into local-test-all
San1357 7c85807
Merge branch 'feat/pyscf-tests-tutorial' into local-test-all
San1357 f630272
fix: tighten libcint ERI tolerance and use improved implementation (#…
San1357 4e2994e
Merge branch 'feat/libcint-tolerance-fix' into local-test-all
San1357 b351377
fix: add pyscf to dev deps and remove conditional imports in test
San1357 6e3a73e
fix: use pytest.importorskip for pyscf instead of dev dependency
San1357 0c215e6
fix: pass rho=harm_mean to boys_func to support erf/erfc attenuated p…
San1357 874c15b
fix: replace tautological assertions with monotonicity check in test_…
San1357 65879ad
fix: pass screener via kwargs instead of class-level state for thread…
San1357 fb9e1a6
perf: cache SchwarzScreener to avoid recomputing bounds on every call
San1357 bfac8b0
revert: restore original ElectronRepulsionIntegral to use old algorithm
San1357 f2f0e0d
fix: use get_boys_function from boys_functions module in ElectronRepu…
San1357 76107ea
fix: use get_boys_function directly instead of ElectronRepulsionInteg…
San1357 104446c
fix: use boys_functions module directly instead of inline hyp1f1 or c…
San1357 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| """Integral screening utilities for efficient 2-electron integral computation. | ||
|
|
||
| This module implements Schwarz screening and shell-pair screening to skip | ||
| negligible integrals, providing speedup for spatially extended systems. | ||
|
|
||
| References: | ||
| - Häser, M. & Ahlrichs, R. J. Comput. Chem. 1989, 10, 104. | ||
| - Gill, P. M. W.; Johnson, B. G.; Pople, J. A. Int. J. Quantum Chem. 1991, 40, 745. | ||
| """ | ||
|
|
||
| import numpy as np | ||
|
|
||
|
|
||
| def compute_schwarz_bound_shell_pair(boys_func, cont_one, cont_two, compute_integral_func): | ||
| """Compute Schwarz bound for a shell pair: sqrt((ab|ab)). | ||
|
|
||
| Parameters | ||
| ---------- | ||
| boys_func : callable | ||
| Boys function for integral evaluation. | ||
| cont_one : GeneralizedContractionShell | ||
| First contracted shell. | ||
| cont_two : GeneralizedContractionShell | ||
| Second contracted shell. | ||
| compute_integral_func : callable | ||
| Function to compute (ab|cd) integrals. | ||
|
|
||
| Returns | ||
| ------- | ||
| bound : float | ||
| Schwarz bound sqrt(max|(ab|ab)|) for this shell pair. | ||
| """ | ||
| # Compute (ab|ab) integral | ||
| integral = compute_integral_func( | ||
| boys_func, | ||
| cont_one.coord, | ||
| cont_one.angmom, | ||
| cont_one.angmom_components_cart, | ||
| cont_one.exps, | ||
| cont_one.coeffs, | ||
| cont_two.coord, | ||
| cont_two.angmom, | ||
| cont_two.angmom_components_cart, | ||
| cont_two.exps, | ||
| cont_two.coeffs, | ||
| cont_one.coord, | ||
| cont_one.angmom, | ||
| cont_one.angmom_components_cart, | ||
| cont_one.exps, | ||
| cont_one.coeffs, | ||
| cont_two.coord, | ||
| cont_two.angmom, | ||
| cont_two.angmom_components_cart, | ||
| cont_two.exps, | ||
| cont_two.coeffs, | ||
| ) | ||
|
|
||
| # Return sqrt of maximum absolute value | ||
| return np.sqrt(np.max(np.abs(integral))) | ||
|
|
||
|
|
||
| def compute_schwarz_bounds(contractions, boys_func, compute_integral_func): | ||
| """Precompute Schwarz bounds for all shell pairs. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| contractions : list of GeneralizedContractionShell | ||
| List of all contracted shells. | ||
| boys_func : callable | ||
| Boys function for integral evaluation. | ||
| compute_integral_func : callable | ||
| Function to compute (ab|cd) integrals. | ||
|
|
||
| Returns | ||
| ------- | ||
| bounds : np.ndarray(n_shells, n_shells) | ||
| Schwarz bounds sqrt((ab|ab)) for each shell pair. | ||
| """ | ||
| n_shells = len(contractions) | ||
| bounds = np.zeros((n_shells, n_shells)) | ||
|
|
||
| for i, cont_i in enumerate(contractions): | ||
| for j in range(i, n_shells): | ||
| cont_j = contractions[j] | ||
| bounds[i, j] = compute_schwarz_bound_shell_pair( | ||
| boys_func, cont_i, cont_j, compute_integral_func | ||
| ) | ||
| bounds[j, i] = bounds[i, j] # Symmetry: (ab|ab) = (ba|ba) | ||
|
|
||
| return bounds | ||
|
|
||
|
|
||
| def shell_pair_significant(cont_one, cont_two, threshold=1e-12): | ||
| """Check if a shell pair is significant using primitive screening. | ||
|
|
||
| Uses the Gaussian product theorem: exp(-a*b/(a+b) * |A-B|^2) factor. | ||
| If this factor is below threshold for all primitive pairs, skip. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| cont_one : GeneralizedContractionShell | ||
| First contracted shell. | ||
| cont_two : GeneralizedContractionShell | ||
| Second contracted shell. | ||
| threshold : float | ||
| Screening threshold. | ||
|
|
||
| Returns | ||
| ------- | ||
| significant : bool | ||
| True if shell pair might contribute significantly. | ||
| """ | ||
| # Distance between shell centers | ||
| r_ab_sq = np.sum((cont_one.coord - cont_two.coord) ** 2) | ||
|
|
||
| if r_ab_sq < 1e-10: | ||
| # Same center, always significant | ||
| return True | ||
|
|
||
| # Check if any primitive pair survives screening | ||
| for exp_a in cont_one.exps: | ||
| for exp_b in cont_two.exps: | ||
| # Gaussian decay factor | ||
| decay = np.exp(-exp_a * exp_b / (exp_a + exp_b) * r_ab_sq) | ||
| if decay > threshold: | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
|
|
||
| class SchwarzScreener: | ||
| """Class for Schwarz integral screening. | ||
|
|
||
| Precomputes Schwarz bounds and provides efficient screening. | ||
|
|
||
| Attributes | ||
| ---------- | ||
| bounds : np.ndarray | ||
| Schwarz bounds for all shell pairs. | ||
| threshold : float | ||
| Screening threshold. | ||
| n_screened : int | ||
| Counter for number of screened shell quartets. | ||
| n_computed : int | ||
| Counter for number of computed shell quartets. | ||
| """ | ||
|
|
||
| def __init__(self, contractions, boys_func, compute_integral_func, threshold=1e-12): | ||
| """Initialize Schwarz screener. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| contractions : list of GeneralizedContractionShell | ||
| List of all contracted shells. | ||
| boys_func : callable | ||
| Boys function for integral evaluation. | ||
| compute_integral_func : callable | ||
| Function to compute (ab|cd) integrals. | ||
| threshold : float | ||
| Screening threshold (default: 1e-12). | ||
| """ | ||
| self.threshold = threshold | ||
| self.n_screened = 0 | ||
| self.n_computed = 0 | ||
|
|
||
| # Precompute Schwarz bounds | ||
| self.bounds = compute_schwarz_bounds(contractions, boys_func, compute_integral_func) | ||
|
|
||
| def is_significant(self, i, j, k, l_shell): | ||
| """Check if shell quartet (ij|kl) is significant. | ||
|
|
||
| Uses Schwarz inequality: |(ij|kl)| <= sqrt((ij|ij)) * sqrt((kl|kl)) | ||
|
|
||
| Parameters | ||
| ---------- | ||
| i, j, k, l_shell : int | ||
| Shell indices. | ||
|
|
||
| Returns | ||
| ------- | ||
| significant : bool | ||
| True if integral might be significant, False if can be skipped. | ||
| """ | ||
| bound = self.bounds[i, j] * self.bounds[k, l_shell] | ||
|
|
||
| if bound < self.threshold: | ||
| self.n_screened += 1 | ||
| return False | ||
| else: | ||
| self.n_computed += 1 | ||
| return True | ||
|
|
||
| def get_statistics(self): | ||
| """Get screening statistics. | ||
|
|
||
| Returns | ||
| ------- | ||
| stats : dict | ||
| Dictionary with screening statistics. | ||
| """ | ||
| total = self.n_screened + self.n_computed | ||
| if total == 0: | ||
| percent_screened = 0.0 | ||
| else: | ||
| percent_screened = 100.0 * self.n_screened / total | ||
|
|
||
| return { | ||
| "n_screened": self.n_screened, | ||
| "n_computed": self.n_computed, | ||
| "total": total, | ||
| "percent_screened": percent_screened, | ||
| "speedup_factor": total / max(self.n_computed, 1), | ||
| } | ||
|
|
||
| def reset_counters(self): | ||
| """Reset screening counters.""" | ||
| self.n_screened = 0 | ||
| self.n_computed = 0 | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here,
compute_schwarz_boundscallscompute_schwarz_bound_shell_pairfor each pair of shells. Thencompute_schwarz_bound_shell_paircomputes the integrals for each shell pair. Isn't this the same as computing all the integrals unscreened?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I get this, you run a$O(n^2)$ screening to screen the $O(n^4)$ integrals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, @marco-2023 — compute_schwarz_bounds runs in O(n²) over shell pairs, computing (ab|ab) type integrals. This upfront cost then screens out negligible shell quartets from the O(n⁴) ERI computation, which is where the real savings come from for larger basis sets.