symvb 2.0.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 (40) hide show
  1. symvb-2.0.0/LICENSE +21 -0
  2. symvb-2.0.0/PKG-INFO +152 -0
  3. symvb-2.0.0/README.md +122 -0
  4. symvb-2.0.0/setup.cfg +4 -0
  5. symvb-2.0.0/setup.py +44 -0
  6. symvb-2.0.0/symvb/__init__.py +18 -0
  7. symvb-2.0.0/symvb/_o2_benchmark.py +163 -0
  8. symvb-2.0.0/symvb/_o2_blocked.py +301 -0
  9. symvb-2.0.0/symvb/_o2_symmetric.py +124 -0
  10. symvb-2.0.0/symvb/data.py +24 -0
  11. symvb-2.0.0/symvb/fixed_psi.py +272 -0
  12. symvb-2.0.0/symvb/functions.py +231 -0
  13. symvb-2.0.0/symvb/huckel.py +322 -0
  14. symvb-2.0.0/symvb/mo_projection.py +252 -0
  15. symvb-2.0.0/symvb/molecule.py +736 -0
  16. symvb-2.0.0/symvb/numerical.py +267 -0
  17. symvb-2.0.0/symvb/operators.py +667 -0
  18. symvb-2.0.0/symvb/orbital_permutations.py +49 -0
  19. symvb-2.0.0/symvb/slaterdet.py +142 -0
  20. symvb-2.0.0/symvb/spin.py +233 -0
  21. symvb-2.0.0/symvb/symmetry.py +467 -0
  22. symvb-2.0.0/symvb/system.py +354 -0
  23. symvb-2.0.0/symvb/test_det_conventions.py +292 -0
  24. symvb-2.0.0/symvb/test_fixed_psi.py +170 -0
  25. symvb-2.0.0/symvb/test_functions.py +95 -0
  26. symvb-2.0.0/symvb/test_molecule.py +467 -0
  27. symvb-2.0.0/symvb/test_non_default_flags.py +124 -0
  28. symvb-2.0.0/symvb/test_numerical.py +72 -0
  29. symvb-2.0.0/symvb/test_o2_agreement.py +548 -0
  30. symvb-2.0.0/symvb/test_o2_symmetric.py +193 -0
  31. symvb-2.0.0/symvb/test_operators.py +227 -0
  32. symvb-2.0.0/symvb/test_slaterdet.py +93 -0
  33. symvb-2.0.0/symvb/test_symmetry_exact.py +234 -0
  34. symvb-2.0.0/symvb/test_system.py +297 -0
  35. symvb-2.0.0/symvb.egg-info/PKG-INFO +152 -0
  36. symvb-2.0.0/symvb.egg-info/SOURCES.txt +38 -0
  37. symvb-2.0.0/symvb.egg-info/dependency_links.txt +1 -0
  38. symvb-2.0.0/symvb.egg-info/requires.txt +3 -0
  39. symvb-2.0.0/symvb.egg-info/top_level.txt +1 -0
  40. symvb-2.0.0/symvb.egg-info/zip-safe +1 -0
