qc-PyCI 0.6.3__tar.gz → 1.0.2__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.
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.github/workflows/build_wheels.yml +42 -9
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/CONTRIBUTORS +1 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/Makefile +4 -0
- {qc_pyci-0.6.3/qc_PyCI.egg-info → qc_pyci-1.0.2}/PKG-INFO +24 -3
- qc_pyci-1.0.2/README.md +52 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/__init__.py +2 -0
- qc_pyci-1.0.2/pyci/_pyci.so +0 -0
- qc_pyci-1.0.2/pyci/_pyci.so.0 +0 -0
- qc_pyci-1.0.2/pyci/_pyci.so.0.6.1 +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/include/pyci.h +1 -1
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/common.cpp +22 -21
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/enpt2.cpp +34 -45
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/hci.cpp +26 -23
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/rdm.cpp +126 -7
- qc_pyci-1.0.2/pyci/test/conftest.py +22 -0
- qc_pyci-1.0.2/pyci/test/data/BH3.fcidump +792 -0
- qc_pyci-1.0.2/pyci/test/data/h8_fcidump.fcidump +693 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/test_routines.py +175 -15
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/utility.py +184 -47
- {qc_pyci-0.6.3 → qc_pyci-1.0.2/qc_PyCI.egg-info}/PKG-INFO +24 -3
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/qc_PyCI.egg-info/SOURCES.txt +20 -1
- qc_pyci-1.0.2/qc_PyCI.egg-info/scm_file_list.json +129 -0
- qc_pyci-1.0.2/qc_PyCI.egg-info/scm_version.json +8 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/setup.py +1 -3
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/website/_config.yml +3 -3
- qc_pyci-1.0.2/website/intro.html +498 -0
- qc_pyci-1.0.2/website/intro.md +45 -0
- qc_pyci-1.0.2/website/intro_files/libs/bootstrap/bootstrap-9e3ffae467580fdb927a41352e75a2e0.min.css +12 -0
- qc_pyci-1.0.2/website/intro_files/libs/bootstrap/bootstrap-icons.css +2106 -0
- qc_pyci-1.0.2/website/intro_files/libs/bootstrap/bootstrap-icons.woff +0 -0
- qc_pyci-1.0.2/website/intro_files/libs/bootstrap/bootstrap.min.js +7 -0
- qc_pyci-1.0.2/website/intro_files/libs/clipboard/clipboard.min.js +7 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/anchor.min.js +9 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/axe/axe-check.js +145 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/popper.min.js +6 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/quarto-syntax-highlighting-7b89279ff1a6dce999919e0e67d4d9ec.css +236 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/quarto.js +847 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/tabsets/tabsets.js +95 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/tippy.css +1 -0
- qc_pyci-1.0.2/website/intro_files/libs/quarto-html/tippy.umd.min.js +2 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/website/requirements.txt +1 -1
- qc_pyci-0.6.3/README.md +0 -32
- qc_pyci-0.6.3/pyci/_pyci.so +0 -0
- qc_pyci-0.6.3/pyci/_pyci.so.0 +0 -0
- qc_pyci-0.6.3/pyci/_pyci.so.0.6.1 +0 -0
- qc_pyci-0.6.3/website/intro.md +0 -25
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.clang-format +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.github/workflows/pypi_release.yaml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.github/workflows/python-app.yml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.github/workflows/website.yml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.gitignore +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.pre-commit-config.yaml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/.travis.yml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/LICENSE +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/MANIFEST.in +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/build_wrapper.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/doc/Makefile +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/doc/source/api.rst +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/doc/source/conf.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/doc/source/index.rst +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/notebooks/fanci_tutorial.ipynb +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/notebooks/pyci_tutorial.ipynb +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/cost_ci.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/excitation_ci.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/__init__.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/ap1rog.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/apig.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/detratio.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/fanci.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/pccds.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/__init__.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/be_ccpvdz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/h2_hf_631gdp.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/h2_hf_sto6g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/he_ccpvqz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/li2_631g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/li2_ccpvdz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/lih_631g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/data/lih_hf_sto6g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/derivcheck.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/test_ap1rog.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/test_apig.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/test_detratio.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/test_objective_fanci.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/fanci/test/test_pccds.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/gkci.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/include/SpookyV2.h +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/include/sort_with_arg.h +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/rdm/__init__.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/rdm/algorithms.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/rdm/conditions.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/rdm/constraints.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/rdm/tools.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/seniority_ci.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/SpookyV2.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/ap1rog.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/apig.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/binding.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/dociwfn.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/fanci.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/fullciwfn.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/genciwfn.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/onespinwfn.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/overlap.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/sparseop.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/squantop.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/twospinwfn.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/src/wfn.cpp +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/__init__.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/BH_sto-3g_eq.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/be_ccpvdz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/be_ccpvdz_spinres.npz +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h10_chain_1.4_STO-6G.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h2_631gdp.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h2_sto3g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h2o_ccpvdz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h2o_ccpvdz_spinres.npz +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h4_sto3g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/h6_sto_3g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/he_ccpvqz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/he_ccpvqz_spinres.npz +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/li2_ccpvdz.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/li2_ccpvdz_spinres.npz +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/data/lih_sto6g.fcidump +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/test_hamiltonian.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/test_odometer.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyci/test/test_wavefunction.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/pyproject.toml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/qc_PyCI.egg-info/dependency_links.txt +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/qc_PyCI.egg-info/requires.txt +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/qc_PyCI.egg-info/top_level.txt +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/setup.cfg +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/tools/conda.recipe/meta.yaml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/tools/python_include_dirs.py +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/tools/setup-clangd +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/tools/wheels/cibw_before_build_linux.sh +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/website/_toc.yml +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/website/favicon.png +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/website/install.rst +0 -0
- {qc_pyci-0.6.3 → qc_pyci-1.0.2}/website/logo.png +0 -0
|
@@ -140,7 +140,7 @@ jobs:
|
|
|
140
140
|
- name: Build wheels
|
|
141
141
|
uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3
|
|
142
142
|
env:
|
|
143
|
-
CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}
|
|
143
|
+
CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}_${{ matrix.buildplat[2] }}
|
|
144
144
|
CIBW_ARCHS: ${{ matrix.buildplat[2] }}
|
|
145
145
|
CIBW_PRERELEASE_PYTHONS: True
|
|
146
146
|
CIBW_FREE_THREADED_SUPPORT: True
|
|
@@ -157,9 +157,14 @@ jobs:
|
|
|
157
157
|
mv ./wheelhouse/*.whl $(find ./wheelhouse -type f -name '*.whl' | sed 's/13_0/14_0/')
|
|
158
158
|
fi
|
|
159
159
|
|
|
160
|
+
- name: Check wheelhouse contents
|
|
161
|
+
run: |
|
|
162
|
+
echo "Contents of wheelhouse:"
|
|
163
|
+
ls -l wheelhouse/
|
|
164
|
+
|
|
160
165
|
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
|
161
166
|
with:
|
|
162
|
-
path: wheelhouse
|
|
167
|
+
path: ./wheelhouse/*.whl
|
|
163
168
|
name: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}
|
|
164
169
|
${{ matrix.buildplat[2] }} ${{ matrix.buildplat[3] }}
|
|
165
170
|
${{ matrix.buildplat[4] }}
|
|
@@ -172,20 +177,48 @@ jobs:
|
|
|
172
177
|
- build_wheels
|
|
173
178
|
runs-on: ubuntu-latest
|
|
174
179
|
environment:
|
|
175
|
-
name:
|
|
180
|
+
name: pypi-release
|
|
176
181
|
url: https://pypi.org/project/${{ env.PYPI_NAME }}
|
|
177
182
|
permissions:
|
|
178
183
|
id-token: write
|
|
179
184
|
|
|
180
185
|
steps:
|
|
181
|
-
- name: Download
|
|
186
|
+
- name: Download all the dists
|
|
182
187
|
uses: actions/download-artifact@v4
|
|
183
188
|
with:
|
|
184
|
-
path: dist
|
|
185
|
-
merge-multiple: true
|
|
189
|
+
path: dist/
|
|
190
|
+
merge-multiple: true # Merge all artifacts into the dist/ directory
|
|
191
|
+
|
|
192
|
+
- name: Check dist contents
|
|
193
|
+
run: |
|
|
194
|
+
echo "Contents of dist:"
|
|
195
|
+
ls -l dist/
|
|
186
196
|
|
|
187
197
|
- name: Publish distribution to PyPI
|
|
188
198
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
199
|
+
with:
|
|
200
|
+
verbose: true
|
|
201
|
+
|
|
202
|
+
# - name: Upload to PyPI
|
|
203
|
+
# env:
|
|
204
|
+
# TWINE_USERNAME: "__token__"
|
|
205
|
+
# TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
206
|
+
# run: |
|
|
207
|
+
# if [ "$(ls -A wheelhouse)" ]; then
|
|
208
|
+
# python -m pip install --upgrade twine
|
|
209
|
+
# python -m twine upload --repository-url https://upload.pypi.org/legacy/ wheelhouse/*
|
|
210
|
+
# else
|
|
211
|
+
# echo "No wheel files to upload"
|
|
212
|
+
# fi
|
|
213
|
+
|
|
214
|
+
# - name: Upload to TestPyPI
|
|
215
|
+
# env:
|
|
216
|
+
# TWINE_USERNAME: "__token__"
|
|
217
|
+
# TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN }}
|
|
218
|
+
# run: |
|
|
219
|
+
# if [ "$(ls -A wheelhouse)" ]; then
|
|
220
|
+
# python -m pip install --upgrade twine
|
|
221
|
+
# python -m twine upload --repository-url https://test.pypi.org/legacy/ wheelhouse/*
|
|
222
|
+
# else
|
|
223
|
+
# echo "No wheel files to upload"
|
|
224
|
+
# fi
|
|
@@ -76,6 +76,10 @@ all: pyci/_pyci.so.$(PYCI_VERSION) pyci/_pyci.so.$(VERSION_MAJOR) pyci/_pyci.so
|
|
|
76
76
|
test:
|
|
77
77
|
@set -e; $(PYTHON) -m pytest -sv ./pyci
|
|
78
78
|
|
|
79
|
+
.PHONY: test-bigmem
|
|
80
|
+
test-bigmem:
|
|
81
|
+
@set -e; $(PYTHON) -m pytest -sv ./pyci --bigmem
|
|
82
|
+
|
|
79
83
|
.PHONY: clean
|
|
80
84
|
clean:
|
|
81
85
|
rm -rf pyci/src/*.o pyci/_pyci.so*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: qc-PyCI
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: PyCI: A flexible quantum chemistry CI library for Python 3.
|
|
5
5
|
Author-email: QC-Devs Community <qcdevs@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -709,6 +709,7 @@ Provides-Extra: doc
|
|
|
709
709
|
Requires-Dist: sphinx; extra == "doc"
|
|
710
710
|
Requires-Dist: nbsphinx; extra == "doc"
|
|
711
711
|
Requires-Dist: sphinx_rtd_theme; extra == "doc"
|
|
712
|
+
Dynamic: license-file
|
|
712
713
|
|
|
713
714
|
<!--
|
|
714
715
|
This file is part of PyCI.
|
|
@@ -741,4 +742,24 @@ tutorials and the API reference.
|
|
|
741
742
|
|
|
742
743
|
## Citing PyCI
|
|
743
744
|
|
|
744
|
-
See the
|
|
745
|
+
See the [publication](https://pubs.aip.org/aip/jcp/article/161/13/132502/3315366/PyCI-A-Python-scriptable-library-for-arbitrary).
|
|
746
|
+
|
|
747
|
+
> Michelle Richer, Gabriela Sánchez-Díaz, Marco Martínez-González, Valerii Chuiko, Taewon David Kim, Alireza Tehrani, Shuoyang Wang, Pratiksha B. Gaikwad, Carlos E. V. de Moura, Cassandra Masschelein, Ramón Alain Miranda-Quintana, Augusto Gerolin, Farnaz Heidar-Zadeh, Paul W. Ayers; "PyCI: A Python-scriptable library for arbitrary determinant CI." *J. Chem. Phys.* **161**: 132502 (2024).
|
|
748
|
+
> https://doi.org/10.1063/5.0219010
|
|
749
|
+
|
|
750
|
+
```
|
|
751
|
+
@article{pyci2024,
|
|
752
|
+
author = {Richer, Michelle and Sánchez-Díaz, Gabriela and Martínez-González, Marco and Chuiko, Valerii and Kim, Taewon David and Tehrani, Alireza and Wang, Shuoyang and Gaikwad, Pratiksha B. and de Moura, Carlos E. V. and Masschelein, Cassandra and Miranda-Quintana, Ramón Alain and Gerolin, Augusto and Heidar-Zadeh, Farnaz and Ayers, Paul W.},
|
|
753
|
+
title = {PyCI: A Python-scriptable library for arbitrary determinant CI},
|
|
754
|
+
journal = {The Journal of Chemical Physics},
|
|
755
|
+
volume = {161},
|
|
756
|
+
number = {13},
|
|
757
|
+
pages = {132502},
|
|
758
|
+
year = {2024},
|
|
759
|
+
month = {10},
|
|
760
|
+
issn = {0021-9606},
|
|
761
|
+
doi = {10.1063/5.0219010},
|
|
762
|
+
url = {https://doi.org/10.1063/5.0219010},
|
|
763
|
+
eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/5.0219010/20192959/132502_1_5.0219010.pdf},
|
|
764
|
+
}
|
|
765
|
+
```
|
qc_pyci-1.0.2/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
This file is part of PyCI.
|
|
3
|
+
|
|
4
|
+
PyCI is free software: you can redistribute it and/or modify it under
|
|
5
|
+
the terms of the GNU General Public License as published by the Free
|
|
6
|
+
Software Foundation, either version 3 of the License, or (at your
|
|
7
|
+
option) any later version.
|
|
8
|
+
|
|
9
|
+
PyCI is distributed in the hope that it will be useful, but WITHOUT
|
|
10
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11
|
+
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12
|
+
for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with PyCI. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
-->
|
|
17
|
+
|
|
18
|
+
[](https://docs.python.org/3.8/)
|
|
19
|
+
|
|
20
|
+
# PyCI
|
|
21
|
+
|
|
22
|
+
PyCI is a flexible quantum chemistry Configuration Interaction library for Python 3.
|
|
23
|
+
|
|
24
|
+
PyCI is distributed under the GNU General Public License version 3 (GPLv3).
|
|
25
|
+
See http://www.gnu.org/licenses/ for more information.
|
|
26
|
+
|
|
27
|
+
See http://pyci.qcdevs.org/ for up-to-date installation and usage instructions, as well as for
|
|
28
|
+
tutorials and the API reference.
|
|
29
|
+
|
|
30
|
+
## Citing PyCI
|
|
31
|
+
|
|
32
|
+
See the [publication](https://pubs.aip.org/aip/jcp/article/161/13/132502/3315366/PyCI-A-Python-scriptable-library-for-arbitrary).
|
|
33
|
+
|
|
34
|
+
> Michelle Richer, Gabriela Sánchez-Díaz, Marco Martínez-González, Valerii Chuiko, Taewon David Kim, Alireza Tehrani, Shuoyang Wang, Pratiksha B. Gaikwad, Carlos E. V. de Moura, Cassandra Masschelein, Ramón Alain Miranda-Quintana, Augusto Gerolin, Farnaz Heidar-Zadeh, Paul W. Ayers; "PyCI: A Python-scriptable library for arbitrary determinant CI." *J. Chem. Phys.* **161**: 132502 (2024).
|
|
35
|
+
> https://doi.org/10.1063/5.0219010
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
@article{pyci2024,
|
|
39
|
+
author = {Richer, Michelle and Sánchez-Díaz, Gabriela and Martínez-González, Marco and Chuiko, Valerii and Kim, Taewon David and Tehrani, Alireza and Wang, Shuoyang and Gaikwad, Pratiksha B. and de Moura, Carlos E. V. and Masschelein, Cassandra and Miranda-Quintana, Ramón Alain and Gerolin, Augusto and Heidar-Zadeh, Farnaz and Ayers, Paul W.},
|
|
40
|
+
title = {PyCI: A Python-scriptable library for arbitrary determinant CI},
|
|
41
|
+
journal = {The Journal of Chemical Physics},
|
|
42
|
+
volume = {161},
|
|
43
|
+
number = {13},
|
|
44
|
+
pages = {132502},
|
|
45
|
+
year = {2024},
|
|
46
|
+
month = {10},
|
|
47
|
+
issn = {0021-9606},
|
|
48
|
+
doi = {10.1063/5.0219010},
|
|
49
|
+
url = {https://doi.org/10.1063/5.0219010},
|
|
50
|
+
eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/5.0219010/20192959/132502_1_5.0219010.pdf},
|
|
51
|
+
}
|
|
52
|
+
```
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -221,7 +221,7 @@ void clearbit_det(const long, ulong *);
|
|
|
221
221
|
|
|
222
222
|
void compute_rdms(const DOCIWfn &, const double *, double *, double *);
|
|
223
223
|
|
|
224
|
-
void compute_rdms_1234(const DOCIWfn &, const double *, double *, double *, double *, double *);
|
|
224
|
+
void compute_rdms_1234(const DOCIWfn &, const double *, double *, double *, double *, double *, double *, double *, double *);
|
|
225
225
|
|
|
226
226
|
void compute_rdms(const FullCIWfn &, const double *, double *, double *);
|
|
227
227
|
|
|
@@ -30,7 +30,7 @@ long get_num_threads(void) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
long end_chunk_idx(const long thread_idx, const long num_threads, const long sideLength) {
|
|
33
|
-
return ceil(
|
|
33
|
+
return ceil(static_cast<double>(thread_idx) / static_cast<double>(num_threads) * sideLength);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
void set_num_threads(const long n) {
|
|
@@ -152,6 +152,14 @@ void unrank_colex(long nbasis, const long nocc, long rank, long *occs) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
inline ulong mask_above(long n) {
|
|
156
|
+
return (n >= Size<ulong>() - 1) ? 0UL : ~( (1UL << (n + 1)) - 1 );
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
inline ulong mask_below(long m) {
|
|
160
|
+
return (m >= Size<ulong>()) ? Max<ulong>() : (1UL << m) - 1;
|
|
161
|
+
}
|
|
162
|
+
|
|
155
163
|
long phase_single_det(const long nword, const long i, const long a, const ulong *det) {
|
|
156
164
|
(void)nword; // nword is deliberately unused.
|
|
157
165
|
long j, k, l, m, n, high, low, nperm = 0;
|
|
@@ -168,21 +176,18 @@ long phase_single_det(const long nword, const long i, const long a, const ulong
|
|
|
168
176
|
j = low / Size<ulong>();
|
|
169
177
|
n = low % Size<ulong>();
|
|
170
178
|
mask = det[j];
|
|
171
|
-
mask &= Max<ulong>();
|
|
172
179
|
if (j == k) {
|
|
173
|
-
mask &= (
|
|
174
|
-
mask &=
|
|
180
|
+
mask &= mask_below(m);
|
|
181
|
+
mask &= mask_above(n);
|
|
175
182
|
nperm += Pop(mask);
|
|
176
183
|
} else {
|
|
177
|
-
mask &=
|
|
184
|
+
mask &= mask_above(n);
|
|
178
185
|
nperm += Pop(mask);
|
|
179
186
|
mask = det[k];
|
|
180
|
-
mask &= (
|
|
187
|
+
mask &= mask_below(m);
|
|
181
188
|
nperm += Pop(mask);
|
|
182
189
|
for (l = j + 1; l < k; ++l) {
|
|
183
|
-
|
|
184
|
-
mask &= Max<ulong>();
|
|
185
|
-
nperm += Pop(mask);
|
|
190
|
+
nperm += Pop(det[l]);
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
return (nperm % 2) ? -1 : 1;
|
|
@@ -206,20 +211,18 @@ long phase_double_det(const long nword, const long i1, const long i2, const long
|
|
|
206
211
|
j = low / Size<ulong>();
|
|
207
212
|
n = low % Size<ulong>();
|
|
208
213
|
mask = det[j];
|
|
209
|
-
mask &= Max<ulong>();
|
|
210
214
|
if (j == k) {
|
|
211
|
-
mask &= (
|
|
212
|
-
mask &=
|
|
215
|
+
mask &= mask_below(m);
|
|
216
|
+
mask &= mask_above(n);
|
|
213
217
|
nperm += Pop(mask);
|
|
214
218
|
} else {
|
|
215
|
-
mask &=
|
|
219
|
+
mask &= mask_above(n);
|
|
216
220
|
nperm += Pop(mask);
|
|
217
221
|
mask = det[k];
|
|
218
|
-
mask &= (
|
|
222
|
+
mask &= mask_below(m);
|
|
219
223
|
nperm += Pop(mask);
|
|
220
224
|
for (l = j + 1; l < k; ++l) {
|
|
221
225
|
mask = det[l];
|
|
222
|
-
mask &= Max<ulong>();
|
|
223
226
|
nperm += Pop(mask);
|
|
224
227
|
}
|
|
225
228
|
}
|
|
@@ -236,20 +239,18 @@ long phase_double_det(const long nword, const long i1, const long i2, const long
|
|
|
236
239
|
j = low / Size<ulong>();
|
|
237
240
|
n = low % Size<ulong>();
|
|
238
241
|
mask = det[j];
|
|
239
|
-
mask &= Max<ulong>();
|
|
240
242
|
if (j == k) {
|
|
241
|
-
mask &= (
|
|
242
|
-
mask &=
|
|
243
|
+
mask &= mask_below(m);
|
|
244
|
+
mask &= mask_above(n);
|
|
243
245
|
nperm += Pop(mask);
|
|
244
246
|
} else {
|
|
245
|
-
mask &=
|
|
247
|
+
mask &= mask_above(n);
|
|
246
248
|
nperm += Pop(mask);
|
|
247
249
|
mask = det[k];
|
|
248
|
-
mask &= (
|
|
250
|
+
mask &= mask_below(m);
|
|
249
251
|
nperm += Pop(mask);
|
|
250
252
|
for (l = j + 1; l < k; ++l) {
|
|
251
253
|
mask = det[l];
|
|
252
|
-
mask &= Max<ulong>();
|
|
253
254
|
nperm += Pop(mask);
|
|
254
255
|
}
|
|
255
256
|
}
|
|
@@ -82,6 +82,7 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
82
82
|
long n2 = n1 * n1;
|
|
83
83
|
long n3 = n1 * n2;
|
|
84
84
|
double val;
|
|
85
|
+
double eps_i = eps / std::abs(coeffs[idet]);
|
|
85
86
|
const ulong *rdet_up = wfn.det_ptr(idet);
|
|
86
87
|
const ulong *rdet_dn = rdet_up + wfn.nword;
|
|
87
88
|
ulong *det_dn = det_up + wfn.nword;
|
|
@@ -104,6 +105,7 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
104
105
|
jj = virs_up[j];
|
|
105
106
|
// 1-0 excitation elements
|
|
106
107
|
excite_det(ii, jj, det_up);
|
|
108
|
+
fill_occs(wfn.nword, det_up, t_up);
|
|
107
109
|
sign_up = phase_single_det(wfn.nword, ii, jj, rdet_up);
|
|
108
110
|
val = ham.one_mo[n1 * ii + jj];
|
|
109
111
|
for (k = 0; k < wfn.nocc_up; ++k) {
|
|
@@ -115,13 +117,11 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
115
117
|
kk = occs_dn[k];
|
|
116
118
|
val += ham.two_mo[ioffset + n2 * kk + n1 * jj + kk];
|
|
117
119
|
}
|
|
118
|
-
val *= coeffs[idet];
|
|
119
120
|
// add determinant if |H*c| > eps and not already in wfn
|
|
120
|
-
if (std::abs(val) >
|
|
121
|
+
if (std::abs(val) > eps_i) {
|
|
121
122
|
rank = wfn.rank_det(det_up);
|
|
122
123
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
123
|
-
val *= sign_up;
|
|
124
|
-
fill_occs(wfn.nword, det_up, t_up);
|
|
124
|
+
val *= sign_up * coeffs[idet];
|
|
125
125
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank], val, n2,
|
|
126
126
|
n3, t_up);
|
|
127
127
|
}
|
|
@@ -134,19 +134,19 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
134
134
|
for (l = 0; l < wfn.nvir_dn; ++l) {
|
|
135
135
|
ll = virs_dn[l];
|
|
136
136
|
// 1-1 excitation elements
|
|
137
|
-
|
|
138
|
-
val
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
val = ham.two_mo[koffset + n1 * jj + ll];
|
|
138
|
+
if (std::abs(val) > eps_i) {
|
|
139
|
+
excite_det(kk, ll, det_dn);
|
|
140
|
+
// add determinant if |H*c| > eps and not already in wfn
|
|
141
141
|
rank = wfn.rank_det(det_up);
|
|
142
142
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
143
|
-
val *= sign_up * phase_single_det(wfn.nword, kk, ll, rdet_dn);
|
|
143
|
+
val *= sign_up * phase_single_det(wfn.nword, kk, ll, rdet_dn) * coeffs[idet];
|
|
144
144
|
fill_occs(wfn.nword, det_dn, t_dn);
|
|
145
145
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank],
|
|
146
146
|
val, n2, n3, t_up);
|
|
147
147
|
}
|
|
148
|
+
excite_det(ll, kk, det_dn);
|
|
148
149
|
}
|
|
149
|
-
excite_det(ll, kk, det_dn);
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
std::memcpy(t_dn, occs_dn, sizeof(long) * wfn.nocc_dn);
|
|
@@ -158,21 +158,19 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
158
158
|
for (l = j + 1; l < wfn.nvir_up; ++l) {
|
|
159
159
|
ll = virs_up[l];
|
|
160
160
|
// 2-0 excitation elements
|
|
161
|
-
|
|
162
|
-
val
|
|
163
|
-
(
|
|
164
|
-
|
|
165
|
-
// add determinant if |H*c| > eps and not already in wfn
|
|
166
|
-
if (std::abs(val) > eps) {
|
|
161
|
+
val = ham.two_mo[koffset + n1 * jj + ll] - ham.two_mo[koffset + n1 * ll + jj];
|
|
162
|
+
if (std::abs(val) > eps_i) {
|
|
163
|
+
excite_det(kk, ll, det_up);
|
|
164
|
+
// add determinant if |H*c| > eps and not already in wfn
|
|
167
165
|
rank = wfn.rank_det(det_up);
|
|
168
166
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
169
|
-
val *= phase_double_det(wfn.nword, ii, kk, jj, ll, rdet_up);
|
|
167
|
+
val *= phase_double_det(wfn.nword, ii, kk, jj, ll, rdet_up) * coeffs[idet];
|
|
170
168
|
fill_occs(wfn.nword, det_up, t_up);
|
|
171
169
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank],
|
|
172
170
|
val, n2, n3, t_up);
|
|
173
171
|
}
|
|
172
|
+
excite_det(ll, kk, det_up);
|
|
174
173
|
}
|
|
175
|
-
excite_det(ll, kk, det_up);
|
|
176
174
|
}
|
|
177
175
|
}
|
|
178
176
|
excite_det(jj, ii, det_up);
|
|
@@ -198,12 +196,11 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
198
196
|
koffset = ioffset + n2 * kk;
|
|
199
197
|
val += ham.two_mo[koffset + n1 * jj + kk] - ham.two_mo[koffset + n1 * kk + jj];
|
|
200
198
|
}
|
|
201
|
-
val *= coeffs[idet];
|
|
202
199
|
// add determinant if |H*c| > eps and not already in wfn
|
|
203
|
-
if (std::abs(val) >
|
|
200
|
+
if (std::abs(val) > eps_i) {
|
|
204
201
|
rank = wfn.rank_det(det_up);
|
|
205
202
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
206
|
-
val *= phase_single_det(wfn.nword, ii, jj, rdet_dn);
|
|
203
|
+
val *= phase_single_det(wfn.nword, ii, jj, rdet_dn) * coeffs[idet];
|
|
207
204
|
fill_occs(wfn.nword, det_dn, t_dn);
|
|
208
205
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank], val, n2,
|
|
209
206
|
n3, t_up);
|
|
@@ -217,21 +214,19 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const FullCIWfn &wfn, PairH
|
|
|
217
214
|
for (l = j + 1; l < wfn.nvir_dn; ++l) {
|
|
218
215
|
ll = virs_dn[l];
|
|
219
216
|
// 0-2 excitation elements
|
|
220
|
-
|
|
221
|
-
val
|
|
222
|
-
(
|
|
223
|
-
|
|
224
|
-
// add determinant if |H*c| > eps and not already in wfn
|
|
225
|
-
if (std::abs(val) > eps) {
|
|
217
|
+
val = ham.two_mo[koffset + n1 * jj + ll] - ham.two_mo[koffset + n1 * ll + jj];
|
|
218
|
+
if (std::abs(val) > eps_i) {
|
|
219
|
+
excite_det(kk, ll, det_dn);
|
|
220
|
+
// add determinant if |H*c| > eps and not already in wfn
|
|
226
221
|
rank = wfn.rank_det(det_up);
|
|
227
222
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
228
|
-
val *= phase_double_det(wfn.nword, ii, kk, jj, ll, rdet_dn);
|
|
223
|
+
val *= phase_double_det(wfn.nword, ii, kk, jj, ll, rdet_dn) * coeffs[idet];
|
|
229
224
|
fill_occs(wfn.nword, det_dn, t_dn);
|
|
230
225
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank],
|
|
231
226
|
val, n2, n3, t_up);
|
|
232
227
|
}
|
|
228
|
+
excite_det(ll, kk, det_dn);
|
|
233
229
|
}
|
|
234
|
-
excite_det(ll, kk, det_dn);
|
|
235
230
|
}
|
|
236
231
|
}
|
|
237
232
|
excite_det(jj, ii, det_dn);
|
|
@@ -270,6 +265,7 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const GenCIWfn &wfn, PairHa
|
|
|
270
265
|
long n2 = n1 * n1;
|
|
271
266
|
long n3 = n1 * n2;
|
|
272
267
|
double val;
|
|
268
|
+
double eps_i = eps / std::abs(coeffs[idet]);
|
|
273
269
|
const ulong *rdet = wfn.det_ptr(idet);
|
|
274
270
|
std::memcpy(det, rdet, sizeof(ulong) * wfn.nword);
|
|
275
271
|
fill_occs(wfn.nword, rdet, occs);
|
|
@@ -290,12 +286,11 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const GenCIWfn &wfn, PairHa
|
|
|
290
286
|
koffset = ioffset + n2 * kk;
|
|
291
287
|
val += ham.two_mo[koffset + n1 * jj + kk] - ham.two_mo[koffset + n1 * kk + jj];
|
|
292
288
|
}
|
|
293
|
-
val *= coeffs[idet];
|
|
294
289
|
// add determinant if |H*c| > eps and not already in wfn
|
|
295
|
-
if (std::abs(val) >
|
|
290
|
+
if (std::abs(val) > eps_i) {
|
|
296
291
|
rank = wfn.rank_det(det);
|
|
297
292
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
298
|
-
val *= phase_single_det(wfn.nword, ii, jj, rdet);
|
|
293
|
+
val *= phase_single_det(wfn.nword, ii, jj, rdet) * coeffs[idet];
|
|
299
294
|
fill_occs(wfn.nword, det, tmps);
|
|
300
295
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank], val, n2,
|
|
301
296
|
n3, tmps);
|
|
@@ -309,21 +304,19 @@ void compute_enpt2_thread_terms(const SQuantOp &ham, const GenCIWfn &wfn, PairHa
|
|
|
309
304
|
for (l = j + 1; l < wfn.nvir; ++l) {
|
|
310
305
|
ll = virs[l];
|
|
311
306
|
// double excitation elements
|
|
312
|
-
|
|
313
|
-
val =
|
|
314
|
-
(ham.two_mo[koffset + n1 * jj + ll] - ham.two_mo[koffset + n1 * ll + jj]) *
|
|
315
|
-
coeffs[idet];
|
|
307
|
+
val = ham.two_mo[koffset + n1 * jj + ll] - ham.two_mo[koffset + n1 * ll + jj];
|
|
316
308
|
// add determinant if |H*c| > eps and not already in wfn
|
|
317
|
-
if (std::abs(val) >
|
|
309
|
+
if (std::abs(val) > eps_i) {
|
|
310
|
+
excite_det(kk, ll, det);
|
|
318
311
|
rank = wfn.rank_det(det);
|
|
319
312
|
if (wfn.index_det_from_rank(rank) == -1) {
|
|
320
|
-
val *= phase_double_det(wfn.nword, ii, kk, jj, ll, rdet);
|
|
313
|
+
val *= phase_double_det(wfn.nword, ii, kk, jj, ll, rdet) * coeffs[idet];
|
|
321
314
|
fill_occs(wfn.nword, det, tmps);
|
|
322
315
|
compute_enpt2_thread_gather(wfn, ham.one_mo, ham.two_mo, terms[rank],
|
|
323
316
|
val, n2, n3, tmps);
|
|
324
317
|
}
|
|
318
|
+
excite_det(ll, kk, det);
|
|
325
319
|
}
|
|
326
|
-
excite_det(ll, kk, det);
|
|
327
320
|
}
|
|
328
321
|
}
|
|
329
322
|
excite_det(jj, ii, det);
|
|
@@ -367,12 +360,8 @@ double compute_enpt2(const SQuantOp &ham, const WfnType &wfn, const double *coef
|
|
|
367
360
|
v_threads.emplace_back(&compute_enpt2_thread<WfnType>, std::ref(ham), std::ref(wfn),
|
|
368
361
|
std::ref(v_terms[i]), coeffs, eps, start, end);
|
|
369
362
|
}
|
|
370
|
-
|
|
371
|
-
for (
|
|
372
|
-
thread.join();
|
|
373
|
-
compute_enpt2_thread_condense(terms, v_terms[n], n);
|
|
374
|
-
++n;
|
|
375
|
-
}
|
|
363
|
+
for (auto &thread : v_threads) thread.join();
|
|
364
|
+
for (long n=0; n<nthread; n++) compute_enpt2_thread_condense(terms, v_terms[n], n);
|
|
376
365
|
// compute enpt2 correction
|
|
377
366
|
double e = energy - ham.ecore, correction = 0.0;
|
|
378
367
|
for (const auto &keyval : terms)
|