Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 14 additions & 43 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,27 @@ on:
jobs:
rust:
runs-on: ubuntu-latest
# The Rust build compiles all of tensor4all-rs from source on a cold cache.
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- run: sudo apt-get update && sudo apt-get install -y libhdf5-dev liblapack-dev
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --release
- name: smoke elementwise
- run: cargo fmt --all -- --check
- run: cargo clippy --locked --all-targets -- -D warnings
- run: cargo test --release --locked
- name: smoke Fourier elementwise
run: >
BENCH_KS=4 BENCH_R=10 BENCH_RUNS=1 BENCH_WARMUPS=0
OUT_DIR=/tmp/smoke EXPORT_HDF5=/tmp/smoke
cargo run --release --bin elementwise_fourier
- name: smoke mpo
OUT_DIR=/tmp/smoke/raw
cargo run --release --locked --bin elementwise_fourier
- name: smoke Gaussian elementwise
run: >
BENCH_RS=8 BENCH_NGAUSS=3 BENCH_RUNS=1 BENCH_WARMUPS=0 BENCH_SANITY=1e-1
OUT_DIR=/tmp/smoke EXPORT_HDF5=/tmp/smoke
cargo run --release --bin mpo_mpo_quantics
- name: smoke elementwise gauss2d
BENCH_NS=2 BENCH_RUNS=1 BENCH_WARMUPS=0
BENCH_INPUT_CACHE_DIR=/tmp/smoke-cache OUT_DIR=/tmp/smoke/raw
cargo run --release --locked --bin elementwise_gauss2d_patched
- name: smoke Gaussian MPO contraction using the shared cache
run: >
BENCH_RS=8 BENCH_NGAUSS=3 BENCH_RUNS=1 BENCH_WARMUPS=0 BENCH_SANITY=1e-1
OUT_DIR=/tmp/smoke EXPORT_HDF5=/tmp/smoke-gauss2d
cargo run --release --bin elementwise_gauss2d
- name: smoke elementwise gauss2d scaling
# No EXPORT_HDF5: case 4 exports no instances, so there is no Julia
# check for it, and a single N is enough to exercise the runner.
run: >
BENCH_NS=8 BENCH_R0=8 BENCH_RUNS=1 BENCH_WARMUPS=0 BENCH_SANITY=1e-1
OUT_DIR=/tmp/smoke
cargo run --release --bin elementwise_gauss2d_scaling
- name: smoke elementwise gauss2d patched
# Both instance families, since they share only the harness: the default
# aniso one, whose N = 8 point is a fraction of a second, and the smooth
# one with R0 lowered so the patched construction stays cheap there, since
# at the default R0 one N already builds hundreds of patches. No
# EXPORT_HDF5, as for case 4.
run: >
BENCH_NS=8 BENCH_RUNS=1 BENCH_WARMUPS=0 BENCH_SANITY=1e-1
OUT_DIR=/tmp/smoke
cargo run --release --bin elementwise_gauss2d_patched
&&
BENCH_FAMILY=smooth BENCH_NS=8 BENCH_R0=8 BENCH_RUNS=1 BENCH_WARMUPS=0
BENCH_SANITY=1e-1 OUT_DIR=/tmp/smoke
cargo run --release --bin elementwise_gauss2d_patched
- uses: julia-actions/setup-julia@v2
with:
version: "1"
- name: julia checks
run: |
julia --project=julia -e 'using Pkg; Pkg.instantiate()'
julia --project=julia julia/check_elementwise.jl /tmp/smoke 4
julia --project=julia julia/check_mpo_mpo.jl /tmp/smoke 8
julia --project=julia julia/check_elementwise_gauss2d.jl /tmp/smoke-gauss2d 8
BENCH_NS=2 BENCH_RUNS=1 BENCH_WARMUPS=0
BENCH_INPUT_CACHE_DIR=/tmp/smoke-cache OUT_DIR=/tmp/smoke/raw
cargo run --release --locked --bin mpo_mpo_aniso_patched
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
Cargo.lock.orig
__pycache__/
.venv/
julia/Manifest.toml
result/**/raw/*.h5
100 changes: 36 additions & 64 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,35 @@
# Agent guidance

Read `README.md` first for the cases, arm names and environment knobs. This file
covers only what is easy to get wrong.

## Julia is JIT compiled

Any TIMED comparison against Julia must run warmup iterations before it measures.
A first invocation includes compilation time and is not a measurement.

The scripts in `julia/` are correctness checks only, not benchmarks. They read an
exported HDF5 instance back through ITensors.jl and compare against the same
analytic formula the Rust side uses. Their wall time is dominated by compilation
and must never be quoted as a timing result. A real Julia timing arm would need
its own warmup loop and a stated count, as `BENCH_WARMUPS` does in Rust.

## Runners are self checking

Every runner exits nonzero when any arm's error exceeds its sanity gate, so a
green exit is part of the evidence that a change is sound. The gates screen order
unity wrongness, not precision. The one exception is the `zipup_treetn` arm of
cases 3 and 4, gated at a hardcoded `5.0` because its error at the fixed output
budget is genuinely of order one (README known issue 8), so for that arm the
gate catches only a non-finite result or a runaway magnitude. Never loosen one
silently to make a run pass.

## Results are committed deliberately

Files under `result/<profile>/` are generated by `scripts/run_all.sh <profile>`
and committed on purpose, as the record of a full sweep on a stated machine. Do
not hand edit them, and do not regenerate them as a side effect of an unrelated
change. Use `OUT_DIR=/tmp/...` for probe runs. One profile belongs to one
physical machine, named after the machine, and a sweep from a different machine
goes to its own profile instead of overwriting another machine's numbers: wall
times of the memory heavy arms differ by factors between machines (README known
issue 10). Never put a hostname in a result file, the machine label and the
hardware fields in `run.yaml` carry the identity.

## Expensive benchmark inputs are cached

Every runner with nontrivial deterministic input construction must cache that
input and reuse it across algorithm comparisons and reruns. Input generation,
cache loading, format conversion and patch preparation stay outside timed
regions.

- Use one shared ignored cache directory, `.cache/inputs/` by default.
- Include every input-defining parameter, seed and an explicit input schema
version in the cache key. Bump the schema when generation semantics change.
- Write cache entries atomically and treat an existing entry as immutable.
- Validate loaded shapes, ranks, dtypes and shared index identities before use.
- Record the cache key, hit or miss, load time and build time in each result.
- Provide explicit refresh and cache-directory environment knobs. Never silently
accept a corrupt or incompatible entry.
- Cache inputs only, never algorithm outputs or timed intermediates.
- Tests whose subject is input generation or serialization must force a rebuild;
ordinary unit tests remain isolated and must not depend on persistent cache
state.

## Upstream is pinned

`Cargo.toml` pins every `tensor4all-rs` crate to one `rev`. Bump it deliberately,
move all the crates together, and never mix backend features across them. A bump
can change measured numbers, so it belongs in its own commit with a rerun.
Read `README.md` before changing case definitions, timing boundaries, input generation, or environment settings.

## Maintained scope

The repository has exactly three benchmark cases: Fourier elementwise, Gaussian elementwise global versus patched, and Gaussian MPO-MPO contraction global versus patched. Do not add another case when an arm or metric in one of these cases answers the question.

Gaussian inputs use independent two-dimensional interpolative decomposition per term, deterministic balanced pairwise add-and-compress, final relative-L2/SVD tolerance `1e-6`, and fixed patch cap 128. Do not add TCI generation, whole-mixture interpolation, isotropic controls, independent `R` sweeps, or a runtime patch-cap knob without an explicit design change.

ACI residual tolerance is not an L2 tolerance. Keep its internal metric explicit and compare it with other arms only through the common achieved external error.

## Timing

Time only the benchmarked elementwise or contraction operation. Input construction, cache I/O, compression, conversion, patch preparation, output conversion, and accuracy evaluation stay outside timed regions.

Run release builds with one pinned CPU core and single-threaded Rayon and BLAS. Warm up any JIT-compiled external implementation before timing it.

## Results

Files under `result/<profile>/` are generated by `scripts/run_all.sh <profile>` and committed deliberately. Do not edit them manually. Probe runs belong under `/tmp`. One profile belongs to one physical machine and contains no hostname.

## Input cache

Every expensive deterministic input must use the shared ignored `.cache/inputs/` directory by default.

- Include every content-defining parameter, seed, upstream revision, and schema version in the key.
- Write atomically and treat existing entries as immutable.
- Validate loaded length, site dimensions, scalar type, and index compatibility.
- Record key, hit or miss, load time, and build time.
- Cache inputs only, never timed outputs.
- Input-generation and serialization tests must force a rebuild.

## Pushing

Expand All @@ -76,7 +45,10 @@ together with the hardware behind them. Keep hostnames out of the description
as well as out of the files: on a public repository a hostname leaks the
operator's institution and location over time.

## Prose style
## Upstream

All tensor4all-rs crates are pinned to one revision in `Cargo.toml`. Move every pin together. A pin change requires fresh measurements.

## Prose

No em dashes or en dashes anywhere in this repository's documents, comments or
generated reports. Use commas, colons or separate sentences.
Do not use em dashes or en dashes in documentation, comments, or generated reports.
44 changes: 0 additions & 44 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ tensor4all-treetn = { git = "https://github.com/tensor4all/tensor4all-rs", rev =
tensor4all-itensorlike = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-itensorlike" }
tensor4all-partitionedtt = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-partitionedtt" }
tensor4all-partitionedtreetn = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-partitionedtreetn" }
tensor4all-quanticstci = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-quanticstci" }
tensor4all-interpolativeqtt = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-interpolativeqtt" }
tensor4all-hdf5 = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-hdf5" }
tensor4all-core = { git = "https://github.com/tensor4all/tensor4all-rs", rev = "9e9aedaebe0d3918b34dd399ff0981e337f3835b", package = "tensor4all-core" }
Expand Down
Loading
Loading