symvb-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marat R. Talipov, Punhasa Senanayake, and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
symvb-2.0.0/PKG-INFO ADDED
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: symvb
3
+ Version: 2.0.0
4
+ Summary: Symbolic calculations for semi-quantitative Valence Bond Theory
5
+ Home-page: https://github.com/ComputationalChemistry-NMSU/symvb
6
+ Author: Marat Talipov
7
+ Author-email: talipovm@nmsu.edu
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: sympy>=1.13
17
+ Requires-Dist: numpy>=1.24
18
+ Requires-Dist: scipy>=1.10
19
+ Dynamic: author
20
+ Dynamic: author-email
21
+ Dynamic: classifier
22
+ Dynamic: description
23
+ Dynamic: description-content-type
24
+ Dynamic: home-page
25
+ Dynamic: license
26
+ Dynamic: license-file
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # symvb
32
+
33
+ Symbolic valence-bond theory in Python. `symvb` builds Slater
34
+ determinants over user-supplied orbital sets, computes one- and
35
+ two-electron matrix elements via Löwdin's cofactor expansion, and
36
+ returns the resulting Hamiltonian and overlap as `sympy` matrices —
37
+ everything stays symbolic in the bond, overlap, and Coulomb
38
+ parameters until you choose to substitute.
39
+
40
+ The package targets pedagogical and small-system research use:
41
+ H₂, allyl, benzene, (H₂)ₙ⁺ chains, cyclic polyenes, and similar
42
+ model systems where closed-form analysis is preferable to
43
+ purely numerical FCI.
44
+
45
+ ## Install
46
+
47
+ ```bash
48
+ pip install git+https://github.com/ComputationalChemistry-NMSU/symvb.git
49
+ ```
50
+
51
+ Or clone and run without installing:
52
+
53
+ ```bash
54
+ git clone https://github.com/ComputationalChemistry-NMSU/symvb.git
55
+ cd symvb
56
+ PYTHONPATH=. python3 examples/h2_hubbard_bond.py
57
+ ```
58
+
59
+ Python ≥ 3.8 (tested on 3.8 and 3.11). The symbolic core needs only
60
+ `sympy`; the numeric helpers (`ground_state(subs=...)`, the scan
61
+ patterns) and most examples also use `numpy` and `scipy`. For the
62
+ teaching notebooks add `jupyter` and `matplotlib`.
63
+
64
+ ## Quick start
65
+
66
+ ```python
67
+ from symvb import Molecule, FixedPsi, System
68
+
69
+ m = Molecule(zero_ii=True, interacting_orbs=['ab'],
70
+ subst={'h': ('H_ab',), 's': ('S_ab',)},
71
+ subst_2e={'U': ('1111',)}, max_2e_centers=1)
72
+ cov = FixedPsi('aB'); cov.add_str_det('bA', coef=1) # Heitler-London singlet
73
+ ion = FixedPsi('aA'); ion.add_str_det('bB', coef=1) # symmetric ionic
74
+
75
+ bond = System.from_structures(m, [cov, ion])
76
+ E, c = bond.ground_state() # symbolic ground-state energy + vector
77
+ w_cov, w_ion = bond.weights() # Chirgwin-Coulson weights
78
+
79
+ benzene = System.ring(6) # topology fills in every edge + on-site U
80
+ H, S = benzene.hamiltonian() # 400x400 sympy matrices, 2e block folded in (~1 min build)
81
+ ```
82
+
83
+ The underlying symbolic matrices stay fully accessible
84
+ (`m.build_matrix(P, op='H')`, `m.o2_matrix(P)`). See
85
+ [docs/recipes.md](docs/recipes.md) for common tasks and
86
+ [docs/api.md](docs/api.md) for the full surface.
87
+
88
+ ## Documentation
89
+
90
+ - [docs/api.md](docs/api.md) — API reference: modules, signatures, conventions.
91
+ - [docs/recipes.md](docs/recipes.md) — task-oriented cookbook; every snippet is
92
+ verified by `docs/_recipes_check.py`.
93
+ - [docs/operators_tutorial.md](docs/operators_tutorial.md) — the second-quantized
94
+ operator algebra, in depth.
95
+
96
+ [docs/README.md](docs/README.md) is the index.
97
+
98
+ ## Teaching notebooks
99
+
100
+ `notebooks/` derives valence-bond theory from the ground up with `symvb`; every
101
+ result is *derived*, not quoted. The four main notebooks are companions to the
102
+ manuscript's four model systems:
103
+
104
+ 1. **H₂, the two-center two-electron bond** — covalent/ionic weights versus
105
+ correlation, the singlet–triplet gap, and charge-shift bonding.
106
+ 2. **The allyl anion (3c4e)** — a long-bond Rumer structure as a biradical
107
+ signature.
108
+ 3. **The (H₂)₂⁺ disphenoid (4c3e)** — the Robin–Day Class II/III crossover.
109
+ 4. **Benzene** — a covalent-only model inverts the sign of the energy response.
110
+
111
+ `notebooks/additional/` keeps further topics (the U=J operator identity, the
112
+ Hubbard→Heisenberg mapping, symmetry projection). See
113
+ [notebooks/README.md](notebooks/README.md), and open in Jupyter with:
114
+
115
+ ```bash
116
+ PYTHONPATH=. jupyter notebook notebooks/
117
+ ```
118
+
119
+ ## Examples
120
+
121
+ `examples/` collects 80 stand-alone scripts, most of them cited from
122
+ the manuscript's source-data records. Worked examples cover H₂, H₂⁺,
123
+ allyl (anion / cation / triplet), benzene, (H₂)ₙ⁺ chains for
124
+ $n = 2, 3, 4$, cyclobutadiene dianion, cyclopentadienyl anion, F₂,
125
+ and benzene + O₃ aromaticity loss. Run any script from the repo root
126
+ with `PYTHONPATH=.`:
127
+
128
+ ```bash
129
+ PYTHONPATH=. python3 examples/benzene_heisenberg_mapping.py
130
+ ```
131
+
132
+ A few scripts cache large symbolic matrices under `/tmp` on first run
133
+ (subsequent runs are fast), and the plotting scripts write their PNGs
134
+ into `figures/`.
135
+
136
+ ## Tests
137
+
138
+ ```bash
139
+ PYTHONPATH=. python3 -m pytest symvb -q # 201 tests
140
+ PYTHONPATH=. python3 docs/_recipes_check.py # every documented recipe, executed
141
+ ```
142
+
143
+ ## License
144
+
145
+ MIT.
146
+
147
+ ## Funding
148
+
149
+ Research reported in this repository was supported by an
150
+ Institutional Development Award (IDeA) from the National Institute
151
+ of General Medical Sciences of the National Institutes of Health
152
+ under grant number P20GM103451.
symvb-2.0.0/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # symvb
2
+
3
+ Symbolic valence-bond theory in Python. `symvb` builds Slater
4
+ determinants over user-supplied orbital sets, computes one- and
5
+ two-electron matrix elements via Löwdin's cofactor expansion, and
6
+ returns the resulting Hamiltonian and overlap as `sympy` matrices —
7
+ everything stays symbolic in the bond, overlap, and Coulomb
8
+ parameters until you choose to substitute.
9
+
10
+ The package targets pedagogical and small-system research use:
11
+ H₂, allyl, benzene, (H₂)ₙ⁺ chains, cyclic polyenes, and similar
12
+ model systems where closed-form analysis is preferable to
13
+ purely numerical FCI.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install git+https://github.com/ComputationalChemistry-NMSU/symvb.git
19
+ ```
20
+
21
+ Or clone and run without installing:
22
+
23
+ ```bash
24
+ git clone https://github.com/ComputationalChemistry-NMSU/symvb.git
25
+ cd symvb
26
+ PYTHONPATH=. python3 examples/h2_hubbard_bond.py
27
+ ```
28
+
29
+ Python ≥ 3.8 (tested on 3.8 and 3.11). The symbolic core needs only
30
+ `sympy`; the numeric helpers (`ground_state(subs=...)`, the scan
31
+ patterns) and most examples also use `numpy` and `scipy`. For the
32
+ teaching notebooks add `jupyter` and `matplotlib`.
33
+
34
+ ## Quick start
35
+
36
+ ```python
37
+ from symvb import Molecule, FixedPsi, System
38
+
39
+ m = Molecule(zero_ii=True, interacting_orbs=['ab'],
40
+ subst={'h': ('H_ab',), 's': ('S_ab',)},
41
+ subst_2e={'U': ('1111',)}, max_2e_centers=1)
42
+ cov = FixedPsi('aB'); cov.add_str_det('bA', coef=1) # Heitler-London singlet
43
+ ion = FixedPsi('aA'); ion.add_str_det('bB', coef=1) # symmetric ionic
44
+
45
+ bond = System.from_structures(m, [cov, ion])
46
+ E, c = bond.ground_state() # symbolic ground-state energy + vector
47
+ w_cov, w_ion = bond.weights() # Chirgwin-Coulson weights
48
+
49
+ benzene = System.ring(6) # topology fills in every edge + on-site U
50
+ H, S = benzene.hamiltonian() # 400x400 sympy matrices, 2e block folded in (~1 min build)
51
+ ```
52
+
53
+ The underlying symbolic matrices stay fully accessible
54
+ (`m.build_matrix(P, op='H')`, `m.o2_matrix(P)`). See
55
+ [docs/recipes.md](docs/recipes.md) for common tasks and
56
+ [docs/api.md](docs/api.md) for the full surface.
57
+
58
+ ## Documentation
59
+
60
+ - [docs/api.md](docs/api.md) — API reference: modules, signatures, conventions.
61
+ - [docs/recipes.md](docs/recipes.md) — task-oriented cookbook; every snippet is
62
+ verified by `docs/_recipes_check.py`.
63
+ - [docs/operators_tutorial.md](docs/operators_tutorial.md) — the second-quantized
64
+ operator algebra, in depth.
65
+
66
+ [docs/README.md](docs/README.md) is the index.
67
+
68
+ ## Teaching notebooks
69
+
70
+ `notebooks/` derives valence-bond theory from the ground up with `symvb`; every
71
+ result is *derived*, not quoted. The four main notebooks are companions to the
72
+ manuscript's four model systems:
73
+
74
+ 1. **H₂, the two-center two-electron bond** — covalent/ionic weights versus
75
+ correlation, the singlet–triplet gap, and charge-shift bonding.
76
+ 2. **The allyl anion (3c4e)** — a long-bond Rumer structure as a biradical
77
+ signature.
78
+ 3. **The (H₂)₂⁺ disphenoid (4c3e)** — the Robin–Day Class II/III crossover.
79
+ 4. **Benzene** — a covalent-only model inverts the sign of the energy response.
80
+
81
+ `notebooks/additional/` keeps further topics (the U=J operator identity, the
82
+ Hubbard→Heisenberg mapping, symmetry projection). See
83
+ [notebooks/README.md](notebooks/README.md), and open in Jupyter with:
84
+
85
+ ```bash
86
+ PYTHONPATH=. jupyter notebook notebooks/
87
+ ```
88
+
89
+ ## Examples
90
+
91
+ `examples/` collects 80 stand-alone scripts, most of them cited from
92
+ the manuscript's source-data records. Worked examples cover H₂, H₂⁺,
93
+ allyl (anion / cation / triplet), benzene, (H₂)ₙ⁺ chains for
94
+ $n = 2, 3, 4$, cyclobutadiene dianion, cyclopentadienyl anion, F₂,
95
+ and benzene + O₃ aromaticity loss. Run any script from the repo root
96
+ with `PYTHONPATH=.`:
97
+
98
+ ```bash
99
+ PYTHONPATH=. python3 examples/benzene_heisenberg_mapping.py
100
+ ```
101
+
102
+ A few scripts cache large symbolic matrices under `/tmp` on first run
103
+ (subsequent runs are fast), and the plotting scripts write their PNGs
104
+ into `figures/`.
105
+
106
+ ## Tests
107
+
108
+ ```bash
109
+ PYTHONPATH=. python3 -m pytest symvb -q # 201 tests
110
+ PYTHONPATH=. python3 docs/_recipes_check.py # every documented recipe, executed
111
+ ```
112
+
113
+ ## License
114
+
115
+ MIT.
116
+
117
+ ## Funding
118
+
119
+ Research reported in this repository was supported by an
120
+ Institutional Development Award (IDeA) from the National Institute
121
+ of General Medical Sciences of the National Institutes of Health
122
+ under grant number P20GM103451.
symvb-2.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
symvb-2.0.0/setup.py ADDED
@@ -0,0 +1,44 @@
1
+ from setuptools import setup
2
+ import os
3
+
4
+
5
+ def get_long_description():
6
+ topdir = os.path.abspath(os.path.join(__file__, '..'))
7
+ with open(os.path.join(topdir, 'README.md'), 'r') as f:
8
+ return f.read()
9
+
10
+
11
+ def get_version():
12
+ topdir = os.path.abspath(os.path.join(__file__, '..'))
13
+ with open(os.path.join(topdir, 'symvb', '__init__.py'), 'r') as f:
14
+ for line in f.readlines():
15
+ if line.startswith('__version__'):
16
+ delim = '"' if '"' in line else "'"
17
+ return line.split(delim)[1]
18
+ raise ValueError("Version string not found")
19
+
20
+ VERSION = get_version()
21
+
22
+ setup(name='symvb',
23
+ version=VERSION,
24
+ description='Symbolic calculations for semi-quantitative Valence Bond Theory',
25
+ long_description=get_long_description(),
26
+ long_description_content_type='text/markdown',
27
+ url='https://github.com/ComputationalChemistry-NMSU/symvb',
28
+ author='Marat Talipov',
29
+ author_email='talipovm@nmsu.edu',
30
+ license='MIT',
31
+ license_files=['LICENSE'],
32
+ classifiers=[
33
+ 'Programming Language :: Python :: 3',
34
+ 'License :: OSI Approved :: MIT License',
35
+ 'Intended Audience :: Science/Research',
36
+ 'Topic :: Scientific/Engineering :: Chemistry',
37
+ ],
38
+ packages=['symvb'],
39
+ zip_safe=True,
40
+ python_requires='>=3.8',
41
+ # numpy/scipy are imported at module level by molecule, functions,
42
+ # numerical, symmetry, spin, operators, and mo_projection
43
+ install_requires=['sympy>=1.13', 'numpy>=1.24', 'scipy>=1.10'],
44
+ )
@@ -0,0 +1,18 @@
1
+ from symvb.slaterdet import SlaterDet
2
+ from symvb.fixed_psi import FixedPsi
3
+ from symvb.molecule import Molecule
4
+ from symvb import symmetry
5
+ from symvb import spin
6
+ from symvb import huckel
7
+ from symvb import mo_projection
8
+ from symvb import operators
9
+ from symvb import system
10
+ from symvb.system import (System, hamiltonian, ground_state,
11
+ chirgwin_coulson, structure_vector)
12
+ from symvb.mo_projection import verify_eigenpair, EigenpairResidualError
13
+
14
+ import logging
15
+
16
+ logging.basicConfig(format='%(levelname)-8s: %(message)s')
17
+
18
+ __version__ = "2.0.0"
@@ -0,0 +1,163 @@
1
+ """
2
+ Benchmark the two o2_det implementations on a fixed system battery.
3
+
4
+ Runs each (system, method) combination N_TRIALS times, reports the median
5
+ of wall-time and peak memory, plus the total SymPy-op count of the
6
+ resulting matrix as a proxy for output expression complexity.
7
+
8
+ Usage:
9
+ cd vbt-3-repo
10
+ PYTHONPATH=. python3 -m symvb._o2_benchmark
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import gc
15
+ import time
16
+ import tracemalloc
17
+
18
+ import sympy as sp
19
+
20
+ from symvb import Molecule
21
+
22
+
23
+ # --- Cases ---------------------------------------------------------------
24
+
25
+ _PPP_2E = {'U': ('1111',), 'J': ('1212',), 'K': ('1122',),
26
+ 'M': ('1112', '1121', '1222')}
27
+
28
+
29
+ def _h2(cutoff):
30
+ return dict(
31
+ label='H2',
32
+ Na=1, Nb=1, Norbs=2,
33
+ kwargs=dict(subst_2e=_PPP_2E,
34
+ interacting_orbs=['ab'],
35
+ max_2e_centers=cutoff),
36
+ )
37
+
38
+
39
+ def _allyl(cutoff):
40
+ return dict(
41
+ label='allyl-3c4e',
42
+ Na=2, Nb=2, Norbs=3,
43
+ kwargs=dict(subst_2e=_PPP_2E,
44
+ interacting_orbs=['ab', 'bc'],
45
+ max_2e_centers=cutoff),
46
+ )
47
+
48
+
49
+ def _benzene_ppp():
50
+ return dict(
51
+ label='benzene-PPP',
52
+ Na=3, Nb=3, Norbs=6,
53
+ kwargs=dict(
54
+ zero_ii=True,
55
+ interacting_orbs=['ab', 'bc', 'cd', 'de', 'ef', 'af'],
56
+ subst={'h': ('H_ab', 'H_bc', 'H_cd', 'H_de', 'H_ef', 'H_af'),
57
+ 's': ('S_ab', 'S_bc', 'S_cd', 'S_de', 'S_ef', 'S_af')},
58
+ subst_2e=_PPP_2E,
59
+ max_2e_centers=2,
60
+ ),
61
+ )
62
+
63
+
64
+ CASES = [
65
+ (_h2(cutoff=1), 5),
66
+ (_h2(cutoff=2), 5),
67
+ (_allyl(cutoff=1), 5),
68
+ (_allyl(cutoff=2), 5),
69
+ (_allyl(cutoff=3), 3),
70
+ (_allyl(cutoff=4), 3),
71
+ (_benzene_ppp(), 1), # 1 trial; if blocked is fast we can rerun with more
72
+ ]
73
+
74
+
75
+ # --- Bench runner --------------------------------------------------------
76
+
77
+ def _build_matrix_o2(method, case):
78
+ m = Molecule(o2_method=method, **case['kwargs'])
79
+ m.generate_basis(case['Na'], case['Nb'], case['Norbs'])
80
+ return m.o2_matrix(m.basis)
81
+
82
+
83
+ def _count_ops(matrix):
84
+ return sum(int(matrix[i, j].count_ops())
85
+ for i in range(matrix.rows) for j in range(matrix.cols))
86
+
87
+
88
+ def _trial(method, case):
89
+ gc.collect()
90
+ tracemalloc.start()
91
+ t0 = time.perf_counter()
92
+ H2 = _build_matrix_o2(method, case)
93
+ wall = time.perf_counter() - t0
94
+ _, peak = tracemalloc.get_traced_memory()
95
+ tracemalloc.stop()
96
+ ops = _count_ops(H2)
97
+ n = H2.rows
98
+ return dict(wall=wall, peak_mb=peak / (1024 * 1024), ops=ops, dim=n)
99
+
100
+
101
+ def _median(xs):
102
+ xs = sorted(xs)
103
+ n = len(xs)
104
+ if n == 0:
105
+ return float('nan')
106
+ if n % 2 == 1:
107
+ return xs[n // 2]
108
+ return 0.5 * (xs[n // 2 - 1] + xs[n // 2])
109
+
110
+
111
+ def benchmark():
112
+ print('=' * 78)
113
+ print('Two-electron matrix benchmark: direct vs blocked')
114
+ print('=' * 78)
115
+ print()
116
+ header = ('| %-15s | %-7s | %-7s | dim | wall (s) | peak (MB) '
117
+ '| ops | speedup |')
118
+ sep = ('|-----------------|---------|---------|-------'
119
+ '|------------|------------|----------|---------|')
120
+ print(header % ('system', 'cutoff', 'method'))
121
+ print(sep)
122
+ for case, n_trials in CASES:
123
+ cutoff = case['kwargs'].get('max_2e_centers', 4)
124
+ results = {}
125
+ for method in ('direct', 'blocked'):
126
+ print(' ... %s cutoff=%d %s (n=%d)'
127
+ % (case['label'], cutoff, method, n_trials), flush=True)
128
+ trials = []
129
+ for ti in range(n_trials):
130
+ t = _trial(method, case)
131
+ trials.append(t)
132
+ print(' trial %d: wall=%.3fs peak=%.1fMB'
133
+ % (ti, t['wall'], t['peak_mb']), flush=True)
134
+ results[method] = dict(
135
+ wall=_median([t['wall'] for t in trials]),
136
+ peak_mb=_median([t['peak_mb'] for t in trials]),
137
+ ops=trials[0]['ops'],
138
+ dim=trials[0]['dim'],
139
+ )
140
+ # Print rows; speedup column shown on the blocked row only.
141
+ for method in ('direct', 'blocked'):
142
+ r = results[method]
143
+ speedup = ''
144
+ if method == 'blocked' and results['direct']['wall'] > 0:
145
+ speedup = '%.2fx' % (results['direct']['wall'] / r['wall'])
146
+ print('| %-15s | %-7d | %-7s | %-5d | %-10.3f | %-10.2f '
147
+ '| %-8d | %-7s |'
148
+ % (case['label'], cutoff, method, r['dim'],
149
+ r['wall'], r['peak_mb'], r['ops'], speedup))
150
+ # Sanity: ops should agree (modulo chemist-symmetry symbol naming).
151
+ ops_diff = results['direct']['ops'] - results['blocked']['ops']
152
+ if ops_diff != 0:
153
+ print('| ^ ops differ by %+d (chemist-symbol naming, not '
154
+ 'a correctness issue)' % ops_diff)
155
+ print()
156
+ print('Notes:')
157
+ print(' - wall and peak_mb are medians across N_TRIALS runs.')
158
+ print(' - ops = sum of sympy.count_ops() over all matrix entries.')
159
+ print(' - speedup > 1 means blocked is faster.')
160
+
161
+
162
+ if __name__ == '__main__':
163
+ benchmark()