Thank you for your interest in contributing to QAtlas! This guide will help you understand how the project is organized and what we look for in contributions.
QAtlas is a dictionary of rigorous results in quantum and statistical physics. It stores analytically known exact values in src/ and verifies them against independent numerical calculations in test/. The core value proposition is that every stored result is cross-validated from at least two independent theoretical or computational sources.
The source code in src/ does not depend on Lattice2D, QuasiCrystal, or any lattice construction package. It contains pure functions that map (model, quantity, bc) → value. Lattice-package dependencies live exclusively in test/ via [extras].
Adding a new rigorous result is always more valuable than perfecting the code structure. If a new result doesn't fit cleanly into the existing directory layout, add it anyway and verify it — the structure can be refactored later without losing the verified result.
A value in src/ is only considered rigorous once it has been independently verified in test/. Internal consistency checks (e.g., scaling relations) are necessary but not sufficient. We require cross-verification from independent theoretical sources whenever possible.
For each new rigorous result, the accompanying docs/src/calc/ derivation must be complete and step-by-step (see md/docs-conventions.md for the depth standard). Forbidden phrases such as "it can be shown" / "we omit details" / "standard calculation gives" must not appear.
src/
├── core/ # Type hierarchy, aliases, BC / Quantity structs
│ ├── type.jl # AbstractQAtlasModel, OBC(N), PBC(N), Infinite, Quantity{S}
│ ├── alias.jl # Symbol -> canonical-name dispatch table
│ └── quantities.jl # MagnetizationX, SusceptibilityZZ, ZZCorrelation{M}, ...
├── deprecate/ # Pre-v0.13 Symbol-dispatch shims (removable at v1.0)
├── universalities/ # Universality{C}(...) parametric type
│ ├── Universality.jl # base type + exponent table
│ ├── Ising2D.jl # 2D Ising (exact + 3D numerical bootstrap)
│ ├── KPZ.jl, Percolation.jl, ...
│ └── E8.jl # E8 mass ratios
├── universalities/ONModel.jl # XY / Heisenberg / O(N) nonlinear σ
└── models/ # Layout: `<class>/<Model>/<Model>.jl`.
│ # Per-model directory so each Model has
│ # its own dir even if currently single
│ # file (room to grow into thermal /
│ # dynamics / local siblings as needed).
├── classical/
│ └── IsingSquare/
│ └── IsingSquare.jl # IsingSquare(; J, Lx, Ly)
└── quantum/
├── TFIM/
│ ├── TFIM.jl # TFIM(; J, h) + Energy + MassGap + CentralCharge
│ ├── TFIM_thermal.jl # FreeEnergy, ThermalEntropy, SpecificHeat, M_x, χ_xx
│ ├── TFIM_dynamics.jl # Majorana covariance, {XX,YY,ZZ}Correlation{M}, structure factors
│ └── TFIM_local.jl # MagnetizationXLocal, MagnetizationZLocal, EnergyLocal
├── Heisenberg/
│ └── Heisenberg.jl # Heisenberg1D() + ExactSpectrum + GroundStateEnergyDensity
├── XXZ/
│ └── XXZ.jl # XXZ1D(; J, Δ) + Luttinger K, u, central charge, Energy
└── tightbinding/ # family dir (multiple tight-binding lattices)
└── regular/ # Bloch-diagonalisable periodic lattices
├── Honeycomb.jl # Honeycomb(; t, Lx, Ly)
├── Kagome.jl
├── Lieb.jl
└── Triangular.jl
# Future: tightbinding/{quasicrystalline,fractal,disordered}/
# for Fibonacci, Penrose, Sierpinski, Anderson, ...
test/
├── util/ # Reusable verification helpers (dense + sparse)
│ ├── classical_partition.jl # Brute-force partition function
│ ├── tight_binding.jl # Real-space TB Hamiltonian
│ ├── spinhalf_ed.jl # Dense spin-1/2 many-body ED
│ ├── sparse_ed.jl # Sparse ED + KrylovKit Lanczos ground state
│ └── bloch.jl # Generic Bloch Hamiltonian builder
├── standalone/ # Lattice-independent tests
└── verification/ # Cross-validation against Lattice2D
docs/src/ # Documenter + GitHub Pages
├── calc/ # Step-by-step derivations (Zettelkasten)
├── models/, universalities/, methods/ # API + results + narrative (links back to calc/)
└── verification/ # Cross-check narrative
md/ # Dev memos (Japanese OK, not published)
├── api.md, roadmap.md
├── docs-conventions.md # Docs depth standard — READ THIS BEFORE WRITING calc/
└── models/, universalities/ # Per-topic implementation notes
Every model is a concrete struct that carries its physical parameters as typed fields. Quantities are likewise concrete structs (not Symbols). Boundary conditions carry their own size.
# Canonical 3-dispatch form
fetch(TFIM(; J=1.0, h=1.0), Energy(), OBC(24); beta=5.0)
fetch(XXZ1D(; J=1.0, Δ=0.5), LuttingerParameter(), Infinite())
fetch(IsingSquare(; J=1.0, Lx=4, Ly=4), PartitionFunction(); β=0.44)Legacy Symbol calls fetch(:TFIM, :energy, OBC(); N=24, J=1.0, h=1.0, beta=5.0) still work through the thin shim layer in src/deprecate/ but emit a deprecation log.
See md/api.md for the full v0.13 design rationale (type hierarchy, quantity naming, deprecation path).
-
Define a concrete model struct (if the model does not yet exist). Physical parameters go in typed fields; boundary conditions and lattice size use the
OBC(N)/PBC(N)/Infinitetypes — never a loose kwarg.struct MyModel <: QAtlas.AbstractQAtlasModel J::Float64 h::Float64 end MyModel(; J::Real=1.0, h::Real=0.0) = MyModel(Float64(J), Float64(h)) function QAtlas.fetch(m::MyModel, ::Energy, bc::OBC; kwargs...) N = QAtlas._bc_size(bc, kwargs) ... end
-
Cite the source precisely in the docstring — not just "Author (Year)" but the specific equation, table, or theorem number. The
md/docs-conventions.mdpolicy applies equally to inline docstrings: no "it can be shown".# Good: traceable to a single line in the literature """ fetch(model::IsingSquare, ::SpontaneousMagnetization) -> Float64 Yang (1952) Phys. Rev. 85, 808 — from the spontaneous magnetization formula M(T) = (1 − sinh⁻⁴(2βJ))^{1/8}. """
-
Write a derivation note under
docs/src/calc/covering the exact computation the new result is based on. Follow the Main result / Setup / Calculation / References / Used by skeleton of md/docs-conventions.md. Non-trivial algebra must be shown line by line; integrals must be evaluated (contour, poles, residues), not cited as "standard calculation gives". -
Link the derivation in the corresponding
docs/src/models/…ordocs/src/universalities/…page viaSee full derivation: [...](../../calc/…md). -
Write tests that independently verify the result. The project uses a three-tier structure:
Tier Location Purpose Standalone test/standalone/Lattice-independent checks: special values, scaling relations Verification test/verification/Cross-check against Lattice2D-based calculations Cross-verification test/verification/Connect universality exponents to model-specific results -
Include at least one cross-verification that links your result to an existing QAtlas result derived from a different theoretical source. This is what makes QAtlas rigorous.
Use the Universality{C} parametric type with dimension d as a keyword:
fetch(Universality(:MyClass), CriticalExponents(); d=2)- Use
Rational{Int}for exact values (e.g.β = 1//8). - For numerical estimates, include
_errfields for uncertainty (e.g.β = 0.32642, β_err = 0.00001). - Verify scaling relations in tests:
α + 2β + γ = 2(Rushbrooke),γ = β(δ−1)(Widom), etc.
The generic Bloch builder in test/util/bloch.jl works for any Lattice2D topology. For lattices already supported by Lattice2D, a test file is usually all that is needed:
λ_bloch = bloch_tb_spectrum(MyTopology, Lx, Ly, t)
H = build_tight_binding(lat, t)
λ_real = sort(eigvals(Symmetric(H)))
@test λ_bloch ≈ λ_real atol=1e-10If you want a hardcoded Bloch formula in src/, place it in models/quantum/tightbinding/ as a concrete struct:
struct MyLattice <: QAtlas.AbstractQAtlasModel
t::Float64
Lx::Int
Ly::Int
endTopology-name collisions with Lattice2D. The identifiers Honeycomb, Kagome, Lieb, Triangular exist in both QAtlas and Lattice2D. To avoid UndefVarError in code that usings both packages, QAtlas does not export any of these names. Always qualify them as QAtlas.Honeycomb(), QAtlas.Kagome(), etc. The backward-compat alias Graphene = Honeycomb is exported because the name does not collide.
Writing a new docs/src/calc/ note? First read md/docs-conventions.md. The depth standard is enforced by:
- grep check:
docs/src/calc/<new-note>.mdmust have zero matches forit can be shown,we omit,standard calculation,as in [Author] [Journal],one can verify,it is easy to see,it follows immediately. - Structure check:
## Main result,## Setup,## Calculation,## References,## Used bysections, in that order. - Documenter build:
julia --project=docs -e 'include("docs/make.jl")'must complete with noError:lines.
The exemplars for depth are docs/src/calc/jw-tfim-bdg.md and docs/src/calc/bethe-ansatz-heisenberg-e0.md.
Public docs (docs/src/) are English only. Dev memos under md/ may be in Japanese.
-
QAtlas.fetchvsBase.fetch: always qualify asQAtlas.fetch(...)in test code to avoid the name collision with Julia's built-inBase.fetch. -
Bond counting in small PBC systems: Lattice2D's
bonds(lat)double-counts bonds whenLx = 2orLy = 2with periodic boundaries. Both the transfer-matrix and brute-force paths use the same convention, so they agree — but be aware of this when writing new models. - OBC vs PBC for gap analysis: in the ordered phase of the TFIM (h ≪ J), the lowest ED "gap" is actually the Z₂ tunneling splitting (exponentially small in N), not the physical excitation gap. This is correct physics but can be surprising in tests.
-
ForwardDiff compatibility: if you want a
fetchfunction to support automatic differentiation, relax type constraints fromFloat64toRealand avoid LAPACK-only operations likeeigvals(Symmetric(T))— usetr(T^n)instead, which works with dual numbers. -
Entanglement tests and RAM: the ED-based entanglement-entropy tests (
test_entanglement_central_charge.jl) scale as$O(2^N)$ memory at$N \ge 14$ . The default PR-CI profile runs$N \le 14$ via sparse + KrylovKit Lanczos.QATLAS_TEST_FULL=1enables$N = 16$ (~24 GB peak) and is run automatically every night byNightlyFullTests.yml(also invokable viaworkflow_dispatchfrom the Actions tab).
-
Run the full test suite with full threading:
julia -e 'using Pkg; Pkg.activate("."); Pkg.test(; julia_args=`-t auto --heap-size-hint=96G`)'On CI (GitHub Actions) this is automatic via
julia-args: "--threads=auto"in.github/workflows/CI.yml. -
If your PR adds new features, update the version in
Project.toml(patch bump per PR; minor for larger additions) — see md/roadmap.md for the current version-bump policy. -
If you added a new
docs/src/calc/derivation, build the docs locally and confirm:julia --project=docs -e 'include("docs/make.jl")'completes with exit 0 and no
Error:lines in stderr. -
If you find a discrepancy between QAtlas values and the literature, please open an issue with the full reference (journal, volume, page, equation number) so we can investigate.