Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
2a254ce
Replace abstract fields with specific types
sou-cheng-choi Jun 2, 2026
2d4ba82
Replace abstract fields with specific types
sou-cheng-choi Jun 2, 2026
1ee36dc
Measure notebook run time
sou-cheng-choi Jun 2, 2026
8d49e53
Add benchmarking
sou-cheng-choi Jun 2, 2026
8990e48
Update Julia version to 1.12 and enhance benchmark script documentation
sou-cheng-choi Jun 2, 2026
7ce5a8a
Update References
sou-cheng-choi Jun 2, 2026
26dcfa9
measure execution time for each test,
sou-cheng-choi Jun 2, 2026
8df624f
Removed print statements
sou-cheng-choi Jun 2, 2026
f21de9e
Add benchmarking scripts for QMCPy and Julia
sou-cheng-choi Jun 2, 2026
7dccf01
minor changes
sou-cheng-choi Jun 2, 2026
f1541d6
+benchmarking scripts and results for QMC.jl vs QMCPy
sou-cheng-choi Jun 2, 2026
b8dd7ab
Fix CI: revert julia compat to 1.10 (CI matrix tests 1.10 and 1.11)
sou-cheng-choi Jun 2, 2026
795b48e
Speed up CubQMCNetG EuropeanOption
sou-cheng-choi Jun 2, 2026
7599f28
Speed up CubQMCNetG EuropeanOption
sou-cheng-choi Jun 3, 2026
d2d9d20
Improve benchmarking output and standardize ratio conventions
sou-cheng-choi Jun 3, 2026
9d24574
Aggregate summary metrics
sou-cheng-choi Jun 3, 2026
93b76ad
remove metadata and add single-run summary function
sou-cheng-choi Jun 3, 2026
642c423
Support custom output file labels
sou-cheng-choi Jun 3, 2026
5db56bf
Fix error
sou-cheng-choi Jun 3, 2026
f0c1324
Support labeled Julia-vs-QMCPy comparison
sou-cheng-choi Jun 3, 2026
852c121
Add README for benchmarking QMC.jl
sou-cheng-choi Jun 3, 2026
aad1791
Add large-d cases for Gaussian transform benchmarks
sou-cheng-choi Jun 3, 2026
79b3830
Add bench-all-label target
sou-cheng-choi Jun 3, 2026
10ac89a
Add bench-compare-labels target and update README
sou-cheng-choi Jun 3, 2026
0804b89
Reduce memory and run time
sou-cheng-choi Jun 3, 2026
e9ddfb6
Add allocation-audit benchmarks for Gaussian transforms and large-d c…
sou-cheng-choi Jun 3, 2026
a78fa5e
Disable formatting test
sou-cheng-choi Jun 3, 2026
ed9c57e
Add QMCPy benchmark for Python memory
sou-cheng-choi Jun 3, 2026
cbe3eb8
Add memory tracking
sou-cheng-choi Jun 3, 2026
3ebdcf5
Update memory measurement
sou-cheng-choi Jun 3, 2026
4645b6c
improve benchmarking output
sou-cheng-choi Jun 3, 2026
3fd0281
Add accuracy checks for Julia vs Python solutions
sou-cheng-choi Jun 3, 2026
4709fb3
Refactor benchmark integration cases
sou-cheng-choi Jun 3, 2026
d4553a1
Fix typo
sou-cheng-choi Jun 3, 2026
5785bbc
Update benchmarks.jl
sou-cheng-choi Jun 3, 2026
ae34022
Update keister.jl
sou-cheng-choi Jun 3, 2026
ea66887
Add exact value checks and accuracy summary for integration benchmarks
sou-cheng-choi Jun 3, 2026
a2a73aa
Add benchmarking cases and update documentation
sou-cheng-choi Jun 3, 2026
851ba29
Refactor stopping criteria calculations and enhance tests with exact …
sou-cheng-choi Jun 3, 2026
b77cfd7
Enhance Keister integral computation and tests
sou-cheng-choi Jun 3, 2026
6c6a190
Refactor benchmark integrand initialization
sou-cheng-choi Jun 3, 2026
9ce6deb
Add function to run benchmarks in a controlled environment with proje…
sou-cheng-choi Jun 3, 2026
ecc9567
Enhance stopping criteria and add tests
sou-cheng-choi Jun 4, 2026
293426c
Normalize order aliases in Lattice and update tests
sou-cheng-choi Jun 4, 2026
026f528
Add Rational Quadratic kernel implementation and tests
sou-cheng-choi Jun 4, 2026
d38af78
Add set_tolerance! function and corresponding tests for stopping crit…
sou-cheng-choi Jun 4, 2026
d018b7f
format
sou-cheng-choi Jun 4, 2026
c6d4616
Add KernelSquaredExponential implementation and update set_tolerance!…
sou-cheng-choi Jun 4, 2026
e5f6d18
fix format
sou-cheng-choi Jun 4, 2026
2cc77d9
Update Makefile to include benchmark directory in formatting and chec…
sou-cheng-choi Jun 4, 2026
c7aaa6f
Add AcceptanceRejectionReal
sou-cheng-choi Jun 4, 2026
f118226
Update JuliaFormatter settings and improve benchmark test assertions
sou-cheng-choi Jun 4, 2026
564c5d2
Better format
sou-cheng-choi Jun 4, 2026
d934070
Add support for digital options and corresponding tests
sou-cheng-choi Jun 4, 2026
e3f91d4
Improve output formatting
sou-cheng-choi Jun 4, 2026
d812831
Add exact value calculation for geometric Asian options and tests
sou-cheng-choi Jun 4, 2026
e4df345
Add deterministic value checks
sou-cheng-choi Jun 4, 2026
c74507f
Add closed-form reference values and sensitivity indices for Ishigami…
sou-cheng-choi Jun 4, 2026
524a763
Add new tests for integration and utility
sou-cheng-choi Jun 4, 2026
bb2ec97
formatting
sou-cheng-choi Jun 4, 2026
8442b48
Disable CompatHelper and nightly workflows; add disabled versions for…
sou-cheng-choi Jun 4, 2026
0db5b53
Merge origin/develop into choi and resolve conflicts
Copilot Jun 4, 2026
2cb7d24
Enhance digital net and lattice generators with custom generating vec…
sou-cheng-choi Jun 4, 2026
bbb2e8d
Better format and make coverage report
sou-cheng-choi Jun 4, 2026
31bd78f
Add support for custom random odd generating vectors in Lattice and e…
sou-cheng-choi Jun 4, 2026
b989469
Update documentation
sou-cheng-choi Jun 4, 2026
70e8624
Clean up documentation build directory before generating new document…
sou-cheng-choi Jun 4, 2026
266e9c1
Merge branch 'choi' of https://github.com/QMCSoftware/QMC.jl into choi
sou-cheng-choi Jun 4, 2026
6944da5
Enhance DigitalNetB2 with custom generating matrices support and impr…
sou-cheng-choi Jun 4, 2026
e8c61a9
Enhance stopping criterion tolerance handling and add tests
sou-cheng-choi Jun 4, 2026
eb0f393
Format
sou-cheng-choi Jun 4, 2026
db298e9
Enhance benchmarking and coverage reporting in Makefile and related s…
sou-cheng-choi Jun 4, 2026
51071b4
Clean up Makefile by removing coverage files after benchmarks
sou-cheng-choi Jun 4, 2026
1728016
Enhance benchmark commands
sou-cheng-choi Jun 4, 2026
4af0946
Fix terminology in collect_integrate_solutions
sou-cheng-choi Jun 4, 2026
d91ffb8
Add lcov.info to .gitignore
sou-cheng-choi Jun 4, 2026
facf4be
Remove CHANGELOG.md and citation file cite_qmcju.bib
sou-cheng-choi Jun 4, 2026
5455d0f
Add new integration functions for CubMCCLT and CubQMCLatticeG options
sou-cheng-choi Jun 4, 2026
d2e3104
Add space
sou-cheng-choi Jun 4, 2026
93347a9
Add extra newline to output
sou-cheng-choi Jun 4, 2026
2598618
Optimize evaluation functions for BoxIntegral, Genz, and Linear0 by i…
sou-cheng-choi Jun 4, 2026
ece54f0
Output formatting
sou-cheng-choi Jun 4, 2026
7d4eb9f
Optimize integration function for CubQMCNetG by batching evaluations …
sou-cheng-choi Jun 4, 2026
326456a
Optimize StudentT transformation for df=2.0 by implementing a closed-…
sou-cheng-choi Jun 4, 2026
274394a
Optimize matrix operations for performance by leveraging column-major…
sou-cheng-choi Jun 4, 2026
5920bb4
Optimize acceptance-rejection transform for performance by accumulati…
sou-cheng-choi Jun 4, 2026
bee79de
Simplify make target name. Optimize Johnson's SU transformation usin…
sou-cheng-choi Jun 4, 2026
674fff1
Enhance notebook runner with verbose output option
sou-cheng-choi Jun 4, 2026
f35e8d7
Fix summary output to only display failed notebooks
sou-cheng-choi Jun 4, 2026
9d877aa
Optimize integrate function by batching R replicates' transform and e…
sou-cheng-choi Jun 4, 2026
ca5733c
Measure run time of doc
sou-cheng-choi Jun 4, 2026
e9b3322
Batch R replicates for improved performance and memory efficiency. Ad…
sou-cheng-choi Jun 4, 2026
1169d79
+ orthonormal Fast Walsh-Hadamard transform `_fwht_ortho`
sou-cheng-choi Jun 4, 2026
eb1869a
+ in-place coefficient decay-ordering function and tests
sou-cheng-choi Jun 4, 2026
e3a36c5
Add CubQMCNetGSingle stopping criterion and related tests/doc
sou-cheng-choi Jun 4, 2026
beb8e29
Enhance CubQMCNetGSingle with r_lag parameter
sou-cheng-choi Jun 4, 2026
4f40516
reorganize sections and add local CI target
sou-cheng-choi Jun 4, 2026
2dc8095
Move targets for better structure
sou-cheng-choi Jun 5, 2026
e2ae116
Add benchmark cases for CubQMCNetGSingle
sou-cheng-choi Jun 5, 2026
37bd0fa
Update local CI target to run tests and benchmarks WITHOUT coverage
sou-cheng-choi Jun 5, 2026
3472f6b
Add coverage caveat to benchmark README
sou-cheng-choi Jun 5, 2026
e8e796c
Fix grammatical error
sou-cheng-choi Jun 5, 2026
45237fa
Replace CubQMCNetGSingle with CubQMCNetGRep
sou-cheng-choi Jun 5, 2026
968d86f
Enhance DigitalNetB2 initialization across demos
sou-cheng-choi Jun 5, 2026
d0ebe7f
Update kernel specifications in digital_net_b2 notebook Julia 1.12.6
sou-cheng-choi Jun 5, 2026
1f29132
Enhanced lattice.jl to support LDData filenames and URL
sou-cheng-choi Jun 5, 2026
432f251
Merge branch 'develop' into choi
sou-cheng-choi Jun 5, 2026
435adde
Remove unnecessary Pkg.resolve() calls
sou-cheng-choi Jun 5, 2026
5712293
Enhance README.md and update stale_deps in test_aqua.jl to include Do…
sou-cheng-choi Jun 5, 2026
00232d1
Enhance DigitalNetB2 to support QMCPy- order and LDData
sou-cheng-choi Jun 5, 2026
1cfc5c5
Merge branch 'choi' of https://github.com/QMCSoftware/QMC.jl into choi
sou-cheng-choi Jun 5, 2026
e0ee3d9
Enhance DigitalNetB2 to support parameters t and msb
sou-cheng-choi Jun 5, 2026
43e6105
Enhance DigitalNetB2 to support higher-order interlacing with alpha
sou-cheng-choi Jun 5, 2026
50708b5
improve DigitalNetB2's handling of generating matrices
sou-cheng-choi Jun 5, 2026
5b0443d
Enhance DigitalNetB2 documentation
sou-cheng-choi Jun 5, 2026
b3b46f8
Enhance DigitalNetB2 documentation
sou-cheng-choi Jun 5, 2026
7ba2cab
Enhance DigitalNetB2 documentation and tests
sou-cheng-choi Jun 5, 2026
0027d77
Enhance DigitalNetB2 instantiation
sou-cheng-choi Jun 5, 2026
f9038a3
Enhance DigitalNetB2 documentation and tests for alpha handling and d…
sou-cheng-choi Jun 5, 2026
aa1aef1
Improve Lattice structure and spawning
sou-cheng-choi Jun 5, 2026
e2d3d71
Enhance Lattice and DigitalNetB2 documentation. Update tests.
sou-cheng-choi Jun 5, 2026
47342d7
Refactor CubMCCLT constructor
sou-cheng-choi Jun 5, 2026
0af4318
Add trace_iterations parameter to CubQMCBayesLatticeG and CubQMCBayes…
sou-cheng-choi Jun 5, 2026
e978e94
Add trace_iterations parameter
sou-cheng-choi Jun 5, 2026
ef3d962
Remove benchmark results README.md file
sou-cheng-choi Jun 5, 2026
7bbcb6e
Enhance benchmarking configuration and metadata
sou-cheng-choi Jun 6, 2026
d1bde1d
Update StudentT benchmark
sou-cheng-choi Jun 6, 2026
89c648f
Enhance benchmark output
sou-cheng-choi Jun 6, 2026
cbbe1ac
Add wait_for_artifact function
sou-cheng-choi Jun 6, 2026
1e1ebeb
Refactor wait_for_artifact
sou-cheng-choi Jun 6, 2026
a67de6a
Enhance benchmarking output and documentation
sou-cheng-choi Jun 6, 2026
c16804e
Fix RSS ratio
sou-cheng-choi Jun 6, 2026
6151443
Enhance StudentT with closed-form quantile transformations for df=1,…
sou-cheng-choi Jun 6, 2026
52f3a34
Enhance documentation
sou-cheng-choi Jun 6, 2026
5070492
Update README and demos doc
sou-cheng-choi Jun 6, 2026
918c8cf
Add nightly benchmarking workflow and update README
sou-cheng-choi Jun 6, 2026
e67cefe
Merge branch 'develop' into choi
sou-cheng-choi Jun 6, 2026
31cfaf6
Indent components
sou-cheng-choi Jun 6, 2026
cd342c1
Merge branch 'choi' of https://github.com/QMCSoftware/QMC.jl into choi
sou-cheng-choi Jun 6, 2026
52b8c39
Enhance test error handling
sou-cheng-choi Jun 6, 2026
d65cad9
Fail fast workflows
sou-cheng-choi Jun 6, 2026
d5bc0e1
Attempt to fix test failure
sou-cheng-choi Jun 6, 2026
96cea5b
Attempt to fix test failure
sou-cheng-choi Jun 6, 2026
0d36d28
Fix CI failures
sou-cheng-choi Jun 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ This folder contains the repository's GitHub Actions workflows.
- `ci-full.yml`: broader matrix CI for pull requests to `develop` and `master`.
- `docs.yml`: Documenter build and deployment workflow.
- `TagBot.yml`: release-tag automation.
- `nightly.yml`: scheduled benchmarking on non-Linux platforms.

