sft-wick 0.2.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.
- sft_wick-0.2.0/.github/workflows/ci.yml +75 -0
- sft_wick-0.2.0/.github/workflows/publish.yml +138 -0
- sft_wick-0.2.0/.gitignore +21 -0
- sft_wick-0.2.0/.readthedocs.yaml +17 -0
- sft_wick-0.2.0/.zenodo.json +28 -0
- sft_wick-0.2.0/CHANGELOG.md +262 -0
- sft_wick-0.2.0/CITATION.cff +47 -0
- sft_wick-0.2.0/LICENSE +13 -0
- sft_wick-0.2.0/PKG-INFO +603 -0
- sft_wick-0.2.0/README.md +551 -0
- sft_wick-0.2.0/docs/Makefile +19 -0
- sft_wick-0.2.0/docs/_static/diagrams/_generate.py +251 -0
- sft_wick-0.2.0/docs/_static/diagrams/custom_labels.png +0 -0
- sft_wick-0.2.0/docs/_static/diagrams/example.tex +18 -0
- sft_wick-0.2.0/docs/_static/diagrams/manual_positions.png +0 -0
- sft_wick-0.2.0/docs/_static/diagrams/order2_grayscale.png +0 -0
- sft_wick-0.2.0/docs/_static/diagrams/order2_publication.png +0 -0
- sft_wick-0.2.0/docs/_static/diagrams/presets.png +0 -0
- sft_wick-0.2.0/docs/api/action.rst +8 -0
- sft_wick-0.2.0/docs/api/diagrams.rst +8 -0
- sft_wick-0.2.0/docs/api/drawing.rst +8 -0
- sft_wick-0.2.0/docs/api/drawing_tikz.rst +8 -0
- sft_wick-0.2.0/docs/api/evaluate.rst +8 -0
- sft_wick-0.2.0/docs/api/expressions.rst +27 -0
- sft_wick-0.2.0/docs/api/fields.rst +8 -0
- sft_wick-0.2.0/docs/api/index.rst +38 -0
- sft_wick-0.2.0/docs/api/indices.rst +8 -0
- sft_wick-0.2.0/docs/api/latex.rst +8 -0
- sft_wick-0.2.0/docs/api/perturbation.rst +8 -0
- sft_wick-0.2.0/docs/api/propagators.rst +8 -0
- sft_wick-0.2.0/docs/api/render_style.rst +28 -0
- sft_wick-0.2.0/docs/api/simplify.rst +8 -0
- sft_wick-0.2.0/docs/api/util.rst +8 -0
- sft_wick-0.2.0/docs/api/vertices.rst +8 -0
- sft_wick-0.2.0/docs/api/wick.rst +8 -0
- sft_wick-0.2.0/docs/api/workflow.rst +67 -0
- sft_wick-0.2.0/docs/changelog.rst +65 -0
- sft_wick-0.2.0/docs/conf.py +89 -0
- sft_wick-0.2.0/docs/contributing.rst +196 -0
- sft_wick-0.2.0/docs/deductive_verification.md +493 -0
- sft_wick-0.2.0/docs/examples/advanced.rst +247 -0
- sft_wick-0.2.0/docs/examples/first_order.rst +90 -0
- sft_wick-0.2.0/docs/examples/index.rst +15 -0
- sft_wick-0.2.0/docs/examples/multicomponent.rst +75 -0
- sft_wick-0.2.0/docs/examples/nonlocal_vertex.rst +80 -0
- sft_wick-0.2.0/docs/examples/notebook.rst +9 -0
- sft_wick-0.2.0/docs/examples/notebook_rendered.ipynb +280 -0
- sft_wick-0.2.0/docs/examples/zeroth_order.rst +99 -0
- sft_wick-0.2.0/docs/getting_started.rst +224 -0
- sft_wick-0.2.0/docs/index.rst +150 -0
- sft_wick-0.2.0/docs/installation.rst +97 -0
- sft_wick-0.2.0/docs/make.bat +35 -0
- sft_wick-0.2.0/docs/notes/R_contracted_nonlocal_vertex.md +277 -0
- sft_wick-0.2.0/docs/notes/equal_time_nonlocal_vertex.md +234 -0
- sft_wick-0.2.0/docs/requirements.txt +13 -0
- sft_wick-0.2.0/docs/theory/feynman_diagrams.rst +130 -0
- sft_wick-0.2.0/docs/theory/index.rst +17 -0
- sft_wick-0.2.0/docs/theory/msr_formalism.rst +174 -0
- sft_wick-0.2.0/docs/theory/wick_theorem.rst +126 -0
- sft_wick-0.2.0/docs/user_guide/diagrams.rst +356 -0
- sft_wick-0.2.0/docs/user_guide/discretization.rst +140 -0
- sft_wick-0.2.0/docs/user_guide/expressions.rst +175 -0
- sft_wick-0.2.0/docs/user_guide/fields.rst +95 -0
- sft_wick-0.2.0/docs/user_guide/index.rst +24 -0
- sft_wick-0.2.0/docs/user_guide/latex_output.rst +118 -0
- sft_wick-0.2.0/docs/user_guide/parallelism.rst +91 -0
- sft_wick-0.2.0/docs/user_guide/perturbative_expansion.rst +231 -0
- sft_wick-0.2.0/docs/user_guide/simplification.rst +140 -0
- sft_wick-0.2.0/docs/user_guide/vertices_and_actions.rst +183 -0
- sft_wick-0.2.0/docs/user_guide/workflow.rst +1155 -0
- sft_wick-0.2.0/docs/verification/index.rst +339 -0
- sft_wick-0.2.0/examples/demo1/L2/config.yaml +122 -0
- sft_wick-0.2.0/examples/demo1/L2/reproduce_figures.py +727 -0
- sft_wick-0.2.0/examples/demo1/c_closed_form.py +91 -0
- sft_wick-0.2.0/examples/demo1/run_simulation.py +269 -0
- sft_wick-0.2.0/examples/demo1/validate_R_C_derivation.py +217 -0
- sft_wick-0.2.0/examples/demo1/validate_phase5.py +317 -0
- sft_wick-0.2.0/examples/demo1/validate_wrapper.py +196 -0
- sft_wick-0.2.0/examples/demo1_config.yaml +72 -0
- sft_wick-0.2.0/examples/demo2/L2/c_closed_form.py +72 -0
- sft_wick-0.2.0/examples/demo2/L2/config_FF.yaml +79 -0
- sft_wick-0.2.0/examples/demo2/L2/config_FK.yaml +87 -0
- sft_wick-0.2.0/examples/demo2/L2/reproduce_figures.py +433 -0
- sft_wick-0.2.0/examples/demo2/k3_coupling.py +98 -0
- sft_wick-0.2.0/examples/demo2/run_simulation.py +270 -0
- sft_wick-0.2.0/examples/demo2/validate_FK_dynamic.py +200 -0
- sft_wick-0.2.0/examples/demo2/validate_wrapper_demo2.py +460 -0
- sft_wick-0.2.0/examples/demo2_config.yaml +97 -0
- sft_wick-0.2.0/examples/demo_workflow.py +195 -0
- sft_wick-0.2.0/pyproject.toml +79 -0
- sft_wick-0.2.0/src/sft_wick/__init__.py +191 -0
- sft_wick-0.2.0/src/sft_wick/_util.py +17 -0
- sft_wick-0.2.0/src/sft_wick/action.py +52 -0
- sft_wick-0.2.0/src/sft_wick/diagrams.py +378 -0
- sft_wick-0.2.0/src/sft_wick/drawing.py +883 -0
- sft_wick-0.2.0/src/sft_wick/drawing_tikz.py +497 -0
- sft_wick-0.2.0/src/sft_wick/evaluate.py +3982 -0
- sft_wick-0.2.0/src/sft_wick/expressions.py +530 -0
- sft_wick-0.2.0/src/sft_wick/fields.py +125 -0
- sft_wick-0.2.0/src/sft_wick/indices.py +30 -0
- sft_wick-0.2.0/src/sft_wick/latex.py +72 -0
- sft_wick-0.2.0/src/sft_wick/perturbation.py +2421 -0
- sft_wick-0.2.0/src/sft_wick/propagators.py +74 -0
- sft_wick-0.2.0/src/sft_wick/render_labels.py +166 -0
- sft_wick-0.2.0/src/sft_wick/render_layout.py +319 -0
- sft_wick-0.2.0/src/sft_wick/render_style.py +429 -0
- sft_wick-0.2.0/src/sft_wick/simplify.py +1106 -0
- sft_wick-0.2.0/src/sft_wick/vertices.py +217 -0
- sft_wick-0.2.0/src/sft_wick/wick.py +690 -0
- sft_wick-0.2.0/src/sft_wick/workflow/__init__.py +93 -0
- sft_wick-0.2.0/src/sft_wick/workflow/cache.py +120 -0
- sft_wick-0.2.0/src/sft_wick/workflow/cli.py +187 -0
- sft_wick-0.2.0/src/sft_wick/workflow/config.py +964 -0
- sft_wick-0.2.0/src/sft_wick/workflow/expansion.py +493 -0
- sft_wick-0.2.0/src/sft_wick/workflow/propagators.py +298 -0
- sft_wick-0.2.0/src/sft_wick/workflow/r_contracted.py +177 -0
- sft_wick-0.2.0/src/sft_wick/workflow/result.py +204 -0
- sft_wick-0.2.0/src/sft_wick/workflow/specs.py +768 -0
- sft_wick-0.2.0/src/sft_wick/workflow/system.py +495 -0
- sft_wick-0.2.0/tests/__init__.py +0 -0
- sft_wick-0.2.0/tests/brute_wick.py +397 -0
- sft_wick-0.2.0/tests/perf/__init__.py +0 -0
- sft_wick-0.2.0/tests/perf/_compare_paths.py +138 -0
- sft_wick-0.2.0/tests/perf/test_dynamic_coupling_perf.py +149 -0
- sft_wick-0.2.0/tests/test_R_contracted_vertex.py +749 -0
- sft_wick-0.2.0/tests/test_c_propagator_gauss_legendre.py +339 -0
- sft_wick-0.2.0/tests/test_d_dim_spatial.py +220 -0
- sft_wick-0.2.0/tests/test_deductive_expansion.py +1577 -0
- sft_wick-0.2.0/tests/test_deductive_numerics.py +2263 -0
- sft_wick-0.2.0/tests/test_diag_C_offdiagonal.py +279 -0
- sft_wick-0.2.0/tests/test_diagonal_A_time_dependent.py +164 -0
- sft_wick-0.2.0/tests/test_diagrams.py +216 -0
- sft_wick-0.2.0/tests/test_drawing_style.py +554 -0
- sft_wick-0.2.0/tests/test_drawing_tikz.py +258 -0
- sft_wick-0.2.0/tests/test_dt_discretization.py +112 -0
- sft_wick-0.2.0/tests/test_dynamic_coupling.py +542 -0
- sft_wick-0.2.0/tests/test_equal_time_nonlocal.py +453 -0
- sft_wick-0.2.0/tests/test_eval_symbolic_batched.py +301 -0
- sft_wick-0.2.0/tests/test_evaluate_interpolation_accuracy.py +153 -0
- sft_wick-0.2.0/tests/test_evaluate_pipeline.py +169 -0
- sft_wick-0.2.0/tests/test_expressions.py +168 -0
- sft_wick-0.2.0/tests/test_fields.py +69 -0
- sft_wick-0.2.0/tests/test_gauss_legendre_integrator.py +277 -0
- sft_wick-0.2.0/tests/test_matrix_r_evaluation.py +46 -0
- sft_wick-0.2.0/tests/test_perturbation.py +540 -0
- sft_wick-0.2.0/tests/test_propagators.py +119 -0
- sft_wick-0.2.0/tests/test_simplify.py +587 -0
- sft_wick-0.2.0/tests/test_wick.py +309 -0
- sft_wick-0.2.0/tests/test_workflow.py +267 -0
- sft_wick-0.2.0/tests/test_workflow_config.py +1241 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
# Cancel superseded runs on the same ref (e.g. rapid pushes to a PR).
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
name: Tests (Python ${{ matrix.python-version }})
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
python-version: ['3.10', '3.11', '3.12']
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
cache: pip
|
|
33
|
+
cache-dependency-path: pyproject.toml
|
|
34
|
+
|
|
35
|
+
- name: Install package with dev extras
|
|
36
|
+
run: |
|
|
37
|
+
python -m pip install --upgrade pip
|
|
38
|
+
pip install -e ".[dev]"
|
|
39
|
+
|
|
40
|
+
- name: Run test suite
|
|
41
|
+
run: pytest tests/ -v
|
|
42
|
+
|
|
43
|
+
build:
|
|
44
|
+
name: Build & check distribution
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Set up Python
|
|
50
|
+
uses: actions/setup-python@v5
|
|
51
|
+
with:
|
|
52
|
+
python-version: '3.12'
|
|
53
|
+
|
|
54
|
+
- name: Install build tooling
|
|
55
|
+
run: python -m pip install --upgrade pip build twine
|
|
56
|
+
|
|
57
|
+
- name: Build sdist and wheel
|
|
58
|
+
run: python -m build
|
|
59
|
+
|
|
60
|
+
- name: Validate distribution metadata
|
|
61
|
+
run: twine check --strict dist/*
|
|
62
|
+
|
|
63
|
+
- name: Smoke-test the built wheel in a clean venv
|
|
64
|
+
run: |
|
|
65
|
+
python -m venv /tmp/smoke
|
|
66
|
+
/tmp/smoke/bin/pip install --upgrade pip
|
|
67
|
+
/tmp/smoke/bin/pip install dist/*.whl
|
|
68
|
+
/tmp/smoke/bin/python -c "from sft_wick import compute_moment; print('import OK')"
|
|
69
|
+
/tmp/smoke/bin/sft-wick --help
|
|
70
|
+
|
|
71
|
+
- name: Upload distribution artifacts
|
|
72
|
+
uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: dist-ci
|
|
75
|
+
path: dist/
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
# Release pipeline using PyPI Trusted Publishing (OIDC) — no API tokens
|
|
4
|
+
# or stored secrets.
|
|
5
|
+
#
|
|
6
|
+
# * Push a `vX.Y.Z` tag -> run tests + build the distribution
|
|
7
|
+
# (validation dry run; nothing is published).
|
|
8
|
+
# * Publish a GitHub Release -> run tests, build, publish to PyPI, then
|
|
9
|
+
# sign the artifacts with Sigstore and
|
|
10
|
+
# attach them to the release.
|
|
11
|
+
#
|
|
12
|
+
# Recommended flow:
|
|
13
|
+
# 1. git tag v0.2.0 && git push origin v0.2.0 # validates the build
|
|
14
|
+
# 2. once the tag run is green, create a GitHub Release *from the existing
|
|
15
|
+
# tag* # -> publishes to PyPI
|
|
16
|
+
on:
|
|
17
|
+
push:
|
|
18
|
+
tags:
|
|
19
|
+
- 'v*'
|
|
20
|
+
release:
|
|
21
|
+
types: [published]
|
|
22
|
+
|
|
23
|
+
# Serialize runs for a given ref so a tag push and a release of the same
|
|
24
|
+
# version never race. Never cancel an in-flight publish — queue instead.
|
|
25
|
+
concurrency:
|
|
26
|
+
group: publish-${{ github.ref }}
|
|
27
|
+
cancel-in-progress: false
|
|
28
|
+
|
|
29
|
+
permissions:
|
|
30
|
+
contents: read
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
test:
|
|
34
|
+
name: Run tests
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- name: Set up Python
|
|
40
|
+
uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: '3.12'
|
|
43
|
+
cache: pip
|
|
44
|
+
cache-dependency-path: pyproject.toml
|
|
45
|
+
|
|
46
|
+
- name: Install package with dev extras
|
|
47
|
+
run: |
|
|
48
|
+
python -m pip install --upgrade pip
|
|
49
|
+
pip install -e ".[dev]"
|
|
50
|
+
|
|
51
|
+
- name: Run test suite
|
|
52
|
+
run: pytest tests/ -v
|
|
53
|
+
|
|
54
|
+
build:
|
|
55
|
+
name: Build & validate distribution
|
|
56
|
+
needs: test
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
|
|
61
|
+
- name: Set up Python
|
|
62
|
+
uses: actions/setup-python@v5
|
|
63
|
+
with:
|
|
64
|
+
python-version: '3.12'
|
|
65
|
+
|
|
66
|
+
- name: Install build tooling
|
|
67
|
+
run: python -m pip install --upgrade pip build twine
|
|
68
|
+
|
|
69
|
+
- name: Build sdist and wheel
|
|
70
|
+
run: python -m build
|
|
71
|
+
|
|
72
|
+
- name: Validate distribution metadata
|
|
73
|
+
run: twine check --strict dist/*
|
|
74
|
+
|
|
75
|
+
- name: Upload distribution artifacts
|
|
76
|
+
uses: actions/upload-artifact@v4
|
|
77
|
+
with:
|
|
78
|
+
name: dist
|
|
79
|
+
path: dist/
|
|
80
|
+
|
|
81
|
+
publish-pypi:
|
|
82
|
+
name: Publish to PyPI
|
|
83
|
+
# Only when a GitHub Release is published. A plain tag push runs just
|
|
84
|
+
# `test` + `build` above (a validation dry run) and stops here.
|
|
85
|
+
if: github.event_name == 'release'
|
|
86
|
+
needs: build
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
environment:
|
|
89
|
+
name: pypi
|
|
90
|
+
url: https://pypi.org/p/sft-wick
|
|
91
|
+
permissions:
|
|
92
|
+
id-token: write # mandatory for Trusted Publishing (OIDC)
|
|
93
|
+
steps:
|
|
94
|
+
- name: Download distribution artifacts
|
|
95
|
+
uses: actions/download-artifact@v4
|
|
96
|
+
with:
|
|
97
|
+
name: dist
|
|
98
|
+
path: dist/
|
|
99
|
+
|
|
100
|
+
- name: Publish to PyPI
|
|
101
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
102
|
+
|
|
103
|
+
github-release:
|
|
104
|
+
name: Sign artifacts and attach to the GitHub Release
|
|
105
|
+
if: github.event_name == 'release'
|
|
106
|
+
needs: publish-pypi
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
permissions:
|
|
109
|
+
contents: write # to upload assets to the release
|
|
110
|
+
id-token: write # to mint the Sigstore signing certificate
|
|
111
|
+
steps:
|
|
112
|
+
- name: Download distribution artifacts
|
|
113
|
+
uses: actions/download-artifact@v4
|
|
114
|
+
with:
|
|
115
|
+
name: dist
|
|
116
|
+
path: dist/
|
|
117
|
+
|
|
118
|
+
- name: Sign the distribution with Sigstore
|
|
119
|
+
uses: sigstore/gh-action-sigstore-python@v3.0.0
|
|
120
|
+
with:
|
|
121
|
+
inputs: >-
|
|
122
|
+
./dist/*.tar.gz
|
|
123
|
+
./dist/*.whl
|
|
124
|
+
|
|
125
|
+
- name: Upload signed artifacts to the GitHub Release
|
|
126
|
+
# Pass the tag through an env var rather than interpolating it
|
|
127
|
+
# directly into the shell, to avoid any script-injection risk.
|
|
128
|
+
env:
|
|
129
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
130
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
131
|
+
# `--clobber` keeps the step idempotent if a later re-run re-uploads
|
|
132
|
+
# assets; `dist/*` (not `dist/**`) is an explicit flat-glob of the
|
|
133
|
+
# sdist, wheel, and their Sigstore `*.sigstore.json` bundles.
|
|
134
|
+
run: >-
|
|
135
|
+
gh release upload "$RELEASE_TAG"
|
|
136
|
+
dist/*
|
|
137
|
+
--repo "${{ github.repository }}"
|
|
138
|
+
--clobber
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.pytest_cache/
|
|
2
|
+
.ruff_cache/
|
|
3
|
+
.mypy_cache/
|
|
4
|
+
*cache/
|
|
5
|
+
.benchmarks/
|
|
6
|
+
__pycache__/
|
|
7
|
+
**/__pycache__/
|
|
8
|
+
*.pyc
|
|
9
|
+
.ipynb_checkpoints/
|
|
10
|
+
.claude/
|
|
11
|
+
CLAUDE.md
|
|
12
|
+
HANDOFF*
|
|
13
|
+
paper/
|
|
14
|
+
archived/
|
|
15
|
+
|
|
16
|
+
# Build / generated artifacts
|
|
17
|
+
.DS_Store
|
|
18
|
+
docs/_build/
|
|
19
|
+
examples/demo_workflow_plot.png
|
|
20
|
+
examples/demo1/__pycache__/
|
|
21
|
+
examples/demo2/__pycache__/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "sft-wick: Feynman diagrammatic expansion and evaluation for statistical field theory",
|
|
3
|
+
"description": "<p><strong>If you use this software, please cite the accompanying paper:</strong> Z. Zhang, <em>sft-wick: A formalism and package for Feynman-diagram expansion and evaluation in stochastic field theories</em>, arXiv:2606.19480 (2026), <a href=\"https://arxiv.org/abs/2606.19480\">https://arxiv.org/abs/2606.19480</a>. This Zenodo record archives the software; the paper is the primary reference.</p> An open-source Python package that constructs diagram tables and computes their integrals numerically for stochastic field dynamics cast into a path-integral (Martin-Siggia-Rose) formulation. Given an action and an observable, it enumerates topologically distinct Feynman diagrams, derives their algebraic coefficients, and evaluates the resulting diagram integrals from user-supplied response and cumulant functions. The core algorithm enumerates spatial topologies before routing component indices, avoiding contraction-by-contraction Wick expansion; response-field constraints (vanishing response-response contractions, the Ito prescription, absence of causal response loops) are enforced during enumeration.",
|
|
4
|
+
"upload_type": "software",
|
|
5
|
+
"license": "BSD-3-Clause",
|
|
6
|
+
"access_right": "open",
|
|
7
|
+
"creators": [
|
|
8
|
+
{
|
|
9
|
+
"name": "Zhang, Zheng",
|
|
10
|
+
"orcid": "0000-0002-9154-2803"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"statistical field theory",
|
|
15
|
+
"Wick's theorem",
|
|
16
|
+
"Feynman diagrams",
|
|
17
|
+
"Martin-Siggia-Rose formalism",
|
|
18
|
+
"perturbation theory",
|
|
19
|
+
"symbolic computation"
|
|
20
|
+
],
|
|
21
|
+
"related_identifiers": [
|
|
22
|
+
{
|
|
23
|
+
"identifier": "arXiv:2606.19480",
|
|
24
|
+
"relation": "isSupplementTo",
|
|
25
|
+
"scheme": "arxiv"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 — 2026-07-25
|
|
4
|
+
|
|
5
|
+
First release on PyPI (`pip install sft-wick`).
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **`NonLocalVertex(equal_time=True)`** — opt-in mode for non-local
|
|
10
|
+
vertices whose `coupling` callable encodes an **equal-shell** /
|
|
11
|
+
**equal-time** connected cumulant (one common cosmology use case:
|
|
12
|
+
`canoes.sachs.compute_kappa3_zeta_table` which returns the
|
|
13
|
+
equal-shell bispectrum `ζ_eq(γ_12, γ_23, γ_31; λ)` for the LSS
|
|
14
|
+
matter / potential 3-point function).
|
|
15
|
+
|
|
16
|
+
When `equal_time=True`, the `m` time legs of that vertex collapse
|
|
17
|
+
into a **single** integration variable while the `m` spatial legs
|
|
18
|
+
remain independent (so the callable still receives `m` distinct
|
|
19
|
+
positions and only one shared time replicated `m` times in
|
|
20
|
+
`t_list`). This matches the action-level relation
|
|
21
|
+
`κ^(m)(z_1,...,z_m) ≈ δ(λ_1−λ_2) … δ(λ_{m−1}−λ_m) · κ_eq(n_1,...,n_m; λ)`
|
|
22
|
+
used in single-shell / Limber-like cosmological approximations.
|
|
23
|
+
|
|
24
|
+
The default `equal_time=False` is unchanged — the full
|
|
25
|
+
cross-spacetime cumulant `κ^(m)(z_1,...,z_m)` with `m` independent
|
|
26
|
+
`(n, λ)` integrations is still the canonical contract.
|
|
27
|
+
|
|
28
|
+
Failure mode this guards against: passing an equal-shell ζ as
|
|
29
|
+
`coupling` without `equal_time=True` lets sft-wick faithfully
|
|
30
|
+
sweep `m` independent times, contributing a spurious `(t_max)^(m−1)`
|
|
31
|
+
factor of integration measure (e.g. `~5.6×10^6` for `m=3` and
|
|
32
|
+
`t_max=2360` Mpc). This was the diagnosis-of-record for the
|
|
33
|
+
STF_lensing path-integral lensing Order-2 FK ⟨κκ⟩ bug.
|
|
34
|
+
|
|
35
|
+
Implementation spans `workflow/specs.py`, `workflow/system.py`,
|
|
36
|
+
`workflow/config.py`, `vertices.py`, `perturbation.py`, and
|
|
37
|
+
`evaluate.py`. Threaded through as
|
|
38
|
+
`Vertex(equal_time=...)` → `VertexInstance.equal_time_aliases` →
|
|
39
|
+
`DiagramTerm.equal_time_aliases` →
|
|
40
|
+
`SpatialStructure.equal_time_aliases`, with time-alias resolution
|
|
41
|
+
in `_times` of the QMC + Gauss-Legendre paths and in
|
|
42
|
+
`DiagramIntegrand.evaluate`. Diagram topology (R / C propagator
|
|
43
|
+
routing, direction groups) is unchanged — only the time-integration
|
|
44
|
+
Jacobian and the callable's `t_list` payload differ.
|
|
45
|
+
|
|
46
|
+
YAML usage::
|
|
47
|
+
|
|
48
|
+
nonlocal_vertices:
|
|
49
|
+
- name: K
|
|
50
|
+
order: 3
|
|
51
|
+
coupling_module: kappa3_callable.py
|
|
52
|
+
coupling_attr: coupling_fn
|
|
53
|
+
equal_time: true
|
|
54
|
+
|
|
55
|
+
See `docs/user_guide/workflow.rst` for the full discussion and
|
|
56
|
+
`docs/notes/equal_time_nonlocal_vertex.md` for the design note.
|
|
57
|
+
Regression coverage: `tests/test_equal_time_nonlocal.py`
|
|
58
|
+
(11 tests covering alias plumbing, static evaluation, dynamic
|
|
59
|
+
callables, and Jacobian ratio).
|
|
60
|
+
|
|
61
|
+
- **`NonLocalVertex(already_R_contracted=True)`** — opt-in mode where
|
|
62
|
+
the user-supplied callable returns the **R-contracted** form
|
|
63
|
+
`κ^(m)_R(γ; z_1', …, z_m') := ∫ ∏ R(z_i', z_i) · κ^(m) dz_1…dz_m`
|
|
64
|
+
evaluated at the **partner** (outer) spacetime points rather than
|
|
65
|
+
the κ's own legs. When set, sft-wick
|
|
66
|
+
|
|
67
|
+
* tags the m R-propagators attached to this vertex's ψ legs as
|
|
68
|
+
**absorbed** — they remain in the diagram graph (so direction
|
|
69
|
+
groups continue to identify the leg with its partner) but
|
|
70
|
+
contribute a factor of 1 instead of the usual `R_time` value;
|
|
71
|
+
* aliases each leg's time onto its Wick partner's time via the
|
|
72
|
+
existing `equal_time_aliases` machinery, so the m leg-time
|
|
73
|
+
integration variables drop out of the simplex;
|
|
74
|
+
* feeds the callable `(n_list, t_list)` with the **partner**
|
|
75
|
+
coordinates instead of the leg's own.
|
|
76
|
+
|
|
77
|
+
Cuts integration dimensionality by `m` per such vertex (e.g. an
|
|
78
|
+
order-2 F+K diagram becomes 1-D after absorbing K's 3 legs). The
|
|
79
|
+
surviving integrand is also **smoother** because the narrow-kernel
|
|
80
|
+
peak has been folded into κ^(m)_R, so Gauss-Legendre converges
|
|
81
|
+
exponentially with far fewer nodes. Motivating use case: canoes'
|
|
82
|
+
squeezed κ³ at `ℓ_max = 5000, z_s = 1100`, where the raw kernel
|
|
83
|
+
has diagonal width `Δχ ~ 2 Mpc/h` and the per-leg χ-integration
|
|
84
|
+
would otherwise demand `~10^11` quadrature points.
|
|
85
|
+
|
|
86
|
+
Mutually exclusive with `equal_time=True` (rejected at
|
|
87
|
+
construction). Default `already_R_contracted=False` is unchanged.
|
|
88
|
+
|
|
89
|
+
Implementation spans `workflow/specs.py`, `workflow/system.py`,
|
|
90
|
+
`workflow/config.py`, `vertices.py`, `perturbation.py`, and
|
|
91
|
+
`evaluate.py`. Threaded through as
|
|
92
|
+
`Vertex(already_R_contracted=...)` →
|
|
93
|
+
`DiagramTerm.r_absorbed_pairs` (collected per-routing in
|
|
94
|
+
`_collect_r_absorbed_pairs`, merged into `equal_time_aliases`) →
|
|
95
|
+
`SpatialStructure.r_absorbed_pairs`, with R-factor skipping
|
|
96
|
+
centralised in `evaluate.py::_kept_r_propagators` (used by all
|
|
97
|
+
five R-product sites: scalar / matrix per-sample, QMC-vectorised,
|
|
98
|
+
GL tensor-product, integrate-over external).
|
|
99
|
+
|
|
100
|
+
YAML usage::
|
|
101
|
+
|
|
102
|
+
nonlocal_vertices:
|
|
103
|
+
- name: K
|
|
104
|
+
order: 3
|
|
105
|
+
coupling_module: kappa3_R_callable.py
|
|
106
|
+
coupling_attr: coupling_fn
|
|
107
|
+
already_R_contracted: true
|
|
108
|
+
|
|
109
|
+
Companion utility `sft_wick.build_R_contracted_callable` wraps a
|
|
110
|
+
raw κ^(m) + R kernel into the R-contracted form via brute-force
|
|
111
|
+
trapezoid quadrature on a user χ-grid — for validation comparand
|
|
112
|
+
use; production callers should supply the analytical / pre-
|
|
113
|
+
tabulated κ^(m)_R directly (e.g. canoes' FFTlog-of-W chain).
|
|
114
|
+
|
|
115
|
+
See `docs/user_guide/workflow.rst` and
|
|
116
|
+
`docs/notes/R_contracted_nonlocal_vertex.md` for full
|
|
117
|
+
documentation. Regression coverage:
|
|
118
|
+
`tests/test_R_contracted_vertex.py` (15 tests including the
|
|
119
|
+
machine-precision constant-κ³ equivalence at `rtol=1e-12` and the
|
|
120
|
+
four-way per-sample × vectorised contract check).
|
|
121
|
+
|
|
122
|
+
### Performance
|
|
123
|
+
|
|
124
|
+
- **Test-suite wall time cut ~3.5×** (from ~18 min to ~5 min for the
|
|
125
|
+
full 275-test suite on M-series). The profile showed two tests
|
|
126
|
+
accounting for 80 % of runtime — both were building expensive
|
|
127
|
+
C-propagator caches that the test's tolerance did not actually
|
|
128
|
+
require:
|
|
129
|
+
- `test_CF3_full_run_matches_L1_reference` (585 s → 72 s): this is
|
|
130
|
+
an equivalence test (YAML pipeline vs. direct Python — rtol=1e-10
|
|
131
|
+
is bit-identity), so the propagator grid only needs internal
|
|
132
|
+
consistency, not physical precision. `n_grid_t` 30 → 12,
|
|
133
|
+
`t_max` 3.0 → 2.0, `n_samples` 1024 → 256.
|
|
134
|
+
- `test_T4_time_dependent_gamma_end_to_end` (302 s → 24 s): an
|
|
135
|
+
order-0 smoke test whose single C-evaluation did not justify a
|
|
136
|
+
30² dblquad grid. `n_grid_t` 30 → 10, `n_grid_cache` 120 → 40,
|
|
137
|
+
`t_max` 2.0 → 1.5.
|
|
138
|
+
- `test_W3_white_noise_absorbed_into_translation_spline`
|
|
139
|
+
(97 s → 32 s): lazy-spline cache cost dominated — `n_grid_t`
|
|
140
|
+
25 → 15 (quadratic win); `n_samples` 2¹³ → 2¹¹ (negligible since
|
|
141
|
+
QMC is not the bottleneck here).
|
|
142
|
+
- `test_spline_matches_split_dblquad` (77 s → 54 s):
|
|
143
|
+
`n_grid` 30 → 25 with worst-case-O(h⁴) tolerance relaxed from
|
|
144
|
+
2e-3 → 3e-3 (still within 2× the theoretical bound).
|
|
145
|
+
- `test_WF4_end_to_end_matches_validate_phase5` (44 s → 18 s): the
|
|
146
|
+
sweep covered 4 × 2 grid points but the reference values only
|
|
147
|
+
pinned 3 × 1 of them — dropped `y=2.5` and `t_final=1.0`.
|
|
148
|
+
|
|
149
|
+
- **`integrate_diagrams` default `n_jobs` flipped from `1` to `-1`.**
|
|
150
|
+
The guard `len(diagram_terms) <= 2 → sequential fallback` already
|
|
151
|
+
prevents joblib's ~1 s startup from dominating on trivial batches,
|
|
152
|
+
so the new default is a free speedup for any order-2+ batch
|
|
153
|
+
evaluation. Explicit `n_jobs=1` callers (determinism-comparison
|
|
154
|
+
tests like C5) are unaffected.
|
|
155
|
+
|
|
156
|
+
### Cleanups
|
|
157
|
+
|
|
158
|
+
- Removed **dead `System.explicit_C` field** (declared but never read
|
|
159
|
+
anywhere in the codebase; replaced by the `c_closed_form` kwarg on
|
|
160
|
+
`System.propagators()` and `Propagators.build()`). Docstring for
|
|
161
|
+
`System.explicit_R` now points to `ExplicitR` as the preferred
|
|
162
|
+
structured alternative.
|
|
163
|
+
- Removed 10 unused imports flagged by ruff F401 across
|
|
164
|
+
`diagrams.py`, `drawing.py`, `evaluate.py`, `perturbation.py`,
|
|
165
|
+
`vertices.py`, `workflow/expansion.py`, `workflow/result.py`,
|
|
166
|
+
`workflow/specs.py`.
|
|
167
|
+
- Removed 3 orphaned local assignments flagged by F841
|
|
168
|
+
(`evaluate.py:ids`, `perturbation.py:sum_idx_dims`,
|
|
169
|
+
`simplify.py:ref_flipped`).
|
|
170
|
+
|
|
171
|
+
### Features
|
|
172
|
+
|
|
173
|
+
- **Time-dependent linear operator** (`workflow/specs.py::DiagonalA`).
|
|
174
|
+
`gamma` may now be a callable ``γ(t) -> np.ndarray(shape=(N,))``;
|
|
175
|
+
the wrapper pre-computes ``Γ_a(t) = ∫_0^t γ_a(τ) dτ`` on a grid
|
|
176
|
+
and caches it as a cubic spline for O(1) R lookups. Diagonal
|
|
177
|
+
case only — full-matrix time-dependent A still requires
|
|
178
|
+
`ExplicitR` with a user-supplied time-ordered matrix exponential.
|
|
179
|
+
New tests in `tests/test_diagonal_A_time_dependent.py`.
|
|
180
|
+
|
|
181
|
+
- **Dynamic coupling evaluation for non-local vertices**
|
|
182
|
+
(`evaluate.py::DynamicCouplingPromise` +
|
|
183
|
+
`perturbation.py::DiagramTerm.build_integrand`). `coupling_values`
|
|
184
|
+
now accepts callables (`fn(n_list, t_list) -> (N,)*m tensor`) for
|
|
185
|
+
spacetime-dependent κ^{(n)}. Demo2's FK channel is now a one-line
|
|
186
|
+
`expansion.evaluate(vertex_types={'FK'})` — no bespoke integrator.
|
|
187
|
+
See `examples/demo2/validate_FK_dynamic.py`.
|
|
188
|
+
|
|
189
|
+
- **Observable convention kwarg** `integrate_over` on
|
|
190
|
+
`integrate_moment` / `Expansion.evaluate` / `.sweep` — per-external
|
|
191
|
+
control over fixed-time (`None`, default, matches ⟨φ(t_f) φ(t_f)⟩
|
|
192
|
+
physics convention) vs time-integrated (`"all"` or a subset).
|
|
193
|
+
The previous default was time-integrated; callers that want that
|
|
194
|
+
now pass `integrate_over="all"` explicitly.
|
|
195
|
+
|
|
196
|
+
- **L2 — YAML config + CLI**. `sft-wick run config.yaml` executes
|
|
197
|
+
an end-to-end workflow (expand → propagators → sweep → output);
|
|
198
|
+
`--override key=value` patches fields without editing the file.
|
|
199
|
+
`c_closed_form_module` and vertex `coupling_module` fields wire
|
|
200
|
+
user Python modules in. Full round-trip tests in
|
|
201
|
+
`tests/test_workflow_config.py` (CF1–CF5). Example configs:
|
|
202
|
+
`examples/demo1_config.yaml`, `examples/demo2_config.yaml`.
|
|
203
|
+
|
|
204
|
+
- **L1 — high-level workflow API**: `System` (physics spec),
|
|
205
|
+
`Expansion` (diagram-level inspection + per-channel integration),
|
|
206
|
+
`Propagators` (thin cache wrapper), `Result` / `SweepResult`
|
|
207
|
+
(pandas-backed structured output). Bare F/κ^{(n)} tensors —
|
|
208
|
+
wrapper applies MSR factors `-(i^n)/n!` automatically.
|
|
209
|
+
`expansion.by_vertex_type(order)` classifies diagrams by
|
|
210
|
+
F/K composition (demo2-style FF/FK split). New tests
|
|
211
|
+
`tests/test_workflow.py` (WF1–WF5).
|
|
212
|
+
|
|
213
|
+
- **Parallelised lazy propagator spline build** (`evaluate.py`).
|
|
214
|
+
`_LazyTimeSplineCache._build` now uses `joblib.Parallel` when
|
|
215
|
+
`n_jobs != 1` (previously silently ignored for lazy mode).
|
|
216
|
+
`examples/demo1/validate_R_C_derivation.py` went from 400 s → 39 s
|
|
217
|
+
on M-series (10.3× speedup) with the `n_jobs=-1` plumbing.
|
|
218
|
+
|
|
219
|
+
### Bug fixes
|
|
220
|
+
|
|
221
|
+
- **`DiagramIntegrand.evaluate` scalar path now honours
|
|
222
|
+
`fixed_indices`** (evaluate.py:1322, 1424). Previously
|
|
223
|
+
`_resolve_component(il, {})` was passed `{}` instead of
|
|
224
|
+
`self.fixed_indices`, so observable component labels (`'a'`,
|
|
225
|
+
`'b'`) failed to resolve and the code summed over all
|
|
226
|
+
components — an N-factor overcounting at order 0. The
|
|
227
|
+
vectorised path already handled `fi` correctly; this brings the
|
|
228
|
+
scalar path in sync.
|
|
229
|
+
|
|
230
|
+
### Bug fixes
|
|
231
|
+
|
|
232
|
+
- **Fixed incorrect C-propagator component resolution in numerical integration**
|
|
233
|
+
(`evaluate.py`). When `build_integrand()` was called with `fixed_indices`
|
|
234
|
+
(e.g. `{'a': 1, 'b': 1}` for selecting a specific correlator component),
|
|
235
|
+
the fixed index names (like `'b'`) were not passed through to the QMC/GL
|
|
236
|
+
integration routines. `_resolve_component('b', idx_map)` failed to
|
|
237
|
+
resolve the index, causing the integrator to **sum over all field
|
|
238
|
+
components** instead of selecting the fixed one. For `N_comp = 2` with
|
|
239
|
+
`iso_C`, this produced a factor-of-2 overcounting per unresolved
|
|
240
|
+
C-propagator index, making perturbative corrections ~1.3–1.8× too large
|
|
241
|
+
depending on the diagram topology.
|
|
242
|
+
|
|
243
|
+
**Fix:** `DiagramIntegrand` now stores the `fixed_indices` dict and
|
|
244
|
+
both `integrate_two_point_qmc` and `integrate_moment_qmc_vectorized`
|
|
245
|
+
merge it into the index map before calling `_resolve_component`.
|
|
246
|
+
|
|
247
|
+
Affected files:
|
|
248
|
+
- `sft_wick/evaluate.py` — added `fixed_indices` field to
|
|
249
|
+
`DiagramIntegrand`; updated `integrate_two_point_qmc` and
|
|
250
|
+
`integrate_moment_qmc_vectorized` to use `ig.fixed_indices`.
|
|
251
|
+
- `sft_wick/perturbation.py` — `build_integrand()` now passes
|
|
252
|
+
`fixed_indices` to the `DiagramIntegrand` constructor.
|
|
253
|
+
|
|
254
|
+
- **Fixed coupling symmetry bug in `compute_moment_numerical`**
|
|
255
|
+
(`perturbation.py`). The canonical grouping of component routings
|
|
256
|
+
reused reference propagators and static coupling symbols, causing
|
|
257
|
+
asymmetric coupling tensors (e.g. `F[1,0,1]=1, F[1,1,0]=0`) to
|
|
258
|
+
produce wrong results. Symmetric tensors were unaffected.
|
|
259
|
+
|
|
260
|
+
**Fix:** Each component routing now produces its own `DiagramTerm`
|
|
261
|
+
with routing-specific propagators. This removes the incorrect
|
|
262
|
+
canonical grouping but increases the number of diagram terms.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite both the software and the paper below."
|
|
3
|
+
title: "sft-wick: Feynman diagrammatic expansion and evaluation for statistical field theory"
|
|
4
|
+
abstract: >-
|
|
5
|
+
An open-source Python package that constructs diagram tables and computes
|
|
6
|
+
their integrals numerically for stochastic field dynamics cast into a
|
|
7
|
+
path-integral (Martin-Siggia-Rose) formulation. Given an action and an
|
|
8
|
+
observable, it enumerates topologically distinct Feynman diagrams, derives
|
|
9
|
+
their algebraic coefficients, and evaluates the resulting diagram integrals
|
|
10
|
+
from user-supplied response and cumulant functions. The setting targeted
|
|
11
|
+
includes multi-component, multi-dimensional fields with matrix propagators,
|
|
12
|
+
tensor-valued couplings, and non-Gaussian driving noise specified by
|
|
13
|
+
arbitrary n-point cumulants. The core algorithm enumerates spatial
|
|
14
|
+
topologies before routing component indices, avoiding
|
|
15
|
+
contraction-by-contraction Wick expansion; response-field constraints
|
|
16
|
+
(vanishing response-response contractions, the Ito prescription, absence of
|
|
17
|
+
causal response loops) are enforced during enumeration.
|
|
18
|
+
type: software
|
|
19
|
+
authors:
|
|
20
|
+
- family-names: Zhang
|
|
21
|
+
given-names: Zheng
|
|
22
|
+
email: zzhang0123@gmail.com
|
|
23
|
+
orcid: "https://orcid.org/0000-0002-9154-2803"
|
|
24
|
+
version: "0.2.0"
|
|
25
|
+
license: BSD-3-Clause
|
|
26
|
+
repository-code: "https://github.com/StatFieldTheory/sft-wick"
|
|
27
|
+
url: "https://sft-wick.readthedocs.io"
|
|
28
|
+
keywords:
|
|
29
|
+
- statistical field theory
|
|
30
|
+
- Wick's theorem
|
|
31
|
+
- Feynman diagrams
|
|
32
|
+
- Martin-Siggia-Rose formalism
|
|
33
|
+
- perturbation theory
|
|
34
|
+
- symbolic computation
|
|
35
|
+
preferred-citation:
|
|
36
|
+
type: article
|
|
37
|
+
title: "sft-wick: A formalism and package for Feynman-diagram expansion and evaluation in stochastic field theories"
|
|
38
|
+
authors:
|
|
39
|
+
- family-names: Zhang
|
|
40
|
+
given-names: Zheng
|
|
41
|
+
orcid: "https://orcid.org/0000-0002-9154-2803"
|
|
42
|
+
year: 2026
|
|
43
|
+
url: "https://arxiv.org/abs/2606.19480"
|
|
44
|
+
identifiers:
|
|
45
|
+
- type: other
|
|
46
|
+
value: "arXiv:2606.19480"
|
|
47
|
+
description: arXiv preprint
|
sft_wick-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present, Zheng Zhang
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
8
|
+
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
10
|
+
|
|
11
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
12
|
+
|
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|