### Disabled

- `format.yml.disabled`: disabled formatter workflow kept for reference.
- `CompatHelper.yml.disabled`: dependency update automation.
- `nightly.yml.disabled`: scheduled regression sweep on non-Linux platforms.


See [`../../docs/src/ci-testing.md`](../../docs/src/ci-testing.md) for the user-facing workflow overview.
4 changes: 2 additions & 2 deletions .github/workflows/ci-full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
name: Julia ${{ matrix.julia-version }} – ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
fail-fast: true
matrix:
julia-version: ['1.10', '1.11']
os: [ubuntu-latest, macos-latest, windows-latest]
Expand Down Expand Up @@ -46,7 +46,7 @@ jobs:
runs-on: ${{ matrix.os }}
needs: test
strategy:
fail-fast: false
fail-fast: true
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
name: Julia ${{ matrix.julia-version }} – Linux
runs-on: ubuntu-latest
strategy:
fail-fast: false
fail-fast: true
matrix:
julia-version: ['1.12']

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ jobs:
name: Nightly – Julia ${{ matrix.julia-version }} – ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
fail-fast: true
matrix:
include:
- os: macos-latest
julia-version: '1.12'
- os: windows-latest
- os: ubuntu-latest
julia-version: '1.12'

steps:
Expand All @@ -41,5 +39,5 @@ jobs:
- name: Install dependencies
run: julia --project=. -e 'using Pkg; Pkg.instantiate()'

- name: Run unit tests
run: julia --project=. -e 'using Pkg; Pkg.test()'
- name: Run benchmark
run: make ci
31 changes: 19 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ QMCPY_PYTHON_AUTO := $(shell \
done)
PYTHON ?= $(if $(QMCPY_PYTHON_AUTO),$(QMCPY_PYTHON_AUTO),python)
BENCH_COVERAGE ?= 0
BENCH_BLAS_THREADS ?= 1
JULIA_BENCH_COVERAGE_FLAG := $(if $(filter 1,$(BENCH_COVERAGE)),--code-coverage=user,)
BENCH_THREAD_ENV := QMC_BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) OPENBLAS_NUM_THREADS=$(BENCH_BLAS_THREADS) MKL_NUM_THREADS=$(BENCH_BLAS_THREADS) OMP_NUM_THREADS=$(BENCH_BLAS_THREADS) NUMEXPR_NUM_THREADS=$(BENCH_BLAS_THREADS)

define RUN_TIMED
@start=$$(date +%s); \
Expand Down Expand Up @@ -136,7 +138,7 @@ notebook-%:
# Override output label with: make bench LABEL=gaus or make bench gaus
# Saves results to benchmark/results/latest.json (default) or <LABEL>.json
bench:
$(call RUN_TIMED,BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/runbenchmarks.jl $(LABEL),bench)
$(call RUN_TIMED,$(BENCH_THREAD_ENV) BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/runbenchmarks.jl $(LABEL),bench)

check-qmcpy-python:
@$(PYTHON) -c "import qmcpy" >/dev/null 2>&1 || \
Expand All @@ -152,7 +154,7 @@ check-qmcpy-python:
REV ?= HEAD
LABEL ?=
bench-compare:
$(call RUN_TIMED,BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare.jl $(REV) $(LABEL),bench-compare)
$(call RUN_TIMED,$(BENCH_THREAD_ENV) BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare.jl $(REV) $(LABEL),bench-compare)

# Side-by-side Julia vs QMCPy comparison.
# Runs both the Julia and QMCPy benchmark harnesses for the requested labels.
Expand All @@ -163,35 +165,40 @@ bench-compare:
# If LABEL is set, it also becomes the default input label for both sides.
JL_LABEL ?= $(if $(LABEL),$(LABEL),latest)
PY_LABEL ?= $(JL_LABEL)
BENCH_COMPARE_OUT := $(if $(LABEL),benchmark/results/compare_$(LABEL).md,benchmark/results/compare_head.md)
BENCH_COMPARE_PY_OUT := $(if $(LABEL),benchmark/results/compare_python_$(LABEL).md,benchmark/results/compare_python.md)
bench-compare-py: bench check-qmcpy-python
$(call RUN_TIMED,$(PYTHON) benchmark/benchmark_qmcpy.py $(PY_LABEL) && BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare_py.jl $(JL_LABEL) $(PY_LABEL) $(LABEL),bench-compare-py)
$(call RUN_TIMED,$(BENCH_THREAD_ENV) $(PYTHON) benchmark/benchmark_qmcpy.py $(PY_LABEL) && $(BENCH_THREAD_ENV) BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare_py.jl $(JL_LABEL) $(PY_LABEL) $(LABEL),bench-compare-py)

# Explicit labeled Julia-vs-QMCPy comparison flow.
# Usage: make bench-compare-py-label LABEL=base
bench-compare-py-label: check-qmcpy-python
$(call RUN_TIMED,BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/runbenchmarks.jl $(LABEL) && $(PYTHON) benchmark/benchmark_qmcpy.py $(LABEL) && BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare_py.jl $(LABEL) $(LABEL) $(LABEL),bench-compare-py-label)
$(call RUN_TIMED,$(BENCH_THREAD_ENV) BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/runbenchmarks.jl $(LABEL) && $(BENCH_THREAD_ENV) $(PYTHON) benchmark/benchmark_qmcpy.py $(LABEL) && $(BENCH_THREAD_ENV) BENCH_COVERAGE=$(BENCH_COVERAGE) julia $(JULIA_BENCH_COVERAGE_FLAG) benchmark/compare_py.jl $(LABEL) $(LABEL) $(LABEL),bench-compare-py-label)

# Run the labeled Julia-only comparison and Julia-vs-QMCPy comparison in one task.
# This target does not define a third ratio; inspect:
# - $(BENCH_COMPARE_OUT) with ratio = reference ÷ local
# - $(BENCH_COMPARE_PY_OUT) with ratio = Python ÷ Julia
# Usage: make bench-all LABEL=base
bench-all:
$(call RUN_TIMED,$(MAKE) bench-compare BENCH_COVERAGE=$(BENCH_COVERAGE) LABEL=$(LABEL) && $(MAKE) bench-compare-py BENCH_COVERAGE=$(BENCH_COVERAGE) LABEL=$(LABEL),bench-all)
$(call RUN_TIMED,$(MAKE) bench-compare BENCH_COVERAGE=$(BENCH_COVERAGE) BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) LABEL=$(LABEL) && $(MAKE) bench-compare-py BENCH_COVERAGE=$(BENCH_COVERAGE) BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) LABEL=$(LABEL) && printf '\n[bench-all] wrote %s (ratio = reference ÷ local) and %s (ratio = Python ÷ Julia)\n' "$(BENCH_COMPARE_OUT)" "$(BENCH_COMPARE_PY_OUT)",bench-all)

# Run the benchmark suite with coverage enabled and produce an lcov report over
# both src/ and benchmark/ coverage files.
bench-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench BENCH_COVERAGE=1 && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-coverage)
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench BENCH_COVERAGE=1 BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-coverage)

# Run the Julia-vs-Julia comparison with coverage enabled and produce an lcov report.
bench-compare-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-compare BENCH_COVERAGE=1 REV=$(REV) LABEL=$(LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-compare-coverage)
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-compare BENCH_COVERAGE=1 BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) REV=$(REV) LABEL=$(LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-compare-coverage)

# Run the Julia-vs-QMCPy comparison with coverage enabled and produce an lcov report.
bench-compare-py-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-compare-py BENCH_COVERAGE=1 LABEL=$(LABEL) JL_LABEL=$(JL_LABEL) PY_LABEL=$(PY_LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-compare-py-coverage)
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-compare-py BENCH_COVERAGE=1 BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) LABEL=$(LABEL) JL_LABEL=$(JL_LABEL) PY_LABEL=$(PY_LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-compare-py-coverage)

# Run the full labeled benchmark workflow with coverage enabled and produce an lcov report.
bench-all-coverage:
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-all BENCH_COVERAGE=1 LABEL=$(LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-all-coverage)
$(call RUN_TIMED,find src benchmark -name '*.cov' -delete && rm -f lcov.info && $(MAKE) bench-all BENCH_COVERAGE=1 BENCH_BLAS_THREADS=$(BENCH_BLAS_THREADS) LABEL=$(LABEL) && julia --project=. devtools/process_coverage.jl src benchmark && find src benchmark -name '*.cov' -delete,bench-all-coverage)

# Compare two saved Julia benchmark-result labels and decide which one is better.
# Usage: make bench-compare-labels LABEL_A=a LABEL_B=b [OUT_LABEL=report]
Expand All @@ -203,7 +210,7 @@ bench-compare-labels:
# Combination of above targets
# ============================================================================

# Run the local full-check pipeline: format code, collect unit-test,
# Run the full-check pipeline: format code, collect unit-test,
# then collect full benchmark. Pass LABEL=... through to the benchmark step.
local-ci:
$(call RUN_TIMED,$(MAKE) format && $(MAKE) test && $(MAKE) bench-all LABEL=$(LABEL),local-ci)
ci:
$(call RUN_TIMED,$(MAKE) format && $(MAKE) test && $(MAKE) bench-all LABEL=$(LABEL),local-ci)
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,23 @@ println("Exact: $(keister_exact(3))")

## Components

QMC.jl provides four building blocks that snap together:
QMC.jl provides four core building blocks, plus related kernel types:

| Component | Types |
|---|---|
| **Discrete Distribution** | `IIDStdUniform`, `Lattice`, `DigitalNetB2`, `Halton`, `Kronecker`, `DigitalNetAnyBases`, `Faure` |
| **True Measure** | `Uniform`, `Gaussian`, `BrownianMotion`, `Lebesgue`, `GeometricBrownianMotion`, `StudentT`, `Triangular`, `Kumaraswamy`, `JohnsonsSU`, `BernoulliCont`, `AcceptanceRejection`, `DistributionsWrapper`, `MaternGP`, `UniformTriangle`, `ZeroInflatedExpUniform` |
| **True Measure** | `Uniform`, `Gaussian`, `BrownianMotion`, `Lebesgue`, `GeometricBrownianMotion`, `StudentT`, `Triangular`, `Kumaraswamy`, `JohnsonsSU`, `BernoulliCont`, `AcceptanceRejection`, `AcceptanceRejectionReal`, `DistributionsWrapper`, `MaternGP`, `UniformTriangle`, `ZeroInflatedExpUniform` |
| **Integrand** | `Keister`, `Genz`, `AsianOption`, `FinancialOption`, `FinancialOptionML`, `BoxIntegral`, `Linear0`, `Sin1D`, `Ishigami`, `Hartmann6D`, `Multimodal2D`, `FourBranch2D`, `SensitivityIndices`, `BayesianLRCoeffs`, `UMBridgeWrapper`, `CustomFun` |
| **Stopping Criterion** | `CubMCCLT`, `CubMCCLTVec`, `CubMCG`, `CubQMCLatticeG`, `CubQMCNetG`, `CubQMCNetGRep`, `CubQMCBayesLatticeG`, `CubQMCBayesNetG`, `CubQMCRepStudentT`, `CubMLMC`, `CubMLMCCont`, `CubMLQMC`, `CubMLQMCCont`, `PFGPCI` |
| **Kernel** | `KernelShiftInvar`, `KernelDigShiftInvar`, `KernelMatern12`, `KernelMatern32`, `KernelMatern52`, `KernelGaussian`, `KernelMultiTask`, `SumKernel`, `ProductKernel` |
| **Kernel** | `KernelShiftInvar`, `KernelDigShiftInvar`, `KernelMatern12`, `KernelMatern32`, `KernelMatern52`, `KernelGaussian`, `KernelRationalQuadratic`, `KernelSquaredExponential`, `KernelMultiTask`, `SumKernel`, `ProductKernel` |

Additional utilities include periodization transforms, iteration diagnostics (`IterationLog`), resume/checkpoint support, Walsh-Hadamard and BRO-FFT transforms, and a LatNetBuilder linker.

Advanced status notes: `PFGPCI` is currently exported as a parity placeholder,
but `integrate(::PFGPCI)` intentionally errors until a Julia GP backend is
implemented. Likewise, `gpu_fwht!` is currently a CPU-fallback stub rather than
a real GPU acceleration path.

## Installation

### Prerequisites
Expand Down
35 changes: 35 additions & 0 deletions benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ This writes:
benchmark/results/latest.json
```

By default the benchmark targets now pin BLAS-style thread env vars to `1` for
more stable dense-transform timings on both the Julia and QMCPy sides. Override
that when needed:

```bash
make bench BENCH_BLAS_THREADS=4
```

To save to a labeled file instead:

```bash
Expand Down Expand Up @@ -151,6 +159,12 @@ benchmark/results/qmcpy_base.json
benchmark/results/compare_python_base.md
```

The Julia memory sidecar and the QMCPy JSON now also record lightweight
benchmark metadata such as generation time, thread configuration, and the
integrate timing sample/repeat counts. `compare_python*.md` surfaces that
metadata in its header so stale or mismatched artifact pairings are easier to
spot.

### Coverage Caveat

Do not interpret coverage-enabled benchmark runs as representative performance comparisons.
Expand Down Expand Up @@ -195,6 +209,19 @@ If one memory ratio is `< 1` and the other is `> 1`, that is normal rather than

If `<label>_memory.json` is missing because the Julia benchmarks were generated before this feature was added, `compare_python*.md` will show Julia RSS delta as `n/a` until that label is rerun with `make bench` or `make bench-compare-py`.

The heaviest adaptive integrate rows are intentionally timed with more samples
than the leaf transform/evaluate rows (`samples=9` in Julia, `repeat=9` in
QMCPy) because those rows were the main source of weighted-ratio swings.

The QMCPy `StudentT` transform rows now also use a dedicated higher-stability
setting (`repeat=21`, `warmup=3`), and the Julia `StudentT` rows use
`samples=9`. Those settings are recorded in the report header so unusually large
cross-run changes in that family are easier to audit. The aggregate summary in
`compare_python*.md` now also breaks out `StudentT` timing separately
(`all matched rows`, `excluding StudentT`, and `StudentT only`) so the headline
cross-language ratio is easier to interpret when that transform family dominates
the total.

The Python harness also mirrors most of the newer Julia-only benchmark rows:

- large-`d` `Gaussian(diag)` and `Gaussian(dense)` transforms
Expand Down Expand Up @@ -274,6 +301,14 @@ benchmark/results/qmcpy_base.json
benchmark/results/compare_python_base.md
```

`bench-all` does not create a third combined ratio. It just runs both report
generators, so you need to read each report with its own convention:

- `compare_<label>.md`: `ratio = reference ÷ local`
- `compare_python_<label>.md`: `ratio = Python ÷ Julia`

So in both of those reports, `ratio > 1` means the local Julia side is faster.

## Output Files

Common generated files:
Expand Down
58 changes: 53 additions & 5 deletions benchmark/benchmark_qmcpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import tracemalloc
import warnings
import statistics
from datetime import datetime
from pathlib import Path

import numpy as np
Expand All @@ -55,6 +56,17 @@
LARGE_DIMS = [50, 200]
LARGE_N = [1024, 4096]
SEED = 42
DEFAULT_REPEAT = 7
INTEGRATE_REPEAT = 9
STUDENT_T_REPEAT = 21
STUDENT_T_WARMUP_RUNS = 3
THREAD_ENV_KEYS = (
"QMC_BENCH_BLAS_THREADS",
"OPENBLAS_NUM_THREADS",
"MKL_NUM_THREADS",
"OMP_NUM_THREADS",
"NUMEXPR_NUM_THREADS",
)


def current_rss_kib():
Expand Down Expand Up @@ -90,11 +102,17 @@ def measure_memory(fn):
return metrics


def bench(make_call, *, repeat=7, warmup=True):
def bench(make_call, *, repeat=DEFAULT_REPEAT, warmup=True):
"""Return median seconds plus approximate memory metrics per call."""
if isinstance(warmup, bool):
warmup_runs = 1 if warmup else 0
else:
warmup_runs = int(warmup)
if warmup_runs < 0:
raise ValueError("warmup must be bool or non-negative integer")
fn = make_call()
if warmup:
fn() # discard first call (cache/allocation warm-up)
for _ in range(warmup_runs):
fn() # discard first call(s) to reduce cache/allocation warm-up noise
mem = measure_memory(fn)
# Pick an inner count so each timing sample is long enough to be stable.
timer = timeit.Timer(fn)
Expand Down Expand Up @@ -134,12 +152,25 @@ def record(results, group, name, make_call, **kw):
print(f" {name:<45s} ERR: {type(e).__name__}: {e}")


def active_thread_env():
return {key: os.environ[key] for key in THREAD_ENV_KEYS if key in os.environ}


def main():
label = sys.argv[1] if len(sys.argv) > 1 else "latest"
results = {"gen_samples": {}, "transform": {}, "evaluate": {}, "integrate": {}}

print("\n\nQMCPy Benchmarks (qmcpy %s)" % getattr(qp, "__version__", "?"))
print("=" * 70)
thread_env = active_thread_env()
if thread_env:
print(
"Thread env: "
+ ", ".join(f"{key}={value}" for key, value in sorted(thread_env.items()))
)
print(
f"StudentT config: repeat={STUDENT_T_REPEAT}, warmup_runs={STUDENT_T_WARMUP_RUNS}"
)

# 1. Discrete distribution sampling --------------------------------------
# [C] = qmctoolscl C kernel (not a language comparison)
Expand Down Expand Up @@ -191,7 +222,14 @@ def make_student_t(n=n):
tm = qp.StudentT(dd, loc=np.zeros(dim), shape=np.eye(dim), df=2.0)
x = dd(n)
return lambda: tm._transform(x)
record(results, "transform", f"StudentT d=10 n={n}", make_student_t)
record(
results,
"transform",
f"StudentT d=10 n={n}",
make_student_t,
repeat=STUDENT_T_REPEAT,
warmup=STUDENT_T_WARMUP_RUNS,
)

def make_johnsons_su(n=n):
dim = 10
Expand Down Expand Up @@ -336,7 +374,7 @@ def _scalar(x):

for name, make_sc, warm in integrate_cases:
record(results, "integrate", name, integrate_call(make_sc),
repeat=3, warmup=warm)
repeat=INTEGRATE_REPEAT, warmup=warm)
# One-shot accuracy measurement: solution value + tolerances used. Kept
# separate from the timed runs and never aborts the run on failure.
try:
Expand All @@ -358,6 +396,16 @@ def _scalar(x):
outfile = resdir / f"qmcpy_{label}.json"
payload = {
"qmcpy_version": getattr(qp, "__version__", "?"),
"python_version": sys.version.split()[0],
"label": label,
"generated_at": datetime.now().isoformat(timespec="seconds"),
"thread_env": thread_env,
"benchmark_config": {
"default_repeat": DEFAULT_REPEAT,
"integrate_repeat": INTEGRATE_REPEAT,
"student_t_repeat": STUDENT_T_REPEAT,
"student_t_warmup_runs": STUDENT_T_WARMUP_RUNS,
},
"results": results,
}
outfile.write_text(json.dumps(payload, indent=2))
Expand Down
Loading
Loading