diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8914bb6..24c7ee6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,22 @@ name: CI +# Build, test and coverage. The deeper checks -- property tests, Kani, +# Miri and the strict lint pass -- are in verify.yml. +# +# `test` and `coverage` are separate jobs on purpose. `cargo llvm-cov` is +# not a reporting step that reads what `cargo test` already produced: +# there is nothing to read. It compiles the crate with +# `-C instrument-coverage` into its own target directory, runs the whole +# suite again to emit .profraw files, and merges those into the summary. +# Running the tests IS how it collects coverage. +# +# So the two do the same work twice no matter what, and the only question +# is whether they do it in series or in parallel. As consecutive steps in +# one job the wall time was their sum -- fifteen to nineteen minutes. As +# separate jobs it is the slower of the two, and the plain `cargo test` +# result comes back in a third of that instead of waiting behind the +# instrumented rebuild. + on: push: branches: [main] @@ -11,30 +28,85 @@ env: jobs: test: + name: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - with: - components: llvm-tools-preview - - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - name: Build - run: cargo build --verbose + # Swatinem/rust-cache rather than a hand-rolled actions/cache, which + # is what this job used to do and which cached nothing. The crate has + # no dependencies -- Cargo.lock holds exactly one package, itself -- + # so ~/.cargo/registry and ~/.cargo/git are empty, and a key of + # hashFiles('**/Cargo.lock') never changes, so after the first save + # the cache was restored stale on every run and never written again. + # This one keys on the compiler version and the job as well, and + # saves each run. + - uses: Swatinem/rust-cache@v2 - name: Test run: cargo test --verbose + # The README's Quick start section IS this example, so running it here + # is what stops the front page of the repository from drifting out of + # date. Its assertions are the check; the printed values are for a + # human reading the log. + - name: Check the README example + run: cargo run --example readme_quickstart + + # docs/GUIDE.md is written around these four files and quotes their + # real output, so running them is what keeps the guide honest. Each + # one asserts its own results; the printing is for a human reading + # the log. + - name: Check the guide examples + run: | + cargo run --example guide_02_orbit + cargo run --example guide_03_signal + cargo run --example guide_04_fem + cargo run --example guide_05_correctness + + # Rustdoc warnings are rendering bugs, not style. `[k]` in a formula + # becomes a broken intra-doc link and `` becomes an unclosed + # HTML tag that swallows the rest of the line, so the published docs + # show something other than what the comment says. There were 81 of + # these; denying them keeps the count at zero. + - name: Documentation + run: cargo doc --no-deps + env: + RUSTDOCFLAGS: "-D warnings" + + # docs/MODULE_MAP.md is generated from the source tree, so it can go + # stale the moment a module is added, renamed or resized. This + # re-derives it and fails if the committed copy differs, which is the + # only thing that keeps a generated file honest. + - name: Module map is current + run: python3 tools/gen_module_map.py --check + + # Every module carries a //! summary, and the map is built from those + # first sentences -- a module without one would appear in the map as a + # blank row. + - name: Every module is documented + run: python3 tools/check_module_docs.py + + coverage: + name: Coverage + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: llvm-tools-preview + + # A separate cache key from the `test` job, which is the point of + # keying on the job: these artifacts are built with + # -C instrument-coverage and cargo fingerprints them separately, so + # sharing one cache between the two would thrash it. + - uses: Swatinem/rust-cache@v2 + - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index a50dd4f..58d4155 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -91,11 +91,11 @@ jobs: # core::, the interval and dual-number arithmetic where index and slice # reasoning is densest, rather than to the whole suite. # - # Five tests in there carry #[cfg_attr(miri, ignore)]. Miri evaluates + # Six tests in there carry #[cfg_attr(miri, ignore)]. Miri evaluates # sin, exp and powi with its own implementations rather than the host's, # and deliberately randomises the result within the slack the language # allows, so a test asserting an exact float value fails under Miri - # whatever the code does. Those five are exactness assertions and are + # whatever the code does. Those six are exactness assertions and are # skipped here; they run everywhere else. # # A libtest filter is a substring match, not a path prefix, so a bare diff --git a/README.md b/README.md index b46597b..ef7d1b4 100644 --- a/README.md +++ b/README.md @@ -4,152 +4,928 @@

CI - Coverage - Tests + Verify + Coverage + Tests + Kani License: MIT Rust Zero Dependencies

-A comprehensive, zero-dependency Rust library for physics, mathematics, and engineering computation. Every public function validates its inputs, every formula is tested against known values, and the entire codebase sits at 99.98% line coverage across 1,659 tests. - -## What's in it - -### Classical & Continuum Mechanics -- **`classical`** — Newtonian mechanics: projectile motion, collisions, SHM, damping, resonance -- **`solid_mechanics`** — Stress, strain, elastic moduli, beam deflection, Mohr's circle -- **`continuum_mechanics`** — 3D Hooke's law, compliance matrices, plane stress/strain -- **`fluid_instabilities`** — Rayleigh-Taylor, Kelvin-Helmholtz, Jeans instability, Plateau-Rayleigh - -### Thermodynamics & Statistical Mechanics -- **`thermodynamics`** — Ideal gas, Carnot, entropy, heat conduction, radiation, Nusselt/Biot/Grashof -- **`statistical_mechanics`** — Maxwell-Boltzmann, Boltzmann/Einstein/Debye models, diffusion, partition functions - -### Electromagnetism & Electronics -- **`electromagnetism`** — Coulomb, Lorentz, Faraday, Maxwell, RLC circuits, transformers -- **`electronics`** — Semiconductors, diodes, MOSFETs, solar cells, PN junctions -- **`rf`** — Friis, skin depth, antenna gain, impedance, VSWR, Smith chart quantities -- **`photonics`** — Gaussian beams, fiber optics, ray transfer matrices, coherence, Fabry-Perot - -### Waves, Optics & Acoustics -- **`waves`** — Doppler, standing waves, diffraction, Snell, seismic waves, dispersion -- **`optics`** — Lenses, mirrors, thin films, diffraction gratings, Rayleigh resolution -- **`acoustics`** — Sabine/Eyring reverberation, psychoacoustic scales (mel, bark, ERB), room modes, STC -- **`signal_processing`** — Waveform generation, FIR/IIR filters, convolution, windowing, resampling - -### Relativity & Quantum -- **`relativity`** — Lorentz transformations, relativistic energy-momentum, time dilation, Doppler -- **`general_relativity`** — Schwarzschild metric, geodesics, frame dragging, cosmological distances -- **`quantum`** — De Broglie, uncertainty principle, particle-in-a-box, tunneling, Planck radiation -- **`particle_physics`** — Invariant mass, Rutherford scattering, Breit-Wigner, rapidity, Lorentz boosts - -### Nuclear & Radiation -- **`nuclear`** — Decay chains, binding energy, Q-values, dosimetry -- **`neutronics`** — Criticality, diffusion, moderation, burnup, shielding -- **`radiation`** — Blackbody, Wien, Planck, radiative transfer, view factors -- **`plasma`** — Debye length, cyclotron/plasma frequencies, Alfven speed, beta, Larmor radius - -### Astrophysics -- **`astrophysics::nbody`** — N-body gravitational simulation (leapfrog integrator) -- **`astrophysics::octree`** — Barnes-Hut tree for O(N log N) force computation -- **`astrophysics::orbital_elements`** — Keplerian elements from state vectors, orbit propagation -- **`astrophysics::gravitational_waves`** — Strain, luminosity, frequency, chirp mass -- **`astrophysics::tidal`** — Tidal forces, Roche limits, tidal tensors -- **`astrophysics::lagrange`** — L1–L5 Lagrange point computation -- **`astrophysics::habitable_zone`** — Habitable zone boundaries, tidal locking -- **`astrophysics::magnetosphere`** — Dipole fields, magnetopause radius, field line tracing -- **`astrophysics::collisions`** — Impact cratering, orbital debris, collision probabilities - -### Fluids & Propulsion -- **`fluids`** — Bernoulli, Poiseuille, Reynolds, drag, capillarity, compressible flow -- **`propulsion`** — Tsiolkovsky rocket equation, Hohmann transfers, nozzle design, staging -- **`magnetohydrodynamics`** — Alfven waves, Hartmann flow, magnetic reconnection, pinch equilibria - -### Chemistry & Biophysics -- **`chemistry`** — Arrhenius, Nernst, pH, electrochemistry, reaction kinetics -- **`biophysics`** — Nernst/Goldman potentials, Michaelis-Menten, Hill equation, hemodynamics - -### Mathematics & Numerical Methods -- **`math`** — `Vec3` type, physical constants (NIST CODATA), linear algebra primitives -- **`linalg`** — 3x3 matrices, rotations, eigenvalue decomposition, SVD-like operations -- **`quaternion`** — Quaternion algebra, slerp/nlerp, axis-angle, Euler angle conversions -- **`numerical`** — Root finding (bisection, Newton, secant), integration (Simpson, Gauss-Legendre), cubic splines -- **`optimization`** — Golden section, Brent, Nelder-Mead, simulated annealing, linear regression, polynomial fitting -- **`statistics`** — Mean, variance, median, distributions (Gaussian, Poisson, exponential), DFT, power spectrum -- **`monte_carlo`** — MC integration, Metropolis-Hastings, Ising model, Langevin dynamics, random walks -- **`vector_calculus`** — Gradient, divergence, curl, Laplacian, Poisson solver, line/surface/volume integrals -- **`nonlinear`** — Logistic map, Lorenz/Rossler attractors, Lyapunov exponents, bifurcation diagrams -- **`information_theory`** — Shannon entropy, mutual information, KL divergence, channel capacity - -### Geometry, Curves & Fractals -- **`geometry`** — Areas, volumes, perimeters for standard shapes, regular polygons -- **`curves`** — Conic sections, Bezier curves, arc length, curvature -- **`fractals`** — Mandelbrot, Julia, burning ship, Newton fractals, Barnsley fern, box counting -- **`trigonometry`** — Trig identities, hyperbolic functions, angle conversions, haversine - -### Simulation Engines -- **`sim::rigid_body`** — 3D rigid body dynamics with quaternion orientation, Euler equations, collision response -- **`sim::fluid_sim`** — Column fluid, 1D shallow water, 2D incompressible Euler (pressure projection) -- **`sim::heat_sim`** — 2D/3D heat conduction (explicit finite difference), convection-diffusion -- **`sim::wave_sim`** — 1D/2D wave equation solvers, absorbing boundary conditions (Mur ABC) -- **`sim::em_sim`** — 1D/2D FDTD electromagnetic simulation, PEC/Mur boundaries, dielectric media -- **`sim::cloth_sim`** — Verlet integration cloth/rope, spring-damper constraints, collision - -### Reference Data -- **`materials::elements`** — All 118 elements with atomic mass, density, melting/boiling points, thermal/electrical conductivity -- **`materials::common`** — Engineering materials (steel, aluminum, copper, etc.) -- **`materials::fluids`** — 16 common fluids with density, viscosity, surface tension, speed of sound -- **`materials::gases`** — Common gases with molar mass, specific heat ratio, thermal conductivity - -### Utilities -- **`units`** — SI unit conversions (temperature, pressure, energy, length, speed, angle, etc.) -- **`color_science`** — RGB/HSV/HSL/XYZ, wavelength-to-color, blackbody color, CIE color difference -- **`control_systems`** — Transfer functions, step/impulse response, PID tuning, stability margins -- **`atmosphere`** — ISA model, barometric formula, lapse rates, humidity, wind shear - -## Usage - -Add to your `Cargo.toml`: +A zero-dependency Rust library for physics, mathematics and engineering computation. + +The aim is not breadth for its own sake. Every routine here is written so that +something about it can be *checked* — against a closed form, against a +conservation law, against an independent implementation of the same quantity, or +against an exact identity over integers. A test that only asserts a function ran +is not evidence, and the test suite is built around that distinction. Where a +result is approximate the error has a stated bound; where it is exact the +assertion uses `==`. + +--- + +## At a glance + +| | | +|---|---| +| **Public functions and methods** | 6,365 (4,124 free functions, 2,241 methods) | +| **Public types** | 431 structs, enums and traits | +| **Top-level modules** | 71 public, across 296 source files — see the [module map](docs/MODULE_MAP.md) | +| **Source** | 266,122 lines of Rust | +| **Unit tests** | 4,193 | +| **Property tests** | 577, across 49 files | +| **Line coverage** | 97.89% (174,685 lines, 3,681 uncovered) | +| **Function coverage** | 99.33% (20,200 functions, 136 uncovered) | +| **Formal verification** | 20 Kani harnesses (13 in CI, 7 behind `kani-slow`) | +| **Undefined behaviour** | Miri-clean; the crate contains no `unsafe` | +| **API documentation** | every module carries a `//!` summary; `cargo doc` is warning-free, and CI denies rustdoc warnings | +| **Dependencies** | none — `Cargo.lock` holds exactly one package | +| **Edition** | 2021, `f64` throughout | + +--- + +## Install ```toml [dependencies] -rust_physics_engine = { path = "." } +rust_physics_engine = { git = "https://github.com/Magic-Man-us/RustPhysicsEngine" } ``` +## Quick start + +This snippet is [`examples/readme_quickstart.rs`](examples/readme_quickstart.rs), +compiled and run by CI, so it cannot drift out of date. + ```rust -use rust_physics_engine::classical::{projectile_range, kinetic_energy}; -use rust_physics_engine::math::constants::{G, C, K_B}; -use rust_physics_engine::thermodynamics::ideal_gas_pressure; -use rust_physics_engine::sim::rigid_body::RigidBody; +use rust_physics_engine::classical::projectile_range; +use rust_physics_engine::exact::rational::Rational; +use rust_physics_engine::math::constants::{C, G}; +use rust_physics_engine::units::quantity::{Dim, Quantity}; + +// Ballistics: v₀ = 50 m/s, θ = 45°, g = 9.81 m/s² +let range = projectile_range(50.0, std::f64::consts::FRAC_PI_4, 9.81); +assert!((range - 254.841_997_961).abs() < 1e-9); + +// Constants come from one table. A black hole's Schwarzschild radius: +let solar_mass = 1.989e30; +let r_s = 2.0 * G * solar_mass / (C * C); // about 2.95 km + +// Quantities carry their dimensions, and addition checks them. +let v = Quantity::new(3.0, Dim::new(1, 0, -1, 0, 0, 0, 0)); // m/s +let t = Quantity::new(2.0, Dim::TIME); +let d = v.mul(&t).unwrap(); // 6 m — a length, exactly +assert!(v.add(&t).is_err()); // a velocity is not a time + +// Exact rational arithmetic over arbitrary-precision integers. +let third = Rational::from_i64(1, 3); +let one = third.mul(&Rational::from_i64(3, 1)); +assert_eq!(one, Rational::one()); // not 0.9999999999999999 +``` + +--- + +# What's in it + +Equations below are the ones the code actually implements, not a +representative sample of the field. + +## Numerical foundations + +**`core`** — the primitives everything else is allowed to rely on. + +- **`core::dual`** — forward-mode automatic differentiation. A dual number + `a + bε` with `ε² = 0` carries a value and its derivative through every + operation, so `f(x + ε)` returns `f(x) + f′(x)ε` with no step size and no + truncation error. +- **`core::interval`** — rigorous interval arithmetic with outward rounding. + Every operation returns an interval *guaranteed* to contain the true result. +- **`core::compensated`** — Kahan and Neumaier summation, and error-free + transformations (`two_sum`, `two_product`) that return a sum together with + its exact rounding error. + +``` +dual: (a + bε)(c + dε) = ac + (ad + bc)ε since ε² = 0 +interval: [a,b] · [c,d] = [min(ac,ad,bc,bd), max(ac,ad,bc,bd)] +two_sum: s = fl(a+b), e = (a − (s − b)) + (b − (s − b)), a + b = s + e exactly +``` + +**`math`** — the `Vec3` type and its algebra, and `math::constants`: the +single table of physical constants the rest of the crate refers back to. + +**`linalg`** — dense `Matrix`, LU with partial pivoting, Cholesky, QR by +Householder reflections, SVD by one-sided Jacobi, eigenvalue solvers, +tridiagonal (Thomas) solve, and CSR sparse matrices with conjugate gradient. + +**`numerical`** — quadrature (Simpson, Gauss–Legendre, adaptive, Romberg), +root finding (bisection, Newton, secant, Brent, polynomial roots), ODE +integrators (explicit RK, Dormand–Prince 5(4) adaptive, backward Euler and +BDF2 for stiff problems, symplectic for `x″ = a(x)`), interpolation and cubic +splines, and two-point boundary value problems. + +**`special`** — error function family, gamma family, beta and regularized +incomplete beta, Bessel functions of integer order, elliptic integrals, +exponential integrals, Legendre polynomials, associated Legendre functions and +real spherical harmonics. + +## Exact and symbolic computation + +**`exact`** — arithmetic without rounding. + +- **`bigint`** — arbitrary-precision signed integers, with Knuth's algorithm D + for division (including the rare add-back correction). +- **`rational`** — exact rationals over `BigInt`, always reduced with a + positive denominator. `from_f64_exact` gives the dyadic rational an `f64` + genuinely is. +- **`bigfloat`** — arbitrary-precision binary floating point. +- **`polynomial`** — dense univariate polynomials over `f64` and over + `Rational`. +- **`contfrac`** — continued fraction expansions, convergents, and the + periodic expansion of a quadratic irrational. +- **`symbolic`** — a small computer algebra system over expression trees: + a precedence-climbing parser, `Display` and LaTeX output, exact + differentiation, simplification and expansion, Taylor series, a stack-machine + compiler, table-driven integration, limits, gradients and Hessians. + +``` +Knuth D add-back: when the trial quotient digit q̂ overshoots, the partial + remainder goes negative and one addition of the divisor + corrects it — a branch taken for roughly 2 divisions in 10⁹ +``` + +## Discrete mathematics + +**`discrete`** + +- **`primes`** — three cross-checking sieves, deterministic Miller–Rabin over + `u64`, Baillie–PSW for `BigInt`, Pollard rho and p−1, Fermat, factorization, + and prime counting by the Lucy_Hedgehog recurrence. +- **`number_theory`** — CRT for general moduli, multiplicative functions, + primitive roots, discrete logarithms, Legendre and Jacobi symbols, + Tonelli–Shanks, Carmichael numbers, Gaussian integers, Frobenius, + Egyptian fractions, Zeckendorf representations, Diophantine solving. +- **`combinatorics`** — counting, enumeration, and the permutation group. +- **`partitions`** — integer partitions, Young diagrams, RSK correspondence. +- **`sequences`** — integer sequences, linear recurrences, generating + functions, Berlekamp–Massey. +- **`disjoint_set`** — union-find with path compression and union by size. + +``` +π(n) via φ(x, a) = φ(x, a−1) − φ(x/pₐ, a−1) O(√n) state + π(10⁹) = 50,847,534, computed in 87 ms in a debug build + +Baillie–PSW = strong Miller–Rabin base 2 ∧ strong Lucas (Selfridge params) + neither test's pseudoprimes below 20,000 are the other's +``` + +**`graph`** — `Graph` representation, structural queries, generators and +products; shortest paths (Dijkstra, Bellman–Ford, Floyd–Warshall, A*, Johnson), +spanning trees and tours; network flow (Dinic, push–relabel, min-cost flow) and +the problems that reduce to it; matchings (bipartite, general Blossom, +weighted, stable); spectral graph theory (Laplacians, centralities, effective +resistance); colouring, cliques, independent sets and covers; and force-directed +and spectral layout. + +``` +max-flow = min-cut +Laplacian L = D − A, eigenvalue 0 multiplicity = number of components +Cheeger: λ₂/2 ≤ h(G) ≤ √(2λ₂) +effective resistance R(u,v) = (eᵤ − eᵥ)ᵀ L⁺ (eᵤ − eᵥ) +``` + +**`codes`** — checksums and check digits (CRC, Luhn, Verhoeff, Damm, Fletcher, +Adler); binary linear block codes (Hamming, Golay, syndrome decoding); +Reed–Solomon and BCH over finite fields; convolutional and turbo codes with +Viterbi and BCJR, over BSC/AWGN channels; lossless compression (Huffman, +arithmetic coding, LZ77/LZW, BWT, move-to-front); and the arithmetic behind +public-key cryptography (modular exponentiation, RSA, Diffie–Hellman, elliptic +curves over prime fields, Shamir secret sharing) — for study, not for +production use. + +``` +Singleton bound: d ≤ n − k + 1, met with equality by Reed–Solomon (MDS) +Hamming bound: 2ᵏ · Σ_{i≤t} C(n,i) ≤ 2ⁿ +Shannon capacity: C = 1 − H₂(p) (BSC), C = ½log₂(1 + S/N) (AWGN) +``` + +## Classical and continuum mechanics + +**`classical`** — projectile motion, collisions, simple harmonic motion, +damping, resonance. +**`gravitation`** — Newtonian gravity, potential, escape and orbital velocity. +**`solid_mechanics`** — stress, strain, elastic moduli, beam deflection, +Mohr's circle. +**`continuum_mechanics`** — 3-D Hooke's law, compliance matrices, plane stress +and plane strain. +**`fluid_instabilities`** — Rayleigh–Taylor, Kelvin–Helmholtz, Jeans, +Plateau–Rayleigh. +**`geophysics`** — seismic and Earth-structure relations. + +``` +projectile range R = v₀² sin(2θ) / g +damped SHM m x″ + c x′ + k x = F(t), ζ = c / (2√(km)) +Hooke (3-D) σᵢⱼ = λ δᵢⱼ ε_kk + 2μ εᵢⱼ +Euler–Bernoulli EI · d⁴w/dx⁴ = q(x) +Jeans length λ_J = √(π c_s² / (G ρ)) +``` + +**`resonance`** — the damped oscillator in closed form and numerically; +coupled oscillators, normal modes and modal superposition; acoustic and +electrical cavities (RLC, Helmholtz); nonlinear resonance (Duffing, van der +Pol); and structural dynamics with finite-element bars and beams. + +## Thermodynamics and statistical mechanics + +**`thermodynamics`** — ideal gas, Carnot, entropy, heat conduction, radiation, +Nusselt/Biot/Grashof. + +**`statistical_mechanics`** — Maxwell–Boltzmann, Boltzmann/Einstein/Debye +models, diffusion and partition functions, plus: + +- **`ising`** — the Ising model and its relatives by Monte Carlo + (Metropolis, Wolff cluster, heat bath). +- **`lattice_models`** — percolation, random walks, growth models, avalanches. +- **`md`** — molecular dynamics: pair potentials, cell-list force evaluation, + thermostats, radial distribution functions. +- **`kinetics`** — chemical kinetics: rate laws, deterministic and stochastic + reaction networks (Gillespie), Michaelis–Menten, Eyring, Nernst. + +``` +partition function Z = Σ exp(−βEᵢ), ⟨E⟩ = −∂ln Z/∂β, F = −kT ln Z +Ising energy E = −J Σ⟨ij⟩ sᵢsⱼ − h Σᵢ sᵢ +Onsager (2-D) sinh(2J/kT_c) = 1 ⟹ kT_c/J = 2/ln(1+√2) ≈ 2.269 +Lennard-Jones V(r) = 4ε[(σ/r)¹² − (σ/r)⁶] +Arrhenius k = A exp(−Eₐ/RT) +Nernst E = E° − (RT/zF) ln Q +``` + +## Electromagnetism and electronics + +**`electromagnetism`** — Coulomb, Lorentz, Faraday, Maxwell, RLC circuits, +transformers. +**`electronics`** — semiconductors, diodes, MOSFETs, solar cells, PN junctions. +**`rf`** — Friis, skin depth, antenna gain, impedance, VSWR, Smith chart +quantities. +**`photonics`** — Gaussian beams, fibre optics, ray transfer matrices, +coherence, Fabry–Pérot. +**`plasma`** — Debye length, cyclotron and plasma frequencies, Alfvén speed, +beta, Larmor radius. +**`magnetohydrodynamics`** — Alfvén waves, Hartmann flow, magnetic +reconnection, pinch equilibria. + +``` +Maxwell ∇·E = ρ/ε₀ ∇·B = 0 ∇×E = −∂B/∂t ∇×B = μ₀J + μ₀ε₀ ∂E/∂t +Lorentz F = q(E + v × B) +skin depth δ = √(2ρ / (ωμ)) +Friis P_r/P_t = G_t G_r (λ / 4πR)² +plasma freq ω_p = √(n e² / (ε₀ mₑ)) +Alfvén v_A = B / √(μ₀ ρ) +``` + +## Waves, optics and acoustics + +**`waves`** — Doppler, standing waves, diffraction, Snell, seismic waves, +dispersion. +**`optics`** — lenses, mirrors, thin films, diffraction gratings, Rayleigh +resolution. +**`acoustics`** — Sabine and Eyring reverberation, psychoacoustic scales (mel, +bark, ERB), room modes, STC. + +``` +Snell n₁ sin θ₁ = n₂ sin θ₂ +thin lens 1/f = 1/dₒ + 1/dᵢ +Rayleigh θ = 1.22 λ/D +Sabine RT₆₀ = 0.161 V / A +mel m = 2595 log₁₀(1 + f/700) +``` + +## Signal processing and transforms + +**`transforms`** + +- **`fft`** — fast Fourier transforms at *any* length: radix-2 and mixed-radix + for composite sizes, Bluestein's chirp-z for prime ones. +- **`dct`** — discrete cosine, sine and Hartley transforms. +- **`stft`** — short-time Fourier transform, spectrograms, Goertzel, chirp-z. +- **`wavelet`** — discrete and continuous wavelet transforms, with canonical + orthogonal and biorthogonal scaling-filter tables (Daubechies, Symlet, + Coiflet, Biorthogonal). +- **`hilbert`** — Hilbert transform, analytic signals, modulation, empirical + mode decomposition. +- **`laplace`** — numerical inverse Laplace transforms (fixed-Talbot, + Gaver–Stehfest). +- **`radon`** — Radon transform and filtered back-projection, plus Hankel and + Abel transforms. +- **`spectral`** — periodogram, Welch averaging, multitaper (DPSS), Lomb–Scargle + for unevenly sampled data. + +**`dsp`** — window functions; FIR design (windowed-sinc, Parks–McClellan, +least-squares) and application; IIR filters (RBJ biquads, second-order-section +cascades, Butterworth/Chebyshev/elliptic); sample-rate conversion (integer, +polyphase rational, arbitrary); and phase tools (1-D and Itoh 2-D unwrapping, +phase-locked loops). + +**`signal_processing`** — waveform generation, convolution, correlation. + +``` +DFT X[k] = Σₙ x[n] e^(−2πikn/N) +Parseval Σ|x[n]|² = (1/N) Σ|X[k]|² +Bluestein X[k] = conj(chirp) · ( (x·chirp) ⊛ chirp ) any N +biquad (RBJ) H(z) = (b₀ + b₁z⁻¹ + b₂z⁻²) / (a₀ + a₁z⁻¹ + a₂z⁻²) +Lomb–Scargle periodogram for non-uniform sampling, exact for a pure tone +``` + +## Audio + +**`audio`** — PolyBLEP anti-aliased oscillators and test signals; envelopes, +LFOs, followers and glides; additive, FM (DX7-style operator routing), granular +and wavetable synthesis; physical modelling (digital waveguides for plucked, +struck and bowed strings, modal resonators); effects (delays, Schroeder and +Freeverb reverbs, feedback delay networks, chorus, distortion, dynamics); +analysis (YIN, autocorrelation, cepstral and HPS pitch detection, onset +detection, MFCC); a phase vocoder for time stretching and pitch shifting; +musical tuning (temperaments, interval arithmetic, Scala file parsing); spatial +audio (panning laws, VBAP, ambisonics, binaural cues); and WAV (RIFF) reading +and writing for PCM 8/16/24/32-bit and IEEE float. + +``` +PolyBLEP corrects the discontinuity at a hard edge by subtracting a + polynomial approximation to the band-limited step +YIN d′(τ) = d(τ) / [(1/τ) Σ_{j≤τ} d(j)] cumulative mean normalization +equal temp fₙ = f₀ · 2^(n/12); cents = 1200 log₂(f₂/f₁) +``` + +## Fluids and computational fluid dynamics + +**`fluids`** — Bernoulli, Poiseuille, Reynolds, drag, capillarity, compressible +flow. +**`propulsion`** — Tsiolkovsky, Hohmann transfers, nozzle design, staging. + +**`cfd`** — staggered (MAC) grids and cell-centred scalar fields; advection +schemes (upwind, Lax–Wendroff, QUICK, MUSCL, WENO); a stable-fluids +incompressible solver with MacCormack advection and pressure projection; exact +and approximate Riemann solvers for the compressible Euler equations (HLL, +HLLC, Roe); well-balanced shallow water; smoothed-particle hydrodynamics; +lattice Boltzmann (D2Q9 with BGK/TRT/MRT collision); level sets for interface +capturing with WENO advection and Sussman reinitialization; potential flow with +complex-variable methods; Blasius and Falkner–Skan boundary layers; turbulence +modelling and statistics; regularized Biot–Savart vortex methods in 2-D and +3-D; Darcy and unsaturated porous-media flow; and multiphase drift-flux +correlations. + +``` +Navier–Stokes ∂u/∂t + (u·∇)u = −∇p/ρ + ν∇²u + f, ∇·u = 0 +Reynolds Re = ρUL/μ +Bernoulli p + ½ρv² + ρgh = const +Euler (1-D) ∂/∂t[ρ, ρu, E] + ∂/∂x[ρu, ρu²+p, u(E+p)] = 0 +CFL Δt ≤ CFL · Δx / max|λ| +lattice Boltzmann fᵢ(x+cᵢΔt, t+Δt) − fᵢ(x,t) = −(1/τ)(fᵢ − fᵢ^eq) +Blasius 2f‴ + f f″ = 0, δ/x = 5.0/√Re_x, c_f = 0.664/√Re_x +``` + +## Relativity, quantum and particle physics + +**`relativity`** — Lorentz transformations, relativistic energy–momentum, time +dilation, Doppler. +**`general_relativity`** — Schwarzschild metric, geodesics, frame dragging, +cosmological distances. +**`particle_physics`** — invariant mass, Rutherford scattering, Breit–Wigner, +rapidity, Lorentz boosts. + +**`quantum`** — de Broglie, uncertainty, particle in a box, tunnelling, Planck +radiation, plus: + +- **`wavefunction`** — 1-D wavefunctions, the standard eigenstates, and + phase-space representations (Wigner, Husimi). +- **`schrodinger`** — stationary and time-dependent solvers: shooting, + Numerov, matrix diagonalization, split-operator and Crank–Nicolson + propagation. +- **`circuit`** — a state-vector quantum circuit simulator, with density + matrices and noise channels. +- **`algorithms`** — Deutsch–Jozsa, Grover, quantum Fourier transform, phase + estimation, Shor's order finding. +- **`spin`** — spin operators, quantum magnets, magnetic resonance. +- **`solid_state`** — bands, densities of states, transport, phonons. + +``` +Schrödinger iħ ∂ψ/∂t = −(ħ²/2m)∇²ψ + Vψ +box eigenvalues Eₙ = n²π²ħ²/(2mL²) +uncertainty Δx Δp ≥ ħ/2 +Schwarzschild ds² = −(1−r_s/r)c²dt² + (1−r_s/r)⁻¹dr² + r²dΩ², r_s = 2GM/c² +invariant mass m²c⁴ = E² − (pc)² +Grover ~ (π/4)√N iterations +``` + +## Nuclear and radiation + +**`nuclear`** — decay chains, binding energy, Q-values, dosimetry. +**`neutronics`** — criticality, diffusion, moderation, burnup, shielding. +**`radiation`** — blackbody, Wien, Planck, radiative transfer, view factors. -// Projectile on Earth -let range = projectile_range(50.0, 0.7854, 9.81); // v₀=50 m/s, θ=45°, g=9.81 +``` +decay N(t) = N₀ e^(−λt), t½ = ln2/λ +semi-empirical B = aᵥA − a_sA^(2/3) − a_c Z²/A^(1/3) − a_a(A−2Z)²/A ± δ +four-factor k_∞ = η f p ε +Planck B(λ,T) = (2hc²/λ⁵) / (exp(hc/λkT) − 1) +Wien λ_max T = 2.897771955×10⁻³ m·K +Stefan–Boltzmann j = σT⁴, σ = 2π⁵k⁴/(15h³c²) +``` + +## Astrophysics and orbital mechanics + +**`astrophysics`** — N-body simulation with a leapfrog integrator; Barnes–Hut +octree for O(N log N) forces; Keplerian elements from state vectors and orbit +propagation; gravitational-wave strain, luminosity, frequency and chirp mass; +tidal forces, Roche limits and tidal tensors; L1–L5 Lagrange points; habitable +zone boundaries and tidal locking; dipole magnetospheres and field-line +tracing; impact cratering and collision probabilities; plus: + +- **`kepler`** — Kepler's equation solved to a residual below 1e-12 including + e = 0.99, for elliptic, parabolic and hyperbolic orbits. +- **`maneuvers`** — Hohmann and bi-elliptic transfers, plane changes, phasing, + J2 secular rates. +- **`lambert`** — Lambert's problem: the transfer orbit between two positions + in a given time. +- **`time_systems`** — Julian dates, UT1/TAI/TT/TDB, sidereal time, ΔT. +- **`coords`** — equatorial, ecliptic, galactic, horizontal and ITRF frames, + precession and nutation. + +``` +Kepler M = E − e sin E (elliptic) + M = e sinh H − H (hyperbolic) +vis-viva v² = μ(2/r − 1/a) +Hohmann Δv₁ = √(μ/r₁)(√(2r₂/(r₁+r₂)) − 1) +J2 nodal drift Ω̇ = −(3/2) J₂ (R/p)² n cos i sun-synchronous at 700 km: i = 98.2° +chirp mass ℳ = (m₁m₂)^(3/5) / (m₁+m₂)^(1/5) +Roche limit d = 2.44 R (ρ_M/ρ_m)^(1/3) +J2000 JD of 2000-01-01 12:00 TT = 2451545.0 +``` + +## PDE solvers: finite elements, FDTD and spectral + +**`fem`** — three ways of turning a differential equation into a linear system, +kept together because the interesting content is how they differ. + +- **`fem1d`** — one-dimensional finite elements for `−(p u′)′ + q u = f`, with + P1 and P2 elements, Dirichlet/Neumann/Robin boundary conditions, and L², H¹ + and energy-norm error computation. +- **`fem2d`** — triangular elements in the plane: Poisson, reaction–diffusion, + Helmholtz, drum eigenvalues and eigenmodes, plane-stress elasticity with + strain, stress and von Mises recovery, and transient heat. +- **`fdtd`** — Maxwell's equations on a Yee grid: 1-D and 2-D TM, Berenger + split-field PML with polynomial grading, Mur absorbing boundaries, photonic + crystal band gaps, and waveguide cutoff. +- **`spectral_pde`** — Chebyshev differentiation matrices and collocation + BVPs, Fourier spectral solvers for periodic problems. + +The finite element method is the one that gives an *optimality* statement +rather than an error estimate. Galerkin orthogonality makes the discrete +solution the exact energy-norm projection of the true one, so the error obeys a +Pythagoras identity — an equality, which cannot hold by accident: + +``` +Galerkin a(u − u_h, v_h) = 0 for every v_h in the space +Pythagoras ‖u − v_h‖²_a = ‖u − u_h‖²_a + ‖u_h − v_h‖²_a +convergence P1: O(h²) in L², O(h) in H¹; P2: O(h³) in L², O(h²) in H¹ +cotangent K_ij = −½(cot α + cot β) Delaunay ⟹ M-matrix +Rayleigh–Ritz discrete eigenvalues bound the true ones from above + +FDTD (1-D) E^(n+1) = E^n − (Δt/εΔx)(H^(n+½)_{i+½} − H^(n+½)_{i−½}) +leapfrog energy U^n = ½Σ εᵣ(E^n)² + ½Σ H^(n−½)H^(n+½) conserved exactly +Courant S = cΔt/Δx ≤ 1/√d, set by the *fastest* medium (min εᵣ) +magic time step S = 1 in 1-D is an exact shift — zero dispersion error +PML grading σ_max = −(m+1) S ln(R₀) / (2D) +waveguide cutoff ω_c = (2/S) arcsin(S sin(k_y/2)) below mπ/a by (k_y/2)²(1−S²)/6 + +Chebyshev exact on polynomials up to degree N; the diagonal of the + differentiation matrix follows from the negative sum trick +``` + +## Chemistry and biophysics + +**`chemistry`** — Arrhenius, Nernst, pH, electrochemistry, reaction kinetics. + +**`biophysics`** — Nernst and Goldman potentials, Michaelis–Menten, Hill +equation, hemodynamics, plus: + +- **`epidemiology`** — SIR/SEIR/SIRS compartment models, their stochastic + counterparts, and the final-size relation. +- **`population`** — growth laws, Lotka–Volterra and competition models, + Hardy–Weinberg, drift, selection and coalescent theory. +- **`seq_align`** — Needleman–Wunsch, Smith–Waterman, affine gaps + (Gotoh), and elementary sequence analysis. +- **`phylo`** — distance methods (UPGMA, neighbour joining), character methods + (Fitch, Sankoff), and substitution models (Jukes–Cantor, Kimura). +- **`neuro`** — Hodgkin–Huxley, integrate-and-fire variants, spike trains, + synapses and small networks. + +``` +Michaelis–Menten v = V_max[S] / (K_m + [S]) +Hill θ = [L]ⁿ / (K_d + [L]ⁿ) +Goldman V_m = (RT/F) ln[ (P_K[K]ₒ + P_Na[Na]ₒ + P_Cl[Cl]ᵢ) + / (P_K[K]ᵢ + P_Na[Na]ᵢ + P_Cl[Cl]ₒ) ] +SIR S′ = −βSI, I′ = βSI − γI, R′ = γI, R₀ = β/γ +final size ln(S₀/S_∞) = R₀(1 − S_∞/N) +Hodgkin–Huxley C dV/dt = −ḡ_Na m³h(V−E_Na) − ḡ_K n⁴(V−E_K) − g_L(V−E_L) + I +Jukes–Cantor d = −(3/4) ln(1 − (4/3)p) +``` + +## Stochastic processes and time series + +**`stochastic`** + +- **`markov`** — finite Markov chains, stationary distributions, absorption, + and Markov chain Monte Carlo. +- **`hmm`** — hidden Markov models: forward–backward, Viterbi, Baum–Welch, + and particle filters. +- **`sde`** — stochastic differential equations: Euler–Maruyama, Milstein, + strong and weak convergence, geometric Brownian motion, + Ornstein–Uhlenbeck, fractional Brownian motion. +- **`point_process`** — Poisson, inhomogeneous, Hawkes and Cox processes. +- **`queueing`** — birth–death queues, Erlang B and C, networks. +- **`timeseries`** — autocorrelation, stationarity tests, ARMA fitting, + spectral estimation, Kalman filtering. +- **`rmt`** — random matrix theory: the classical ensembles, semicircle and + Marchenko–Pastur laws, level spacing. +- **`extreme`** — extreme value theory (GEV, GPD, block maxima, peaks over + threshold) and copulas. + +``` +Chapman–Kolmogorov P^(m+n) = P^m P^n +detailed balance π(i)P(i,j) = π(j)P(j,i) ⟹ π stationary +Itô dX = a(X,t)dt + b(X,t)dW +Euler–Maruyama strong order ½, weak order 1 +Milstein strong order 1 +Little's law L = λW +Erlang B B(c,a) = (aᶜ/c!) / Σ_{k≤c} (aᵏ/k!) +semicircle ρ(x) = (1/2π)√(4 − x²) on [−2, 2] +Marchenko–Pastur support [(1−√λ)², (1+√λ)²], λ = p/n +``` + +## Optimization and operations research + +**`optimization`** + +- **`lp`** — the simplex method, interior point methods, duality and + sensitivity analysis. +- **`integer`** — branch and bound, cutting planes, dynamic programming, + knapsack, TSP, combinatorial search. +- **`network`** — project planning (CPM/PERT), flows on networks, scheduling. +- **`convex`** — gradient and accelerated gradient methods, L-BFGS, proximal + operators, ADMM, projections. +- **`metaheuristics`** — simulated annealing, genetic algorithms, particle + swarm, differential evolution, CMA-ES, Bayesian optimization, and the + standard benchmark functions. +- **`game_theory`** — Nash and correlated equilibria, evolutionary dynamics, + Shapley value, the core, auctions and matching. +- **`least_squares`** — Levenberg–Marquardt for nonlinear least squares. + +Plus golden section, Brent, Nelder–Mead, linear regression and polynomial +fitting at the module root. + +``` +LP duality max cᵀx s.t. Ax ≤ b, x ≥ 0 ≡ min bᵀy s.t. Aᵀy ≥ c, y ≥ 0 +complementary xⱼ(Aᵀy − c)ⱼ = 0 and yᵢ(b − Ax)ᵢ = 0 at optimality +KKT ∇f + Σλᵢ∇gᵢ + Σμⱼ∇hⱼ = 0, λᵢgᵢ = 0, λᵢ ≥ 0 +Nesterov O(1/k²) for smooth convex, against O(1/k) for plain descent +Shapley φᵢ = Σ_S |S|!(n−|S|−1)!/n! · [v(S∪{i}) − v(S)] +``` + +## Machine learning + +**`learn`** — written to be read rather than to be fast, and every method has +an exactly checkable property attached, because that is what makes a learning +algorithm testable at all. + +- **`nn`** — feed-forward networks trained by backpropagation, with a + numerical gradient check as the definitive test, plus 2-D convolution. +- **`gp`** — Gaussian process regression: fitting, prediction, log marginal + likelihood, hyperparameter optimization, posterior sampling. +- **`cluster`** — k-means with k-means++ initialization and restarts, DBSCAN, + hierarchical agglomerative clustering, Gaussian mixture EM, silhouette, + adjusted Rand index, Davies–Bouldin, and k-nearest-neighbour + classification and regression. +- **`tree`** — decision trees, regression trees, feature importance, random + forests, gradient boosting. + +``` +backprop reverse-mode differentiation — so a finite-difference check + settles whether the gradients are right, and nothing else does +softmax + CE ∂L/∂z = p − y exactly, at the logits +GP posterior μ* = K*ᵀ(K + σ²I)⁻¹y, Σ* = K** − K*ᵀ(K + σ²I)⁻¹K* +log marginal log p(y) = −½yᵀK⁻¹y − ½log|K| − (n/2)log 2π +k-means Lloyd's algorithm decreases inertia monotonically +EM increases the log likelihood monotonically +tree depth d ⟹ at most 2^d leaves ⟹ at most 2^d distinct predictions +ARI corrected for chance: expected value 0 for a random labelling +``` + +## Quantitative finance + +**`finance`** + +- **`options`** — Black–Scholes closed forms and Greeks, binomial and + trinomial lattices, Monte Carlo with variance reduction, Longstaff–Schwartz + for American options, and a Crank–Nicolson PDE solver. +- **`rates`** — discounting, bond pricing, duration and convexity, curve + bootstrapping, and short-rate models (Vasicek, CIR, Hull–White). +- **`portfolio`** — mean–variance optimization, the efficient frontier, + CAPM, and performance measurement. +- **`risk`** — value at risk, expected shortfall, and backtesting. + +``` +Black–Scholes C = S N(d₁) − K e^(−rT) N(d₂) + d₁ = [ln(S/K) + (r + σ²/2)T] / (σ√T), d₂ = d₁ − σ√T +put–call parity C − P = S − K e^(−rT) holds to 1e-12 +binomial → BS error O(1/n) +Macaulay duration D = Σ t·CF_t·e^(−rt) / P, ΔP/P ≈ −D·Δy +Vasicek dr = a(b − r)dt + σdW +VaR / ES ES_α = E[X | X ≤ VaR_α] — coherent where VaR is not +``` -// Ideal gas -let p = ideal_gas_pressure(2.0, 8.314, 300.0, 0.05); // n, R, T, V +## Geometry, manifolds and topology + +**`geometry`** — areas, volumes, perimeters, regular polygons. +**`curves`** — conic sections, Bézier curves, arc length, curvature. +**`trigonometry`** — identities, hyperbolic functions, angle conversion, +haversine. +**`quaternion`** — quaternion algebra, slerp and nlerp, axis–angle, Euler +conversions. +**`vector_calculus`** — gradient, divergence, curl, Laplacian, a Poisson +solver, and line, surface and volume integrals. + +**`manifold`** — geometry beyond three dimensions. + +- **`vecn`** — n-dimensional vectors and arbitrary-rank tensors. +- **`metric`** — Riemannian metrics, Christoffel symbols, curvature tensors. +- **`geodesic`** — geodesics, parallel transport, Jacobi fields, relativistic + orbits. +- **`lie`** — Lie groups and algebras: rotation and rigid-motion groups in 2, + 3 and 4 dimensions, exponential and logarithm maps. +- **`hyperbolic`** — the Poincaré disk and ball, upper half-space, hyperboloid + and Klein models, and the maps between them. +- **`spherical`** — n-sphere maps, spherical trigonometry, map projections. +- **`polytope4`** — the six regular 4-polytopes with their full symmetry + groups, Schlegel diagrams and cross sections. +- **`clifford`** — Clifford (geometric) algebras Cl(p, q, r) with a dense + multivector type. +- **`dec`** — discrete exterior calculus on triangle meshes. +- **`embedding`** — manifold learning: spectral embeddings, MDS, Isomap, LLE, + diffusion maps. +- **`spacetime`** — four-vectors, Lorentz transforms, and curved-spacetime + metrics. + +``` +Christoffel Γᵏᵢⱼ = ½gᵏˡ(∂ᵢgⱼˡ + ∂ⱼgᵢˡ − ∂ˡgᵢⱼ) +geodesic ẍᵏ + Γᵏᵢⱼ ẋⁱẋʲ = 0 +Riemann R^ρ_σμν = ∂_μΓ^ρ_νσ − ∂_νΓ^ρ_μσ + Γ^ρ_μλΓ^λ_νσ − Γ^ρ_νλΓ^λ_μσ +Gauss–Bonnet ∫K dA + ∮k_g ds = 2πχ +geometric product ab = a·b + a∧b +hyperbolic area for a triangle, A = π − (α + β + γ) +Euler characteristic V − E + F = 2 for every convex polyhedron +``` + +**`spatial`** — bounding volume hierarchies, k-d trees, quadtrees and octrees; +orientation predicates and containment tests; closest-point and set-distance +queries; intersection tests; rigid coordinate frames; 4×4 homogeneous +transforms and 2-D affine transforms; 2-D projective geometry with cross +ratios; and signed distance fields with primitives, combinators and domain +operators. + +**`mesh`** — indexed triangle meshes: construction, mass properties, cleanup, +topology analysis (manifoldness, orientation, boundary, genus), procedural +generation with watertight closed shapes, subdivision surfaces (Loop, +Catmull–Clark, √3, midpoint), parameterization, isosurface and isocontour +extraction, and parametric surfaces (Bézier, B-spline, NURBS). + +## Patterns, fractals and chaos + +**`fractals`** — escape-time fractals with smooth colouring (Mandelbrot, Julia, +burning ship, Newton); strange attractors (Lorenz, Rössler, and 2-D chaotic +maps); iterated function systems and the chaos game; Lindenmayer systems; +cellular automata and growth models; and coherent noise (Perlin, OpenSimplex2, +Worley, fBm). + +**`patterns`** — 2-D polygon algorithms (triangulation, simplification, +offsetting, boolean operations); Poisson-disk and low-discrepancy sampling +(Bridson, Halton, Sobol); Platonic, Archimedean, Catalan, Johnson and Goldberg +polyhedra; aperiodic tilings (Penrose P2 and P3 by substitution); circle and +sphere packings (Descartes, Apollonian, lattice); phyllotaxis and spirals; +space-filling curves (Hilbert, Morton, Peano); knots and space curves with +Frenet frames; and the 17 wallpaper groups and 7 frieze groups. + +**`nonlinear`** — logistic map, Lorenz and Rössler attractors, Lyapunov +exponents, bifurcation diagrams. + +**`information_theory`** — Shannon entropy, mutual information, KL divergence, +channel capacity. -// Rigid body simulation -let mut body = RigidBody::new_sphere(10.0, 0.5); // mass=10 kg, radius=0.5 m -body.apply_force(rust_physics_engine::math::Vec3::new(0.0, -98.1, 0.0)); -body.step(0.01); ``` +Mandelbrot z ↦ z² + c, escape when |z| > 2 +Feigenbaum δ = 4.669201609…, α = 2.502907875… +Lyapunov λ = lim (1/n) Σ ln|f′(xᵢ)|, λ > 0 ⟹ chaos +box counting D = lim log N(ε) / log(1/ε) +Descartes (k₁+k₂+k₃+k₄)² = 2(k₁²+k₂²+k₃²+k₄²) +golden angle 137.507764…° = 360°/φ² +Shannon H = −Σ pᵢ log₂ pᵢ +``` + +## Units, dimensions and constants + +**`units`** — SI conversions for temperature, pressure, energy, length, speed, +angle and more, plus: + +- **`quantity`** — `Dim`, seven signed-byte exponents for metre, kilogram, + second, ampere, kelvin, mole and candela; and `Quantity`, a value that + carries them. Addition checks that the exponents agree and refuses if they + do not, multiplication adds them, and a square root fails unless every one is + even. None of it is approximate. Also a unit parser (`"9.81 m/s^2"`, + `"3 kWh"`), SI prefix formatting, and the 2022 CODATA constants. +- **`dimensional`** — Buckingham's Π theorem computed as an exact null space + over `Rational`, the named dimensionless groups, natural units (ħ = c = 1), + the Planck scale, and `dimensional_check_formula`, which walks a symbolic + expression and refuses a sum of unlike terms or a sine of a length. + +``` +Buckingham n quantities, r independent dimensions ⟹ exactly n − r groups + a group is exactly in the null space or it is not — so the + computation is done over Rational, never in floating point +Reynolds Re = ρUL/μ — the one group of the pipe-flow problem +Planck length √(ħG/c³) = 1.616255×10⁻³⁵ m +Planck mass √(ħc/G) = 2.176434×10⁻⁸ kg +natural units [L] = [T] = [E]⁻¹, [M] = [E]; 1 kg = 5.6096×10³⁵ eV +transcendentals exp, sin and ln take a pure number — because their series add + x to x³, so exp(−t/τ) is meaningful and exp(−t) is not +``` + +Physical constants live in one table, `math::constants`. The values fixed by +the 2019 SI redefinition are exact; derived ones are computed from their +factors rather than transcribed, so `FARADAY == N_A * E_CHARGE` holds bit for +bit. A test pins the two constant tables together: the SI-exact constants must +agree exactly, and the measured ones to within 1e-8, which separates the +2018→2022 CODATA revision from a mistyped digit. + +## Reference data + +- **`materials::elements`** — all 118 elements with atomic mass, density, + melting and boiling points, and thermal and electrical conductivity. +- **`materials::common`** — engineering materials (steels, aluminium, copper…). +- **`materials::fluids`** — 16 fluids with density, viscosity, surface tension + and speed of sound. +- **`materials::gases`** — gases with molar mass, specific heat ratio and + thermal conductivity. + +## Simulation engines + +- **`sim::rigid_body`** — 3-D rigid body dynamics with quaternion orientation, + Euler's equations, and collision response. +- **`sim::fluid_sim`** — column fluid, 1-D shallow water, 2-D incompressible + Euler with pressure projection. +- **`sim::heat_sim`** — 2-D and 3-D heat conduction, convection–diffusion. +- **`sim::wave_sim`** — 1-D and 2-D wave equations with Mur absorbing + boundaries. +- **`sim::em_sim`** — 1-D and 2-D FDTD with PEC and Mur boundaries and + dielectric media. +- **`sim::cloth_sim`** — Verlet cloth and rope with spring–damper constraints. + +## Utilities + +- **`color_science`** — RGB/HSV/HSL/XYZ, wavelength to colour, blackbody + colour, CIE colour difference. +- **`control_systems`** — transfer functions, step and impulse response, PID + tuning, stability margins. +- **`atmosphere`** — the ISA model, barometric formula, lapse rates, humidity, + wind shear. +- **`monte_carlo`** — Monte Carlo integration, Metropolis–Hastings, Langevin + dynamics, random walks, and an `Rng`. +- **`statistics`** — descriptive measures, error propagation, distributions, + hypothesis tests and confidence intervals, resampling (bootstrap, BCa, + permutation), and DFT utilities. +- **`fields`** — uniform-grid scalar fields. +- **`error`** — the error types the numerical solvers share. + +> **A note on `monte_carlo::Rng`.** It is a plain linear congruential +> generator that returns its raw state, so the low bits have a short period: +> `next_u64() % m` for a power-of-two `m` cycles through a handful of values. +> Use `Rng::below(n)`, which takes the high bits, for any small-integer draw. + +--- + +# How it's tested + +Four independent mechanisms, because they fail in different ways. + +### Unit tests — 4,193 + +Every one asserts something checkable: a closed form, a conservation law, a +known reference value, or an exact identity. Approximate results carry a stated +tolerance derived from the method's error term, not one tuned until the test +passed. + +### Property tests — 577, across 49 files + +Randomized tests over invariants that must hold for *every* input, not for a +chosen example. They are what catch the cases nobody thought to write down: +round-trips (transform then invert), algebraic laws (multiplying dimensions +adds their exponents, exactly), conservation (leapfrog FDTD energy), and +agreement between two independent implementations of the same quantity. + +### Formal verification — 20 Kani harnesses + +Kani model-checks with CBMC: for a bounded input domain it proves absence of +panics, overflow and division by zero, rather than sampling. Thirteen run in +CI; seven that CBMC cannot decide in a CI-sized budget sit behind the +`kani-slow` feature, with the measured times recorded in +`src/verification/mod.rs`. Asserting panic-freedom lands in well under a +minute; asserting a numeric relation between symbolic float expressions +exceeds five, because CBMC must bit-blast the full mantissa of every +intermediate. + +### Miri + +The crate contains no `unsafe`, so Miri is a backstop rather than the primary +check. It runs against `core::` — the interval and dual-number arithmetic, +where index and slice reasoning is densest — under +`-Zmiri-strict-provenance`. + +### Coverage — 97.89% of lines, 99.33% of functions + +Measured by `cargo llvm-cov` on every push. + +### Why the coverage number is not the point + +Coverage says a line ran, not that anything checked what it did. Some of the +worst gaps this project has found were in lines with full coverage: + +- **The strong Lucas test** — the second half of Baillie–PSW — was replaced + wholesale with `return true`, and the entire suite stayed green. Composites + are rejected by Miller–Rabin first, so the Lucas branch is essentially never + reached in practice. It is now tested directly against the strong Lucas + pseudoprimes below 20,000 (5459, 5777, 10877, 16109, 18971), computed + independently rather than read off the implementation. +- **Knuth's add-back correction** in `BigInt` division, taken for roughly two + divisions in a billion. +- **The Lentz convergence threshold** in the continued-fraction evaluators. + +Each was found by mutating the code and observing that no test noticed. + +--- ## Design -- **Zero dependencies** — pure Rust, no external crates -- **`f64` throughout** — double precision for all computation -- **Input validation** — every function asserts valid inputs (positive mass, non-zero denominators, physical bounds) -- **NIST constants** — physical constants from CODATA 2018/2019 -- **99.98% line coverage** — 1,659 tests across 67 source files +- **Zero dependencies.** `Cargo.lock` holds exactly one package: this crate. +- **`f64` throughout**, except where exactness is the point — `exact` works + over arbitrary-precision integers and rationals, and `units::dimensional` + computes null spaces over `Rational` because a group is exactly + dimensionless or it is not. +- **Input validation.** Public functions validate their inputs: positive mass, + non-zero denominators, physical bounds. Solvers return `Result` rather than + panicking on non-convergence. +- **One table per constant.** Physical constants come from `math::constants`; + duplicates elsewhere are re-exports, and a test enforces the agreement. +- **Documented specification choices.** Where a definition is genuinely + ambiguous — the Frobenius number with a unit coin, Stern–Brocot indexing, + which parenthesization a unit string means — the reading is stated in the + doc comment rather than left implicit. -## Building & Testing +## Building and testing ```bash -cargo build # Build -cargo test # Run all 1,659 tests -cargo llvm-cov # Coverage report (requires cargo-llvm-cov) +cargo build # build +cargo test --lib # 4,193 unit tests +cargo test --release --test properties # 577 property tests +cargo clippy --all-targets -- -D warnings +cargo llvm-cov --summary-only # coverage (needs cargo-llvm-cov) +cargo kani # 13 harnesses (needs Kani) +cargo kani --features kani-slow # all 20, much slower +cargo miri test --lib -- core:: --skip ::core:: +cargo doc --no-deps --open # API documentation ``` +CI runs `test` and `coverage` as parallel jobs — the `test` job also runs the +README example and builds the documentation with `RUSTDOCFLAGS=-D warnings` — +and a separate `verify` workflow runs the property suite, Kani, Miri and a +strict Clippy pass. + +## Further reading + +- [`docs/GUIDE.md`](docs/GUIDE.md) — **start here.** A walk through the library + by doing things with it: putting a spacecraft in orbit, pulling a tone out of + noise, solving a differential equation and proving the answer converges at + the predicted rate, and the tools for not being wrong. Every code block is a + file in [`examples/`](examples) that CI compiles and runs, and the output + shown is what it actually prints. +- [`docs/MODULE_MAP.md`](docs/MODULE_MAP.md) — a generated map of every one of + the 295 modules: a size-annotated tree, tables by subject area, and a row per + module with its line count, public item counts and summary. Produced by + [`tools/gen_module_map.py`](tools/gen_module_map.py) from the sources, so + nothing in it is transcribed; CI fails if it is out of date. +- [`docs/ROADMAP_PART4.md`](docs/ROADMAP_PART4.md) — the specification the most + recent tranche of work was built against, with the function signatures and + the property each module had to satisfy. Marked complete. +- `cargo doc --no-deps --open` — the API documentation. The crate root carries + an orientation page; every module has a summary. + ## License MIT diff --git a/docs/GUIDE.md b/docs/GUIDE.md new file mode 100644 index 0000000..ff75697 --- /dev/null +++ b/docs/GUIDE.md @@ -0,0 +1,441 @@ +# Guide + +A walk through the library by doing things with it, rather than a list of +what it contains. For that list see [the module map](MODULE_MAP.md); for +the API reference run `cargo doc --no-deps --open`. + +Every code block below is a real file in [`examples/`](../examples), compiled +and run by CI. The output shown is what it actually prints. If a chapter +here describes something that does not work, CI fails. + +```bash +cargo run --example guide_02_orbit +cargo run --example guide_03_signal +cargo run --example guide_04_fem +cargo run --example guide_05_correctness +``` + +**Contents** + +1. [Getting your bearings](#1-getting-your-bearings) +2. [A spacecraft in orbit](#2-a-spacecraft-in-orbit) +3. [A tone buried in noise](#3-a-tone-buried-in-noise) +4. [Solving a differential equation](#4-solving-a-differential-equation) +5. [The tools for not being wrong](#5-the-tools-for-not-being-wrong) +6. [Where to look for things](#6-where-to-look-for-things) +7. [Things that will bite you](#7-things-that-will-bite-you) + +--- + +## 1. Getting your bearings + +Add it to `Cargo.toml`: + +```toml +[dependencies] +rust_physics_engine = { git = "https://github.com/Magic-Man-us/RustPhysicsEngine" } +``` + +There is nothing else to install. The crate has no dependencies — `Cargo.lock` +holds exactly one package, itself — so there is no feature matrix to learn and +no transitive tree to audit. + +Three conventions hold everywhere: + +- **SI units, angles in radians.** A function that wants something else says + so in its documentation. +- **`f64`**, except where exactness is the point. [`exact`] works over + arbitrary-precision integers and rationals. +- **Solvers return `Result`.** A solver that cannot converge tells you, rather + than returning a number that looks like an answer. + +The smallest useful thing: + +```rust +use rust_physics_engine::classical::projectile_range; + +// v₀ = 50 m/s, θ = 45°, g = 9.81 m/s² +let range = projectile_range(50.0, std::f64::consts::FRAC_PI_4, 9.81); +// 254.84 m +``` + +--- + +## 2. A spacecraft in orbit + +📄 [`examples/guide_02_orbit.rs`](../examples/guide_02_orbit.rs) + +Orbital mechanics never uses `G` and `M` separately — only their product, the +gravitational parameter μ. That is the first thing to internalise, because +every formula in [`astrophysics`] takes μ. + +```rust +let mu = G * EARTH_MASS; + +// A circular orbit 400 km up, near enough the ISS. +let r = EARTH_RADIUS + 400e3; +let speed = (mu / r).sqrt(); +let position = Vec3::new(r, 0.0, 0.0); +let velocity = Vec3::new(0.0, speed, 0.0); + +let elements = OrbitalElements::from_state_vectors(position, velocity, mu); +``` + +Going from a state vector to Keplerian elements is the first thing you do with +tracking data, because elements are what you can reason about — a position and +velocity tell you where something is, elements tell you what it is doing. + +``` +circular orbit at 400 km + speed 7673 m/s + semi-major 6771.0 km + eccentricity 0.00e0 + period 92.4 min + bound? true +``` + +Those are the real ISS numbers. A circular orbit has `e = 0` to within +rounding, and its period is Kepler's third law — both worth asserting rather +than eyeballing: + +```rust +assert!(elements.eccentricity < 1e-12); +let kepler = 2.0 * PI * (r.powi(3) / mu).sqrt(); +assert!((elements.period(mu) - kepler).abs() < 1e-6); +``` + +### Getting somewhere else + +A Hohmann transfer is two burns: one to enter an ellipse that touches both +circles, one to circularise at the far end. + +```rust +let (dv1, dv2) = hohmann_delta_v(mu, r, 42_164e3); // to geostationary +``` + +``` +Hohmann transfer to geostationary + burn 1 2399 m/s + burn 2 1457 m/s + total 3857 m/s + flight time 5.3 hours +``` + +The transfer ellipse touches both circles, so its semi-major axis is the mean +of the two radii, and half its period is the flight time. You can check the +whole thing closes with vis-viva, `v² = μ(2/r − 1/a)`: + +```rust +let a_transfer = 0.5 * (r + r_geo); +let v_peri = (mu * (2.0 / r - 1.0 / a_transfer)).sqrt(); +assert!((v_peri - (speed + dv1)).abs() < 1e-6); // burn 1 lands you on it +``` + +**Where to go next.** [`astrophysics::kepler`] solves Kepler's equation for +elliptic, parabolic and hyperbolic orbits including e = 0.99; +[`astrophysics::lambert`] finds the transfer connecting two positions in a +given time; [`astrophysics::maneuvers`] covers plane changes, phasing and J2 +drift; [`astrophysics::nbody`] integrates many bodies at once. + +--- + +## 3. A tone buried in noise + +📄 [`examples/guide_03_signal.rs`](../examples/guide_03_signal.rs) + +Two tones and noise at more than the amplitude of the signal. We want the +440 Hz one and not the 2.6 kHz one. + +```rust +let spectrum = rfft(&signal); // real input -> non-negative frequencies only +``` + +`rfft` returns only the non-negative frequencies, which is all a real signal +has: bin `k` sits at `k·fs/n` Hz. + +``` +before filtering + tone found at 439 Hz (magnitude 1797) + interference at 2600 Hz (magnitude 1556) +``` + +Both tones come out clearly despite the noise, because noise spreads across +every bin while a sinusoid concentrates into one. That is the whole reason +the FFT is the first tool you reach for. + +### Filtering + +```rust +// Cutoff is in cycles per sample, so 1 kHz at fs = 8 kHz is 0.125. +let taps = fir_lowpass(101, 1_000.0 / fs, WindowKind::Hamming); +let filtered = fir_apply(&taps, &signal); +``` + +``` +after a 1 kHz low-pass + 440 Hz kept magnitude 1782 + 2.6 kHz rejected magnitude 1 + rejection 67 dB +``` + +More taps means a sharper transition between passband and stopband, at the +cost of more delay and more arithmetic. 101 taps buys 67 dB here. + +### Getting the noise floor instead of the peak + +Welch's method averages periodograms over overlapping segments. It trades +frequency resolution for a reduction in variance, which is what you want when +you care about the noise floor rather than the exact peak: + +```rust +let (freqs, psd) = welch(&signal, fs, 512, 256, WindowKind::Hann); +``` + +**Where to go next.** [`transforms::fft`] handles any length, not just powers +of two — Bluestein's chirp-z covers the prime ones. [`dsp::iir`] has RBJ +biquads and second-order-section cascades when you want a filter that is cheap +rather than linear-phase. [`transforms::wavelet`] is the tool when the +frequency content changes over time. [`transforms::spectral`] adds multitaper +and Lomb–Scargle, the latter for unevenly sampled data. + +--- + +## 4. Solving a differential equation + +📄 [`examples/guide_04_fem.rs`](../examples/guide_04_fem.rs) + +Solve `−u″ = f` on `[0, 1]` with `u(0) = u(1) = 0`. Choosing +`f = π² sin(πx)` makes the exact answer `u = sin(πx)`, which is what makes the +error *measurable* rather than merely plausible. + +```rust +let values = fem_1d_poisson(&f, 0.0, 1.0, (Bc::Dirichlet(0.0), Bc::Dirichlet(0.0)), n)?; +let solution = Fem1dSolution::new(0.0, 1.0, 1, values)?; + +let e_l2 = fem_1d_error_l2(&solution, &exact); +let e_h1 = fem_1d_error_h1_seminorm(&solution, &d_exact); +``` + +``` + P1 elements + cells h L2 error H1 error + 8 0.1250 9.921e-3 2.512e-1 + 16 0.0625 2.487e-3 1.258e-1 + 32 0.0312 6.220e-4 6.295e-2 + 64 0.0156 1.555e-4 3.148e-2 + 128 0.0078 3.888e-5 1.574e-2 + + measured rate L2 2.00 H1 1.00 + theory L2 2.00 H1 1.00 +``` + +**This is the part worth pausing on.** An error that merely shrinks tells you +nothing — almost any wrong method produces a shrinking error. An error that +shrinks at *exactly* `h²` tells you the discretisation is the one you think it +is. The rate is the slope of `log(error)` against `log(h)`, and it is +predicted before it is measured. + +The H1 rate is one lower than L2 because the energy norm measures the +derivative, and differentiating a piecewise polynomial costs you an order. + +Quadratic elements buy an order in each norm on the same mesh: + +``` + P2 elements measured rate L2 3.00 theory 3.00 +``` + +**Why finite elements rather than finite differences.** A finite difference +replaces the derivative with a difference quotient and asks the equation to +hold at grid points. A finite element multiplies by a test function, integrates +by parts, and asks the resulting integral identity to hold across a +finite-dimensional space. That change buys two things: the method needs one +less derivative of the solution to make sense, so a kink in the coefficient is +admissible rather than fatal; and the answer is the *best* approximation in the +space under the energy norm — not close to the best, the best. + +**Where to go next.** [`fem::fem2d`] does triangular elements in the plane: +Poisson, Helmholtz, drum eigenvalues, plane-stress elasticity, transient heat. +[`fem::fdtd`] is Maxwell on a Yee grid with PML. [`fem::spectral_pde`] trades +matrix sparsity for a convergence rate limited only by smoothness. [`cfd`] has +the fluid-specific schemes; [`sim`] has compact readable integrators when you +want to watch something move rather than converge. + +--- + +## 5. The tools for not being wrong + +📄 [`examples/guide_05_correctness.rs`](../examples/guide_05_correctness.rs) + +The two most expensive unit mistakes on record — the Mars Climate Orbiter's +pound-seconds fed to a newton-second interface, and the Gimli Glider's +kilograms of fuel loaded as pounds — were both arithmetic a computer performed +correctly on numbers that meant something other than the receiving code +assumed. Neither would have been caught by testing the arithmetic. + +### Dimensions in the type + +```rust +let work = force.mul(&distance)?; // exactly joules +force.add(&time) // Err: dimension mismatch +``` + +``` + 4.45 N x 2 m = 8.90 m^2 kg s^-2 + adding a force to a time -> dimension mismatch: expected m kg s^-2, found s + sqrt(9 m^2) = 3.0 m +``` + +Multiplication adds the seven exponents, division subtracts them, and a square +root exists only when every one of them is even — there is no square root of a +metre, so that is a refusal rather than a rounding decision. + +### Checking a formula rather than a number + +Both sides of `x + v` are perfectly good floats, so no amount of *running* a +formula finds that mistake. Walking the expression does: + +```rust +let pendulum = Expr::Sqrt(Box::new(Expr::mul(vec![Expr::var("l"), over_g]))); +dimensional_check_formula(&pendulum, &vars)? // -> s +``` + +``` + sqrt(l/g) has dimension s + sin(omega*t) checks out; sin(t) does not +``` + +A transcendental's argument must be dimensionless, because its series adds `x` +to `x³`. `exp(−t/τ)` is meaningful and `exp(−t)` is not — and the difference is +a missing timescale, which is a real bug that produces finite numbers. + +### Buckingham's theorem, exactly + +``` + 4 quantities, rank 3 -> 1 group + exponents (rho, u, d, mu): -1, -1, -1, 1 + that is rho^-1 u^-1 d^-1 mu, which is 1/Re +``` + +The theorem says how many dimensionless groups there are — quantity count +minus the rank of the dimension matrix — not which ones. Any basis of the null +space works, and Reynolds is a particular choice made for physical reasons the +algebra knows nothing about. + +The computation runs over exact `Rational`, not floats, and that is not +fastidiousness: a group is exactly in the null space or it is not, and one that +cancelled to `1e-16` would be a rounding error reported as physics. In floating +point there is no way to tell those apart. + +### Arithmetic without rounding + +``` + 0.1 + 0.2 in f64 = 0.30000000000000004 + 1/10 + 1/5 exact = 3/10 + and 0.1 as an f64 is really 3602879701896397/36028797018963968 +``` + +That last line is the useful one. `0.1` is not one tenth; it is a +power-of-two fraction near it. `Rational::from_f64_exact` gives you the value +the float genuinely holds rather than the decimal it is printed as. + +--- + +## 6. Where to look for things + +| If you want to… | Start at | +|---|---| +| throw, drop, collide, oscillate | [`classical`], [`resonance`] | +| bend or load a structure | [`solid_mechanics`], [`continuum_mechanics`] | +| move heat around | [`thermodynamics`], [`sim::heat_sim`] | +| do circuits or fields | [`electromagnetism`], [`electronics`], [`rf`] | +| filter or transform a signal | [`transforms`], [`dsp`], [`signal_processing`] | +| make or analyse sound | [`audio`], [`acoustics`] | +| move a fluid | [`fluids`] for relations, [`cfd`] for solvers | +| go to orbit | [`astrophysics`], [`propulsion`] | +| do quantum mechanics | [`quantum`] | +| solve a PDE properly | [`fem`] | +| fit or classify data | [`learn`], [`statistics`] | +| optimise something | [`optimization`] | +| price or hedge something | [`finance`] | +| work in more than 3 dimensions | [`manifold`] | +| index or intersect geometry | [`spatial`], [`mesh`] | +| avoid a unit mistake | [`units`] | +| avoid a rounding mistake | [`exact`], [`core`] | + +The [module map](MODULE_MAP.md) has all 295 modules with sizes and summaries. + +--- + +## 7. Things that will bite you + +**`Rng` is a linear congruential generator that returns its raw state.** The +low bits have a short period, so `next_u64() % m` for a power-of-two `m` cycles +through a handful of values — `% 2` gives 0,1,0,1 forever. Use +[`monte_carlo::Rng::below`], which takes the high bits, for any small-integer +draw. It is fine for simulation and not cryptographically secure. + +**Explicit time-stepping is conditionally stable.** Heat needs +`α Δt / Δx² ≤ 1/4` in 2-D and `1/6` in 3-D, so halving the grid spacing +*quarters* the time step. Waves and FDTD need the Courant condition, and the +limit is set by the fastest medium in the grid — for FDTD that means the +*smallest* relative permittivity, not vacuum. + +**`pcg_jacobi`'s tolerance is relative to the norm of the right-hand side**, +not absolute. Passing `1e-13` when your data is at `1e8` asks for something +much weaker than you meant. + +**Reference tables are room-temperature values.** Viscosity in particular can +change by a factor of several over a few tens of degrees; a single figure is a +starting point, not a datasheet. + +**A specification reading is written down where one was needed.** Where a +definition is genuinely ambiguous — the Frobenius number with a unit coin, +Stern–Brocot indexing, which parenthesisation a unit string means — the choice +is stated in the doc comment rather than left implicit. If a result surprises +you, read the doc comment before assuming a bug. + +--- + +[`acoustics`]: ../src/acoustics.rs +[`astrophysics`]: ../src/astrophysics/ +[`astrophysics::kepler`]: ../src/astrophysics/kepler.rs +[`astrophysics::lambert`]: ../src/astrophysics/lambert.rs +[`astrophysics::maneuvers`]: ../src/astrophysics/maneuvers.rs +[`astrophysics::nbody`]: ../src/astrophysics/nbody.rs +[`audio`]: ../src/audio/ +[`cfd`]: ../src/cfd/ +[`classical`]: ../src/classical.rs +[`continuum_mechanics`]: ../src/continuum_mechanics.rs +[`core`]: ../src/core/ +[`dsp`]: ../src/dsp/ +[`dsp::iir`]: ../src/dsp/iir.rs +[`electromagnetism`]: ../src/electromagnetism.rs +[`electronics`]: ../src/electronics.rs +[`exact`]: ../src/exact/ +[`fem`]: ../src/fem/ +[`fem::fdtd`]: ../src/fem/fdtd.rs +[`fem::fem2d`]: ../src/fem/fem2d.rs +[`fem::spectral_pde`]: ../src/fem/spectral_pde.rs +[`finance`]: ../src/finance/ +[`fluids`]: ../src/fluids.rs +[`learn`]: ../src/learn/ +[`manifold`]: ../src/manifold/ +[`mesh`]: ../src/mesh/ +[`monte_carlo::Rng::below`]: ../src/monte_carlo/mod.rs +[`optimization`]: ../src/optimization/ +[`propulsion`]: ../src/propulsion.rs +[`quantum`]: ../src/quantum/ +[`resonance`]: ../src/resonance/ +[`rf`]: ../src/rf.rs +[`signal_processing`]: ../src/signal_processing/ +[`sim`]: ../src/sim/ +[`sim::heat_sim`]: ../src/sim/heat_sim.rs +[`solid_mechanics`]: ../src/solid_mechanics.rs +[`spatial`]: ../src/spatial/ +[`statistics`]: ../src/statistics/ +[`thermodynamics`]: ../src/thermodynamics.rs +[`transforms`]: ../src/transforms/ +[`transforms::fft`]: ../src/transforms/fft.rs +[`transforms::spectral`]: ../src/transforms/spectral.rs +[`transforms::wavelet`]: ../src/transforms/wavelet.rs +[`units`]: ../src/units/ diff --git a/docs/MODULE_MAP.md b/docs/MODULE_MAP.md new file mode 100644 index 0000000..301d3ce --- /dev/null +++ b/docs/MODULE_MAP.md @@ -0,0 +1,784 @@ +# Module map + +**Generated file — do not edit.** Produced by +[`tools/gen_module_map.py`](../tools/gen_module_map.py) from the source +tree; CI fails if it is out of date. Regenerate with: + +```bash +python3 tools/gen_module_map.py +``` + +Every figure below is parsed from the sources. Summaries are the first +sentence of each module's `//!` documentation. Public-item counts exclude +anything inside `#[cfg(test)]`, and tell a method from a free function by +the enclosing `impl` block rather than by indentation -- an indented +`pub fn` inside an inline `pub mod` is a free function, and there are 175 +of those. + +The count is syntactic, so an item generated by a macro is counted once +where the macro defines it rather than once per expansion. That affects +two places: `units::quantity`, whose `unit_ctor!` generates about thirty +constructors from one template, and `spatial::kdtree`, whose macro +generates two tree types from one. + +**295 modules** across **71 public top-level modules**, **266,122 lines** in **296 files** (the modules plus the crate root `src/lib.rs`), **4,124 public functions** and **2,241 public methods**, **431 public types**. + +`verification` is compiled and tested but declared `mod` rather than `pub mod`, so it is not part of the public API and is excluded from the module count above. + +## Tree + +A directory's figure is its own `mod.rs` plus everything beneath it. + +``` +src/ lines +├── lib.rs 159 (crate root) +├── acoustics.rs 576 +├── astrophysics/ 6,122 +│ ├── collisions.rs 318 +│ ├── coords.rs 1,051 +│ ├── gravitational_waves.rs 233 +│ ├── habitable_zone.rs 127 +│ ├── kepler.rs 913 +│ ├── lagrange.rs 195 +│ ├── lambert.rs 553 +│ ├── magnetosphere.rs 405 +│ ├── maneuvers.rs 618 +│ ├── nbody.rs 403 +│ ├── orbital_elements.rs 660 +│ ├── tidal.rs 209 +│ └── time_systems.rs 399 +├── atmosphere.rs 409 +├── audio/ 10,716 +│ ├── analysis.rs 1,950 +│ ├── effects.rs 1,669 +│ ├── envelope.rs 604 +│ ├── oscillators.rs 939 +│ ├── physical.rs 1,331 +│ ├── spatial.rs 1,132 +│ ├── synthesis.rs 1,260 +│ ├── tuning.rs 517 +│ ├── vocoder.rs 862 +│ └── wav.rs 370 +├── biophysics/ 11,396 +│ ├── epidemiology.rs 1,924 +│ ├── neuro.rs 2,519 +│ ├── phylo.rs 1,979 +│ ├── population.rs 2,356 +│ └── seq_align.rs 2,150 +├── cfd/ 16,732 +│ ├── advection.rs 869 +│ ├── boundary_layer.rs 579 +│ ├── grid.rs 685 +│ ├── lbm.rs 1,142 +│ ├── level_set.rs 2,066 +│ ├── multiphase.rs 778 +│ ├── porous.rs 695 +│ ├── potential_flow.rs 1,523 +│ ├── riemann.rs 1,564 +│ ├── shallow_water.rs 938 +│ ├── sph.rs 1,154 +│ ├── stable_fluids.rs 1,776 +│ ├── turbulence.rs 1,537 +│ └── vortex.rs 1,304 +├── chemistry.rs 334 +├── classical.rs 786 +├── codes/ 8,243 +│ ├── block.rs 1,579 +│ ├── checksum.rs 880 +│ ├── compression.rs 1,420 +│ ├── convolutional.rs 1,335 +│ ├── crypto_math.rs 1,501 +│ └── reed_solomon.rs 1,519 +├── color_science.rs 788 +├── continuum_mechanics.rs 508 +├── control_systems/ 744 +│ └── kalman.rs 291 +├── core/ 984 +│ ├── compensated.rs 117 +│ ├── dual.rs 410 +│ └── interval.rs 451 +├── curves.rs 500 +├── discrete/ 9,047 +│ ├── combinatorics.rs 2,827 +│ ├── disjoint_set.rs 352 +│ ├── number_theory.rs 2,345 +│ ├── partitions.rs 784 +│ ├── primes.rs 1,238 +│ └── sequences.rs 1,491 +├── dsp/ 3,928 +│ ├── fir.rs 996 +│ ├── iir.rs 1,666 +│ ├── phase.rs 270 +│ ├── resample.rs 513 +│ └── windows.rs 446 +├── electromagnetism.rs 822 +├── electronics.rs 445 +├── error.rs 103 +├── exact/ 9,249 +│ ├── bigfloat.rs 2,000 +│ ├── bigint.rs 1,463 +│ ├── contfrac.rs 524 +│ ├── polynomial.rs 2,286 +│ ├── rational.rs 1,079 +│ └── symbolic.rs 1,882 +├── fem/ 4,725 +│ ├── fdtd.rs 1,154 +│ ├── fem1d.rs 952 +│ ├── fem2d.rs 1,901 +│ └── spectral_pde.rs 693 +├── fields.rs 211 +├── finance/ 5,119 +│ ├── options.rs 2,090 +│ ├── portfolio.rs 865 +│ ├── rates.rs 1,388 +│ └── risk.rs 751 +├── fluid_instabilities.rs 451 +├── fluids.rs 709 +├── fractals/ 9,454 +│ ├── attractors.rs 1,104 +│ ├── automata.rs 2,881 +│ ├── escape_time.rs 1,044 +│ ├── ifs.rs 924 +│ ├── lsystem.rs 1,056 +│ └── noise.rs 1,803 +├── general_relativity.rs 427 +├── geometry/ 1,522 +│ ├── delaunay.rs 262 +│ ├── geodesy.rs 342 +│ ├── hull.rs 310 +│ └── mesh.rs 155 +├── geophysics.rs 483 +├── graph/ 13,493 +│ ├── coloring.rs 1,649 +│ ├── core.rs 2,862 +│ ├── flow.rs 1,519 +│ ├── layout.rs 1,935 +│ ├── matching.rs 1,399 +│ ├── paths.rs 2,133 +│ └── spectral.rs 1,984 +├── gravitation.rs 236 +├── information_theory.rs 367 +├── learn/ 4,213 +│ ├── cluster.rs 1,295 +│ ├── gp.rs 839 +│ ├── nn.rs 1,163 +│ └── tree.rs 900 +├── linalg/ 3,295 +│ ├── cholesky.rs 147 +│ ├── eigen.rs 492 +│ ├── lu.rs 223 +│ ├── matrix.rs 344 +│ ├── qr.rs 205 +│ ├── sparse.rs 360 +│ ├── svd.rs 321 +│ └── tridiagonal.rs 233 +├── magnetohydrodynamics.rs 359 +├── manifold/ 20,431 +│ ├── clifford.rs 2,830 +│ ├── dec.rs 1,618 +│ ├── embedding.rs 1,624 +│ ├── geodesic.rs 1,422 +│ ├── hyperbolic.rs 1,710 +│ ├── lie.rs 3,225 +│ ├── metric.rs 1,382 +│ ├── polytope4.rs 2,142 +│ ├── spacetime.rs 1,556 +│ ├── spherical.rs 1,671 +│ └── vecn.rs 1,146 +├── materials/ 3,548 +│ ├── common.rs 349 +│ ├── elements.rs 2,632 +│ ├── fluids.rs 308 +│ └── gases.rs 242 +├── math.rs 621 +├── mesh/ 6,516 +│ ├── analyze.rs 1,201 +│ ├── generate.rs 881 +│ ├── isosurface.rs 1,052 +│ ├── parameterize.rs 652 +│ ├── subdivide.rs 616 +│ └── surfaces.rs 1,043 +├── monte_carlo/ 982 +│ └── quasi.rs 282 +├── neutronics.rs 409 +├── nonlinear.rs 432 +├── nuclear.rs 303 +├── numerical/ 2,563 +│ ├── bvp.rs 201 +│ ├── integrate.rs 270 +│ ├── interpolate.rs 648 +│ ├── ode/ 740 +│ │ ├── adaptive.rs 309 +│ │ ├── explicit.rs 63 +│ │ ├── implicit.rs 232 +│ │ └── symplectic.rs 125 +│ └── roots.rs 280 +├── optics.rs 348 +├── optimization/ 15,189 +│ ├── convex.rs 2,410 +│ ├── game_theory.rs 3,326 +│ ├── integer.rs 2,694 +│ ├── least_squares.rs 371 +│ ├── lp.rs 2,600 +│ ├── metaheuristics.rs 1,577 +│ └── network.rs 1,383 +├── particle_physics.rs 402 +├── patterns/ 12,404 +│ ├── aperiodic.rs 1,807 +│ ├── knots.rs 831 +│ ├── packing.rs 1,130 +│ ├── phyllotaxis.rs 490 +│ ├── polygon_ops.rs 2,022 +│ ├── polyhedra.rs 2,032 +│ ├── sampling.rs 1,220 +│ ├── space_filling.rs 755 +│ ├── symmetry.rs 996 +│ └── tilings.rs 1,107 +├── photonics.rs 485 +├── plasma.rs 297 +├── propulsion.rs 361 +├── quantum/ 11,941 +│ ├── algorithms.rs 1,707 +│ ├── circuit.rs 2,460 +│ ├── schrodinger.rs 2,607 +│ ├── solid_state.rs 1,685 +│ ├── spin.rs 1,703 +│ └── wavefunction.rs 1,368 +├── quaternion.rs 562 +├── radiation.rs 335 +├── relativity.rs 302 +├── resonance/ 4,275 +│ ├── cavity.rs 931 +│ ├── coupled.rs 828 +│ ├── nonlinear.rs 704 +│ ├── oscillator.rs 636 +│ └── structural.rs 1,134 +├── rf.rs 440 +├── signal_processing.rs 708 +├── sim/ 4,927 +│ ├── cloth_sim.rs 970 +│ ├── em_sim.rs 638 +│ ├── fluid_sim.rs 1,161 +│ ├── heat_sim.rs 774 +│ ├── rigid_body.rs 681 +│ └── wave_sim.rs 682 +├── solid_mechanics.rs 380 +├── spatial/ 7,020 +│ ├── bvh.rs 513 +│ ├── contain.rs 527 +│ ├── distance.rs 495 +│ ├── frame.rs 215 +│ ├── intersect.rs 908 +│ ├── kdtree.rs 510 +│ ├── mat4.rs 504 +│ ├── octree.rs 342 +│ ├── primitives.rs 1,128 +│ ├── projective.rs 447 +│ ├── quadtree.rs 359 +│ ├── sdf.rs 731 +│ └── transform2d.rs 308 +├── special/ 1,955 +│ ├── bessel.rs 528 +│ ├── beta.rs 145 +│ ├── elliptic.rs 333 +│ ├── erf.rs 335 +│ ├── expint.rs 126 +│ ├── gamma.rs 219 +│ └── legendre.rs 243 +├── statistical_mechanics/ 9,687 +│ ├── ising.rs 2,004 +│ ├── kinetics.rs 2,806 +│ ├── lattice_models.rs 1,199 +│ └── md.rs 3,237 +├── statistics/ 2,125 +│ ├── descriptive.rs 114 +│ ├── distributions.rs 1,013 +│ ├── fourier.rs 56 +│ ├── inference.rs 415 +│ └── resampling.rs 239 +├── stochastic/ 15,707 +│ ├── extreme.rs 1,852 +│ ├── hmm.rs 1,451 +│ ├── markov.rs 1,952 +│ ├── point_process.rs 1,373 +│ ├── queueing.rs 1,933 +│ ├── rmt.rs 1,217 +│ ├── sde.rs 1,939 +│ └── timeseries.rs 3,979 +├── thermodynamics.rs 808 +├── transforms/ 6,353 +│ ├── dct.rs 489 +│ ├── fft.rs 962 +│ ├── hilbert.rs 570 +│ ├── laplace.rs 435 +│ ├── radon.rs 619 +│ ├── spectral.rs 808 +│ ├── stft.rs 695 +│ ├── wavelet.rs 1,022 +│ └── wavelet_tables.rs 699 +├── trigonometry.rs 493 +├── units/ 2,785 +│ ├── dimensional.rs 974 +│ └── quantity.rs 998 +├── vector_calculus.rs 1,195 +├── verification/ 394 (private) +│ ├── core.rs 27 +│ ├── linalg.rs 27 +│ ├── physics.rs 236 +│ └── spatial.rs 41 +└── waves.rs 784 +``` + +## By area + +### Numeric foundations + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`core`** | 984 | 34 | 2 | Pure numeric building blocks: compensated summation, forward-mode automatic differentiation, and interval arithmetic. | +| **`math`** | 621 | 23 | 2 | Vectors and the crate's table of physical constants. | +| **`linalg`** | 3,295 | 74 | 8 | Dense and sparse linear algebra. | +| **`numerical`** | 2,563 | 43 | 4 | Numerical methods: quadrature, root finding, ODE solvers, and interpolation. | +| **`special`** | 1,955 | 34 | 0 | Special functions: error function family, gamma family, and beta functions. | +| **`error`** | 103 | 0 | 2 | Error types shared by the numerical solvers. | + +### Exact and symbolic + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`exact`** | 9,249 | 242 | 8 | Exact arithmetic: arbitrary-precision integers, exact rationals, arbitrary-precision binary floating point, polynomials, and continued fractions. | +| **`discrete`** | 9,047 | 181 | 1 | Discrete mathematics: primes and factorization, elementary and analytic number theory, counting and enumeration, integer partitions, integer… | +| **`graph`** | 13,493 | 182 | 3 | Graphs: representation and structure, shortest paths, network flow, matchings, spectral graph theory, colouring, and drawing. | +| **`codes`** | 8,243 | 225 | 16 | Error detection, error correction, compression, and the arithmetic cryptography is built on. | + +### Classical mechanics + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`classical`** | 786 | 54 | 0 | Newtonian mechanics: kinematics, dynamics, and the harmonic oscillator. | +| **`gravitation`** | 236 | 14 | 0 | Newtonian gravity and two-body orbits. | +| **`solid_mechanics`** | 380 | 23 | 0 | Strength of materials: stress, strain, elastic constants and beams. | +| **`continuum_mechanics`** | 508 | 19 | 0 | Stress and strain as tensors, and the yield criteria built on them. | +| **`resonance`** | 4,275 | 144 | 7 | Resonance and vibration: single and coupled oscillators, acoustic and electromagnetic cavities, nonlinear resonance, and structural dynamics. | +| **`geophysics`** | 483 | 22 | 0 | The solid Earth: gravity, seismology, and heat. | + +### Thermal and statistical + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`thermodynamics`** | 808 | 52 | 0 | Thermodynamics: gases, heat transfer, cycles and phase change. | +| **`statistical_mechanics`** | 9,687 | 161 | 9 | Statistical mechanics: the elementary relations here, with lattice models and Monte Carlo in submodules. | +| **`radiation`** | 335 | 14 | 0 | Thermal radiation and radiative transfer. | + +### Electromagnetism + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`electromagnetism`** | 822 | 60 | 0 | Classical electromagnetism, from Coulomb's law to radiating dipoles. | +| **`electronics`** | 445 | 17 | 0 | Semiconductor device physics. | +| **`rf`** | 440 | 28 | 0 | Radio-frequency engineering: links, lines and noise. | +| **`photonics`** | 485 | 26 | 0 | Laser beams, optical fibre, and interferometry. | +| **`plasma`** | 297 | 16 | 0 | Plasma parameters: the characteristic lengths, frequencies and speeds. | +| **`magnetohydrodynamics`** | 359 | 19 | 0 | Magnetohydrodynamics: a conducting fluid and the field frozen into it. | + +### Waves and signals + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`waves`** | 784 | 48 | 0 | Wave propagation: mechanical, acoustic and seismic. | +| **`optics`** | 348 | 20 | 0 | Geometric and wave optics. | +| **`acoustics`** | 576 | 31 | 0 | Room acoustics, psychoacoustic scales, and musical pitch. | +| **`transforms`** | 6,353 | 120 | 8 | Discrete transforms: FFT (any length), DCT/DST, STFT, wavelets, Hilbert, Laplace inversion, Radon, and spectral estimation. | +| **`dsp`** | 3,928 | 94 | 7 | Digital signal processing: window functions, FIR/IIR filter design, resampling, and phase utilities. | +| **`signal_processing`** | 708 | 16 | 0 | Time-domain signal operations and test waveforms. | +| **`audio`** | 10,716 | 350 | 49 | Audio synthesis, analysis, effects, and I/O. | + +### Fluids + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`fluids`** | 709 | 45 | 0 | Fluid statics and single-phase flow. | +| **`cfd`** | 16,732 | 477 | 50 | Computational fluid dynamics: staggered grids, advection schemes, and (in later modules) incompressible solvers, shallow water, SPH, LBM, level… | +| **`fluid_instabilities`** | 451 | 19 | 0 | When a fluid configuration stops being stable, and how fast it comes apart. | +| **`propulsion`** | 361 | 15 | 0 | Rocket propulsion and impulsive orbital transfers. | + +### Modern physics + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`relativity`** | 302 | 18 | 0 | Special relativity. | +| **`general_relativity`** | 427 | 23 | 0 | General relativity: black holes and cosmology. | +| **`quantum`** | 11,941 | 267 | 8 | Quantum mechanics: the elementary relations here, with the wavefunction machinery and the Schrodinger solvers in submodules. | +| **`particle_physics`** | 402 | 20 | 0 | Relativistic kinematics and scattering for particle collisions. | +| **`nuclear`** | 303 | 20 | 0 | Radioactive decay, nuclear binding, and dosimetry. | +| **`neutronics`** | 409 | 22 | 0 | Reactor physics: criticality, neutron diffusion, and shielding. | + +### Space + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`astrophysics`** | 6,122 | 111 | 9 | Astrodynamics and astrophysics. | + +### PDE solvers + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`fem`** | 4,725 | 52 | 6 | Finite elements, finite-difference time domain, and spectral methods. | +| **`sim`** | 4,927 | 101 | 15 | Time-stepping simulation engines. | +| **`fields`** | 211 | 10 | 2 | Uniform-grid scalar fields. | +| **`vector_calculus`** | 1,195 | 14 | 0 | Vector calculus operators and field theory for physics grids. | + +### Chemistry and life + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`chemistry`** | 334 | 18 | 0 | Reaction kinetics, chemical thermodynamics and electrochemistry. | +| **`biophysics`** | 11,396 | 177 | 7 | Biophysics: the elementary membrane, transport and mechanics relations here, with the population-scale models in submodules. | + +### Probability and data + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`statistics`** | 2,125 | 52 | 14 | Statistics: descriptive measures, probability distributions, and Fourier utilities. | +| **`stochastic`** | 15,707 | 253 | 19 | Stochastic processes: Markov chains, Markov chain Monte Carlo, and hidden state models. | +| **`monte_carlo`** | 982 | 28 | 3 | Monte Carlo methods and the random number generator behind them. | +| **`information_theory`** | 367 | 16 | 0 | Shannon information: entropy, divergence, and channel capacity. | +| **`learn`** | 4,213 | 55 | 13 | Learning algorithms, written to be read rather than to be fast. | + +### Decisions + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`optimization`** | 15,189 | 177 | 19 | Optimization: continuous, combinatorial, and strategic. | +| **`finance`** | 5,119 | 60 | 6 | Quantitative finance: derivative pricing, interest rates, portfolio construction and risk measurement. | + +### Geometry + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`geometry`** | 1,522 | 49 | 3 | Areas, volumes and surface areas of the standard shapes. | +| **`curves`** | 500 | 25 | 0 | Plane curves: conics, Bézier curves, and parametric families. | +| **`trigonometry`** | 493 | 33 | 0 | Triangle solving, trigonometric identities, and hyperbolic functions. | +| **`quaternion`** | 562 | 18 | 1 | Unit quaternions for 3-D rotation. | +| **`manifold`** | 20,431 | 720 | 33 | Manifolds and higher-dimensional geometry: generic n-dimensional vectors and tensors, metric-driven curvature, and (in later modules) geodesics,… | +| **`spatial`** | 7,020 | 254 | 25 | Spatial data structures, transforms, geometric primitives, and queries. | +| **`mesh`** | 6,516 | 136 | 10 | Indexed triangle meshes: construction, mass properties, cleanup, spatial queries, and OBJ/STL interchange. | + +### Patterns and chaos + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`fractals`** | 9,454 | 288 | 38 | Fractals: escape-time sets, attractors, automata and noise. | +| **`patterns`** | 12,404 | 239 | 12 | Geometric patterns: polygon algorithms, sampling distributions, phyllotaxis, tilings, symmetry groups, packings, space-filling curves, polyhedra,… | +| **`nonlinear`** | 432 | 13 | 0 | Chaos in low-dimensional systems. | + +### Reference and utility + +| Module | Lines | Public fns | Types | What it is | +|---|--:|--:|--:|---| +| **`units`** | 2,785 | 85 | 3 | Unit conversions, dimensional analysis and the CODATA constants. | +| **`materials`** | 3,548 | 11 | 6 | Reference property tables. | +| **`color_science`** | 788 | 14 | 0 | Colour: the standard spaces, the transforms between them, and perceptual measures. | +| **`control_systems`** | 744 | 27 | 3 | Linear control: system response, stability margins and PID tuning. | +| **`atmosphere`** | 409 | 17 | 0 | The standard atmosphere, humidity, and near-surface wind. | +| **`verification`** | 394 | 0 | 0 | Kani proof harnesses. | + +## Every module + +| Path | Module | Lines | Fns | Methods | Types | Summary | +|---|---|--:|--:|--:|--:|---| +| `acoustics.rs` | `acoustics` | 576 | 31 | 0 | 0 | Room acoustics, psychoacoustic scales, and musical pitch. | +| `astrophysics/mod.rs` | `astrophysics` | 38 | 0 | 0 | 0 | Astrodynamics and astrophysics. | +| `astrophysics/collisions.rs` | `astrophysics::collisions` | 318 | 8 | 0 | 3 | Impacts, mergers, and collision probability. | +| `astrophysics/coords.rs` | `astrophysics::coords` | 1,051 | 11 | 0 | 2 | Astronomical coordinates, low-precision ephemerides and TLE parsing. | +| `astrophysics/gravitational_waves.rs` | `astrophysics::gravitational_waves` | 233 | 8 | 0 | 0 | Gravitational radiation from a compact binary. | +| `astrophysics/habitable_zone.rs` | `astrophysics::habitable_zone` | 127 | 6 | 0 | 0 | Habitable zone boundaries and tidal locking. | +| `astrophysics/kepler.rs` | `astrophysics::kepler` | 913 | 9 | 0 | 0 | Kepler's equation, anomaly conversions and two-body propagation. | +| `astrophysics/lagrange.rs` | `astrophysics::lagrange` | 195 | 4 | 0 | 0 | The five Lagrange points of the circular restricted three-body problem. | +| `astrophysics/lambert.rs` | `astrophysics::lambert` | 553 | 4 | 0 | 0 | Lambert's problem: the orbit connecting two positions in a given time. | +| `astrophysics/magnetosphere.rs` | `astrophysics::magnetosphere` | 405 | 6 | 0 | 1 | Planetary dipole fields and the magnetopause. | +| `astrophysics/maneuvers.rs` | `astrophysics::maneuvers` | 618 | 8 | 0 | 0 | Orbital manoeuvres: combined burns, patched conics, gravity assists and the perturbation that dominates low orbits. | +| `astrophysics/nbody.rs` | `astrophysics::nbody` | 403 | 8 | 7 | 2 | Direct N-body gravitational simulation. | +| `astrophysics/orbital_elements.rs` | `astrophysics::orbital_elements` | 660 | 15 | 5 | 1 | Keplerian elements: conversion, propagation, and the anomalies. | +| `astrophysics/tidal.rs` | `astrophysics::tidal` | 209 | 7 | 0 | 0 | Tidal forces and the Roche limit. | +| `astrophysics/time_systems.rs` | `astrophysics::time_systems` | 399 | 5 | 0 | 0 | Astronomical time: Julian dates and sidereal time. | +| `atmosphere.rs` | `atmosphere` | 409 | 17 | 0 | 0 | The standard atmosphere, humidity, and near-surface wind. | +| `audio/mod.rs` | `audio` | 82 | 0 | 0 | 0 | Audio synthesis, analysis, effects, and I/O. | +| `audio/analysis.rs` | `audio::analysis` | 1,950 | 60 | 0 | 2 | Audio analysis: pitch detection (YIN, autocorrelation, cepstral, HPS, McLeod), onset/tempo/beat tracking, MFCCs, LPC and formants, LSPs, spectral… | +| `audio/effects.rs` | `audio::effects` | 1,669 | 21 | 52 | 20 | Audio effects: delays, reverbs (Schroeder, Freeverb, FDN), convolution, modulation effects, dynamics, distortion, EQ, imaging, loudness (ITU-R… | +| `audio/envelope.rs` | `audio::envelope` | 604 | 9 | 18 | 5 | Envelopes, LFOs, followers, fades, and glides. | +| `audio/oscillators.rs` | `audio::oscillators` | 939 | 16 | 15 | 5 | Audio-rate oscillators and test signals: PolyBLEP anti-aliased classics, additive resynthesis, mipmapped wavetables, colored noise, chirps, and… | +| `audio/physical.rs` | `audio::physical` | 1,331 | 12 | 34 | 8 | Physical modeling synthesis: digital waveguides (plucked/struck/bowed strings, clarinet and flute bores), modal synthesis (bars, membranes,… | +| `audio/spatial.rs` | `audio::spatial` | 1,132 | 28 | 0 | 0 | Spatial audio: panning laws, VBAP, ambisonics, simple binaural cues, Doppler, distance/air attenuation, geometric room acoustics (image source and… | +| `audio/synthesis.rs` | `audio::synthesis` | 1,260 | 29 | 7 | 4 | Sound synthesis: additive, FM (DX7-style operator routing), Karplus-Strong, subtractive, granular, formant, waveshaping, drums, and note/sequence… | +| `audio/tuning.rs` | `audio::tuning` | 517 | 25 | 0 | 2 | Musical tuning: temperaments, interval math, Scala parsing, consonance models, stretch tuning, and pitch-class utilities. | +| `audio/vocoder.rs` | `audio::vocoder` | 862 | 8 | 8 | 2 | Phase vocoder and related voice/spectral processors: time stretching, pitch shifting, robotization, channel and LPC vocoders, WSOLA, PSOLA,… | +| `audio/wav.rs` | `audio::wav` | 370 | 8 | 0 | 1 | WAV (RIFF) reading and writing: PCM 8/16/24/32-bit, IEEE float 32/64-bit, and WAVE_FORMAT_EXTENSIBLE containers. | +| `biophysics/mod.rs` | `biophysics` | 468 | 19 | 0 | 0 | Biophysics: the elementary membrane, transport and mechanics relations here, with the population-scale models in submodules. | +| `biophysics/epidemiology.rs` | `biophysics::epidemiology` | 1,924 | 22 | 1 | 1 | Compartment models of epidemics, their stochastic counterparts, and the quantities estimated from case data. | +| `biophysics/neuro.rs` | `biophysics::neuro` | 2,519 | 35 | 2 | 1 | Computational neuroscience: single neurons, spike trains, synapses and the small networks built from them. | +| `biophysics/phylo.rs` | `biophysics::phylo` | 1,979 | 9 | 19 | 2 | Phylogenetics: trees, the distance and character methods that build them, and the statistics read off them. | +| `biophysics/population.rs` | `biophysics::population` | 2,356 | 36 | 0 | 1 | Population dynamics and population genetics: growth laws, interacting species, age-structured projection, discrete maps, and the drift, selection… | +| `biophysics/seq_align.rs` | `biophysics::seq_align` | 2,150 | 30 | 4 | 2 | Sequence alignment and the elementary sequence analysis around it. | +| `cfd/mod.rs` | `cfd` | 122 | 0 | 0 | 0 | Computational fluid dynamics: staggered grids, advection schemes, and (in later modules) incompressible solvers, shallow water, SPH, LBM, level… | +| `cfd/advection.rs` | `cfd::advection` | 869 | 17 | 0 | 2 | Advection schemes: classic 1D finite-volume methods (upwind, Lax-Wendroff, MUSCL with slope limiters, WENO5), 2D semi-Lagrangian transport with… | +| `cfd/boundary_layer.rs` | `cfd::boundary_layer` | 579 | 31 | 0 | 0 | Boundary layers: Blasius and Falkner-Skan similarity solutions (shooting), Thwaites and Head integral methods, turbulent wall laws, transition and… | +| `cfd/grid.rs` | `cfd::grid` | 685 | 0 | 30 | 4 | Staggered (MAC) grids and cell-centered scalar fields for incompressible flow solvers. | +| `cfd/lbm.rs` | `cfd::lbm` | 1,142 | 8 | 22 | 4 | Lattice Boltzmann method: D2Q9 with BGK/TRT/MRT/cumulant-style collisions, bounce-back solids, Zou-He open boundaries, Guo forcing, D3Q19 and… | +| `cfd/level_set.rs` | `cfd::level_set` | 2,066 | 12 | 34 | 6 | Interface capturing: level sets (upwind/WENO advection, Sussman reinitialization, fast marching, marching squares/tetrahedra), volume of fluid… | +| `cfd/multiphase.rs` | `cfd::multiphase` | 778 | 35 | 1 | 2 | Multiphase flow correlations: mixture properties, drift-flux and void fraction models, two-phase pressure drop, flow-pattern maps, bubble and… | +| `cfd/porous.rs` | `cfd::porous` | 695 | 24 | 8 | 1 | Porous-media flow: Darcy's law and extensions, unsaturated flow (Richards equation with Van Genuchten retention), well hydraulics, solute… | +| `cfd/potential_flow.rs` | `cfd::potential_flow` | 1,523 | 27 | 19 | 5 | Incompressible potential flow: elementary singularities, complex potentials, Joukowski and Karman-Trefftz airfoils, NACA sections, the Hess-Smith… | +| `cfd/riemann.rs` | `cfd::riemann` | 1,564 | 26 | 16 | 6 | 1D/2D compressible Euler equations: exact and approximate Riemann solvers (HLL, HLLC, Roe with entropy fix, Rusanov, AUSM+), MUSCL finite-volume… | +| `cfd/shallow_water.rs` | `cfd::shallow_water` | 938 | 14 | 12 | 1 | Shallow water equations: well-balanced HLL finite volumes with hydrostatic reconstruction and wet/dry handling (1D and 2D), the Stoker dam-break… | +| `cfd/sph.rs` | `cfd::sph` | 1,154 | 9 | 23 | 7 | Smoothed-particle hydrodynamics: standard kernel family, spatial hashing, weakly compressible (WCSPH) and predictive-corrective solvers with… | +| `cfd/stable_fluids.rs` | `cfd::stable_fluids` | 1,776 | 8 | 19 | 3 | Stable-fluids incompressible solver on a MAC grid: MacCormack advection, implicit viscosity, buoyancy, vorticity confinement, and a pressure… | +| `cfd/turbulence.rs` | `cfd::turbulence` | 1,537 | 34 | 12 | 5 | Turbulence modelling and statistics. | +| `cfd/vortex.rs` | `cfd::vortex` | 1,304 | 17 | 19 | 4 | Vortex methods: regularized Biot-Savart particle methods in 2D and 3D, classical vortex solutions (Lamb-Oseen, Rankine, Burgers, Hill), point… | +| `chemistry.rs` | `chemistry` | 334 | 18 | 0 | 0 | Reaction kinetics, chemical thermodynamics and electrochemistry. | +| `classical.rs` | `classical` | 786 | 54 | 0 | 0 | Newtonian mechanics: kinematics, dynamics, and the harmonic oscillator. | +| `codes/mod.rs` | `codes` | 9 | 0 | 0 | 0 | Error detection, error correction, compression, and the arithmetic cryptography is built on. | +| `codes/block.rs` | `codes::block` | 1,579 | 11 | 35 | 2 | Binary linear block codes. | +| `codes/checksum.rs` | `codes::checksum` | 880 | 21 | 0 | 0 | Checksums and check digits: cheap ways to notice that data changed. | +| `codes/compression.rs` | `codes::compression` | 1,420 | 28 | 7 | 3 | Lossless compression, and the string machinery it is built on. | +| `codes/convolutional.rs` | `codes::convolutional` | 1,335 | 17 | 27 | 3 | Convolutional and turbo codes, and the channels they run over. | +| `codes/crypto_math.rs` | `codes::crypto_math` | 1,501 | 24 | 14 | 2 | The arithmetic underneath public-key cryptography, for study rather than for use. | +| `codes/reed_solomon.rs` | `codes::reed_solomon` | 1,519 | 4 | 37 | 6 | Reed-Solomon and BCH codes over finite fields. | +| `color_science.rs` | `color_science` | 788 | 14 | 0 | 0 | Colour: the standard spaces, the transforms between them, and perceptual measures. | +| `continuum_mechanics.rs` | `continuum_mechanics` | 508 | 19 | 0 | 0 | Stress and strain as tensors, and the yield criteria built on them. | +| `control_systems/mod.rs` | `control_systems` | 453 | 18 | 3 | 1 | Linear control: system response, stability margins and PID tuning. | +| `control_systems/kalman.rs` | `control_systems::kalman` | 291 | 0 | 6 | 2 | Kalman filtering. | +| `core/mod.rs` | `core` | 6 | 0 | 0 | 0 | Pure numeric building blocks: compensated summation, forward-mode automatic differentiation, and interval arithmetic. | +| `core/compensated.rs` | `core::compensated` | 117 | 3 | 0 | 0 | Compensated (error-free-transformation) summation. | +| `core/dual.rs` | `core::dual` | 410 | 3 | 15 | 1 | Forward-mode automatic differentiation with dual numbers. | +| `core/interval.rs` | `core::interval` | 451 | 1 | 12 | 1 | Rigorous interval arithmetic with outward rounding. | +| `curves.rs` | `curves` | 500 | 25 | 0 | 0 | Plane curves: conics, Bézier curves, and parametric families. | +| `discrete/mod.rs` | `discrete` | 10 | 0 | 0 | 0 | Discrete mathematics: primes and factorization, elementary and analytic number theory, counting and enumeration, integer partitions, integer… | +| `discrete/combinatorics.rs` | `discrete::combinatorics` | 2,827 | 59 | 0 | 0 | Counting, enumeration, and the permutation group. | +| `discrete/disjoint_set.rs` | `discrete::disjoint_set` | 352 | 0 | 10 | 1 | Union-find over `0..n` with path compression and union by size. | +| `discrete/number_theory.rs` | `discrete::number_theory` | 2,345 | 49 | 0 | 0 | Elementary and analytic number theory. | +| `discrete/partitions.rs` | `discrete::partitions` | 784 | 15 | 0 | 0 | Integer partitions, Young diagrams, and the RSK correspondence. | +| `discrete/primes.rs` | `discrete::primes` | 1,238 | 26 | 0 | 0 | Primes: sieves, primality testing, factorization, and prime counting. | +| `discrete/sequences.rs` | `discrete::sequences` | 1,491 | 22 | 0 | 0 | Integer sequences, linear recurrences, and generating functions. | +| `dsp/mod.rs` | `dsp` | 37 | 0 | 0 | 0 | Digital signal processing: window functions, FIR/IIR filter design, resampling, and phase utilities. | +| `dsp/fir.rs` | `dsp::fir` | 996 | 18 | 3 | 1 | FIR filter design and application. | +| `dsp/iir.rs` | `dsp::iir` | 1,666 | 22 | 26 | 4 | Infinite impulse response filters: RBJ biquads, second-order-section cascades, and classical designs (Butterworth, Chebyshev I/II, elliptic,… | +| `dsp/phase.rs` | `dsp::phase` | 270 | 8 | 0 | 0 | Phase utilities: unwrapping (1D and Itoh 2D), phase-locked loops, interpolated zero crossings, and phase measurement against a reference tone. | +| `dsp/resample.rs` | `dsp::resample` | 513 | 10 | 0 | 0 | Sample-rate conversion: integer up/down sampling, polyphase rational resampling, windowed-sinc/linear/cubic interpolation, CIC decimation, and… | +| `dsp/windows.rs` | `dsp::windows` | 446 | 7 | 0 | 2 | Window functions for spectral analysis and FIR design. | +| `electromagnetism.rs` | `electromagnetism` | 822 | 60 | 0 | 0 | Classical electromagnetism, from Coulomb's law to radiating dipoles. | +| `electronics.rs` | `electronics` | 445 | 17 | 0 | 0 | Semiconductor device physics. | +| `error.rs` | `error` | 103 | 0 | 0 | 2 | Error types shared by the numerical solvers. | +| `exact/mod.rs` | `exact` | 15 | 0 | 0 | 0 | Exact arithmetic: arbitrary-precision integers, exact rationals, arbitrary-precision binary floating point, polynomials, and continued fractions. | +| `exact/bigfloat.rs` | `exact::bigfloat` | 2,000 | 5 | 39 | 1 | Arbitrary-precision binary floating point. | +| `exact/bigint.rs` | `exact::bigint` | 1,463 | 0 | 41 | 1 | Arbitrary-precision signed integers. | +| `exact/contfrac.rs` | `exact::contfrac` | 524 | 10 | 0 | 0 | Continued fractions: expansions, convergents, the periodic expansion of a square root, Pell's equation, generalized continued fractions by the… | +| `exact/polynomial.rs` | `exact::polynomial` | 2,286 | 5 | 76 | 2 | Dense univariate polynomials with `f64` coefficients ([`Poly`]) and with exact rational coefficients ([`PolyQ`]). | +| `exact/rational.rs` | `exact::rational` | 1,079 | 8 | 26 | 1 | Exact rational arithmetic over [`BigInt`]. | +| `exact/symbolic.rs` | `exact::symbolic` | 1,882 | 3 | 29 | 3 | A small computer algebra system over expression trees. | +| `fem/mod.rs` | `fem` | 25 | 0 | 0 | 0 | Finite elements, finite-difference time domain, and spectral methods. | +| `fem/fdtd.rs` | `fem::fdtd` | 1,154 | 7 | 1 | 3 | Finite-difference time domain: Maxwell's equations on a Yee grid. | +| `fem/fem1d.rs` | `fem::fem1d` | 952 | 7 | 6 | 2 | One-dimensional finite elements for `-(p u')' + q u = f`. | +| `fem/fem2d.rs` | `fem::fem2d` | 1,901 | 16 | 8 | 1 | Triangular finite elements in the plane. | +| `fem/spectral_pde.rs` | `fem::spectral_pde` | 693 | 7 | 0 | 0 | Spectral methods: global basis functions instead of local ones. | +| `fields.rs` | `fields` | 211 | 0 | 10 | 2 | Uniform-grid scalar fields. | +| `finance/mod.rs` | `finance` | 25 | 0 | 0 | 0 | Quantitative finance: derivative pricing, interest rates, portfolio construction and risk measurement. | +| `finance/options.rs` | `finance::options` | 2,090 | 17 | 0 | 3 | Option pricing: closed forms, lattices, Monte Carlo and a PDE solver. | +| `finance/portfolio.rs` | `finance::portfolio` | 865 | 16 | 0 | 0 | Portfolio construction and performance measurement. | +| `finance/rates.rs` | `finance::rates` | 1,388 | 19 | 1 | 2 | Interest rates: discounting, bonds, curves and short-rate models. | +| `finance/risk.rs` | `finance::risk` | 751 | 7 | 0 | 1 | Risk measurement: value at risk, expected shortfall, backtesting. | +| `fluid_instabilities.rs` | `fluid_instabilities` | 451 | 19 | 0 | 0 | When a fluid configuration stops being stable, and how fast it comes apart. | +| `fluids.rs` | `fluids` | 709 | 45 | 0 | 0 | Fluid statics and single-phase flow. | +| `fractals/mod.rs` | `fractals` | 642 | 10 | 5 | 1 | Fractals: escape-time sets, attractors, automata and noise. | +| `fractals/attractors.rs` | `fractals::attractors` | 1,104 | 42 | 8 | 3 | Strange attractors: 3-D chaotic flows and 2-D chaotic maps with trajectory integration, Lyapunov spectra (Benettin renormalization), Kaplan-Yorke… | +| `fractals/automata.rs` | `fractals::automata` | 2,881 | 29 | 63 | 16 | Cellular automata and growth models: elementary 1-D rules, life-like 2-D automata with pattern/RLE placement, cyclic CA, Langton's ant and… | +| `fractals/escape_time.rs` | `fractals::escape_time` | 1,044 | 24 | 0 | 3 | Escape-time fractals: a generic iteration engine with smooth coloring, orbit traps, and distance estimation, the classic quadratic families… | +| `fractals/ifs.rs` | `fractals::ifs` | 924 | 18 | 12 | 3 | Iterated function systems: the chaos game and deterministic attractor construction (Barnsley, "Fractals Everywhere", 1988), Moran similarity… | +| `fractals/lsystem.rs` | `fractals::lsystem` | 1,056 | 25 | 12 | 4 | Lindenmayer systems: parallel string rewriting with simple, stochastic, and context-sensitive rules, 2-D and 3-D turtle interpretation of the ABOP… | +| `fractals/noise.rs` | `fractals::noise` | 1,803 | 19 | 21 | 8 | Coherent noise: Perlin gradient noise (Perlin 2002), OpenSimplex2 (ported from K.jpg's reference implementation), value noise, Worley cellular… | +| `general_relativity.rs` | `general_relativity` | 427 | 23 | 0 | 0 | General relativity: black holes and cosmology. | +| `geometry/mod.rs` | `geometry` | 453 | 30 | 0 | 0 | Areas, volumes and surface areas of the standard shapes. | +| `geometry/delaunay.rs` | `geometry::delaunay` | 262 | 3 | 0 | 0 | Delaunay triangulation and Voronoi diagrams in the plane. | +| `geometry/geodesy.rs` | `geometry::geodesy` | 342 | 5 | 2 | 1 | Geodesy on a reference ellipsoid. | +| `geometry/hull.rs` | `geometry::hull` | 310 | 4 | 0 | 0 | Convex hulls and polygon predicates. | +| `geometry/mesh.rs` | `geometry::mesh` | 155 | 0 | 5 | 2 | Minimal indexed triangle mesh with ray intersection, backfilling the Part 2 `Mesh` type consumed by acoustics ray tracing and display helpers. | +| `geophysics.rs` | `geophysics` | 483 | 22 | 0 | 0 | The solid Earth: gravity, seismology, and heat. | +| `graph/mod.rs` | `graph` | 12 | 0 | 0 | 0 | Graphs: representation and structure, shortest paths, network flow, matchings, spectral graph theory, colouring, and drawing. | +| `graph/coloring.rs` | `graph::coloring` | 1,649 | 20 | 0 | 1 | Colouring, cliques, independent sets, and covers. | +| `graph/core.rs` | `graph::core` | 2,862 | 24 | 41 | 1 | Graphs: representation, structural queries, generators, and products. | +| `graph/flow.rs` | `graph::flow` | 1,519 | 14 | 0 | 0 | Network flow: maximum flow, minimum cut, and the problems that reduce to them. | +| `graph/layout.rs` | `graph::layout` | 1,935 | 15 | 0 | 0 | Graph drawing: where to put the vertices. | +| `graph/matching.rs` | `graph::matching` | 1,399 | 10 | 0 | 0 | Matchings: bipartite, general, weighted, and stable. | +| `graph/paths.rs` | `graph::paths` | 2,133 | 26 | 0 | 1 | Shortest paths, spanning trees, and tours. | +| `graph/spectral.rs` | `graph::spectral` | 1,984 | 32 | 0 | 0 | Spectral graph theory: Laplacians, centralities, resistances, and community detection. | +| `gravitation.rs` | `gravitation` | 236 | 14 | 0 | 0 | Newtonian gravity and two-body orbits. | +| `information_theory.rs` | `information_theory` | 367 | 16 | 0 | 0 | Shannon information: entropy, divergence, and channel capacity. | +| `learn/mod.rs` | `learn` | 16 | 0 | 0 | 0 | Learning algorithms, written to be read rather than to be fast. | +| `learn/cluster.rs` | `learn::cluster` | 1,295 | 13 | 2 | 3 | Clustering, mixture models and nearest neighbours. | +| `learn/gp.rs` | `learn::gp` | 839 | 1 | 12 | 2 | Gaussian process regression. | +| `learn/nn.rs` | `learn::nn` | 1,163 | 2 | 14 | 4 | Feed-forward networks, trained by backpropagation. | +| `learn/tree.rs` | `learn::tree` | 900 | 11 | 0 | 4 | Decision trees, random forests and gradient boosting. | +| `linalg/mod.rs` | `linalg` | 970 | 10 | 24 | 2 | Dense and sparse linear algebra. | +| `linalg/cholesky.rs` | `linalg::cholesky` | 147 | 2 | 0 | 0 | Cholesky factorization of symmetric positive-definite matrices. | +| `linalg/eigen.rs` | `linalg::eigen` | 492 | 2 | 0 | 1 | Eigenvalue solvers. | +| `linalg/lu.rs` | `linalg::lu` | 223 | 2 | 4 | 1 | LU decomposition with partial pivoting (Doolittle form). | +| `linalg/matrix.rs` | `linalg::matrix` | 344 | 0 | 16 | 1 | Dense row-major matrix of `f64`. | +| `linalg/qr.rs` | `linalg::qr` | 205 | 2 | 0 | 1 | QR decomposition by Householder reflections and least-squares solve. | +| `linalg/sparse.rs` | `linalg::sparse` | 360 | 2 | 4 | 1 | Compressed sparse row (CSR) matrices and conjugate-gradient solvers. | +| `linalg/svd.rs` | `linalg::svd` | 321 | 4 | 0 | 1 | Singular value decomposition by one-sided Jacobi rotations. | +| `linalg/tridiagonal.rs` | `linalg::tridiagonal` | 233 | 2 | 0 | 0 | Tridiagonal linear solve (Thomas algorithm). | +| `magnetohydrodynamics.rs` | `magnetohydrodynamics` | 359 | 19 | 0 | 0 | Magnetohydrodynamics: a conducting fluid and the field frozen into it. | +| `manifold/mod.rs` | `manifold` | 105 | 0 | 0 | 0 | Manifolds and higher-dimensional geometry: generic n-dimensional vectors and tensors, metric-driven curvature, and (in later modules) geodesics,… | +| `manifold/clifford.rs` | `manifold::clifford` | 2,830 | 93 | 45 | 2 | Clifford (geometric) algebras Cl(p, q, r): a dense multivector type over any signature, with the geometric/outer/inner products, versors and… | +| `manifold/dec.rs` | `manifold::dec` | 1,618 | 3 | 30 | 1 | Discrete exterior calculus on triangle meshes: exterior derivatives, diagonal Hodge stars, Laplacians, Hodge decomposition, harmonic forms and… | +| `manifold/embedding.rs` | `manifold::embedding` | 1,624 | 40 | 0 | 0 | Manifold learning and dimensionality reduction: spectral embeddings (MDS, Isomap, LLE, Laplacian eigenmaps, diffusion maps), PCA and kernel PCA,… | +| `manifold/geodesic.rs` | `manifold::geodesic` | 1,422 | 8 | 22 | 2 | Geodesics, parallel transport, Jacobi fields, and relativistic orbits, all driven by the finite-difference [`Metric`] machinery. | +| `manifold/hyperbolic.rs` | `manifold::hyperbolic` | 1,710 | 43 | 9 | 2 | Hyperbolic geometry across the standard models: Poincare disk/ball, upper half-plane/space, Klein disk, and the hyperboloid, with isometries,… | +| `manifold/lie.rs` | `manifold::lie` | 3,225 | 17 | 108 | 15 | Lie groups and algebras: rotation and rigid-motion groups in 2/3/4 dimensions, SU(2) and SL(2) groups, matrix exponentials and logarithms,… | +| `manifold/metric.rs` | `manifold::metric` | 1,382 | 5 | 49 | 2 | Metric geometry on n-dimensional manifolds: a metric is a function from coordinates to a matrix g_ij, and everything else — Christoffel symbols,… | +| `manifold/polytope4.rs` | `manifold::polytope4` | 2,142 | 27 | 41 | 2 | Four-dimensional polytopes: the six regular 4-polytopes with their full combinatorics, prisms and products, projections and cross-sections, duals,… | +| `manifold/spacetime.rs` | `manifold::spacetime` | 1,556 | 30 | 30 | 5 | Special and general relativity: four-vectors and Lorentz transforms, Rindler and Kruskal coordinates, Schwarzschild and Kerr geodesics,… | +| `manifold/spherical.rs` | `manifold::spherical` | 1,671 | 67 | 0 | 0 | Spherical geometry: n-sphere maps, spherical trigonometry, map projections, the Hopf fibration, spherical harmonics and their transforms, sky… | +| `manifold/vecn.rs` | `manifold::vecn` | 1,146 | 3 | 50 | 2 | n-dimensional vectors and arbitrary-rank tensors: the generic machinery behind the metric-driven differential geometry in this module tree. | +| `materials/mod.rs` | `materials` | 17 | 0 | 0 | 0 | Reference property tables. | +| `materials/common.rs` | `materials::common` | 349 | 2 | 0 | 1 | Engineering solids: metals, alloys, polymers and ceramics. | +| `materials/elements.rs` | `materials::elements` | 2,632 | 5 | 0 | 3 | The 118 chemical elements. | +| `materials/fluids.rs` | `materials::fluids` | 308 | 2 | 0 | 1 | Common liquids. | +| `materials/gases.rs` | `materials::gases` | 242 | 2 | 0 | 1 | Common gases. | +| `math.rs` | `math` | 621 | 0 | 23 | 2 | Vectors and the crate's table of physical constants. | +| `mesh/mod.rs` | `mesh` | 1,071 | 0 | 32 | 1 | Indexed triangle meshes: construction, mass properties, cleanup, spatial queries, and OBJ/STL interchange. | +| `mesh/analyze.rs` | `mesh::analyze` | 1,201 | 20 | 0 | 1 | Mesh analysis: topology (manifoldness, orientation, boundary, components, genus), quality statistics, QEM decimation, discrete curvatures, and… | +| `mesh/generate.rs` | `mesh::generate` | 881 | 14 | 0 | 0 | Procedural mesh generators. | +| `mesh/isosurface.rs` | `mesh::isosurface` | 1,052 | 8 | 9 | 2 | Isosurface and isocontour extraction from sampled scalar fields: marching squares/cubes/tetrahedra, surface nets, dual contouring, and metaballs. | +| `mesh/parameterize.rs` | `mesh::parameterize` | 652 | 7 | 0 | 1 | Mesh parameterization: closed-form spherical/planar/cylindrical projections, harmonic (cotangent-Laplace) disk parameterization with fixed… | +| `mesh/subdivide.rs` | `mesh::subdivide` | 616 | 9 | 3 | 1 | Subdivision surfaces (Loop, Catmull-Clark, sqrt(3), midpoint) and Laplacian-family smoothing. | +| `mesh/surfaces.rs` | `mesh::surfaces` | 1,043 | 19 | 15 | 4 | Parametric surfaces: Bézier/B-spline/NURBS patches, classic surface constructions, differential geometry via fundamental forms, and a catalogue of… | +| `monte_carlo/mod.rs` | `monte_carlo` | 700 | 15 | 5 | 1 | Monte Carlo methods and the random number generator behind them. | +| `monte_carlo/quasi.rs` | `monte_carlo::quasi` | 282 | 2 | 6 | 2 | Quasi-random (low-discrepancy) sequences: Sobol and Halton. | +| `neutronics.rs` | `neutronics` | 409 | 22 | 0 | 0 | Reactor physics: criticality, neutron diffusion, and shielding. | +| `nonlinear.rs` | `nonlinear` | 432 | 13 | 0 | 0 | Chaos in low-dimensional systems. | +| `nuclear.rs` | `nuclear` | 303 | 20 | 0 | 0 | Radioactive decay, nuclear binding, and dosimetry. | +| `numerical/mod.rs` | `numerical` | 424 | 0 | 0 | 0 | Numerical methods: quadrature, root finding, ODE solvers, and interpolation. | +| `numerical/bvp.rs` | `numerical::bvp` | 201 | 2 | 0 | 0 | Two-point boundary value problems. | +| `numerical/integrate.rs` | `numerical::integrate` | 270 | 8 | 0 | 1 | Numerical integration (quadrature) rules. | +| `numerical/interpolate.rs` | `numerical::interpolate` | 648 | 6 | 9 | 2 | Interpolation routines. | +| `numerical/ode/mod.rs` | `numerical::ode` | 11 | 0 | 0 | 0 | Ordinary differential equation solvers. | +| `numerical/ode/adaptive.rs` | `numerical::ode::adaptive` | 309 | 2 | 0 | 1 | Adaptive Runge-Kutta integration: Dormand-Prince 5(4). | +| `numerical/ode/explicit.rs` | `numerical::ode::explicit` | 63 | 4 | 0 | 0 | Explicit fixed-step ODE integrators. | +| `numerical/ode/implicit.rs` | `numerical::ode::implicit` | 232 | 2 | 0 | 0 | Implicit (stiff-stable) ODE steps: backward Euler and BDF2. | +| `numerical/ode/symplectic.rs` | `numerical::ode::symplectic` | 125 | 3 | 0 | 0 | Symplectic integrators for second-order systems x'' = a(x). | +| `numerical/roots.rs` | `numerical::roots` | 280 | 7 | 0 | 0 | Scalar and polynomial root finding. | +| `optics.rs` | `optics` | 348 | 20 | 0 | 0 | Geometric and wave optics. | +| `optimization/mod.rs` | `optimization` | 828 | 11 | 0 | 0 | Optimization: continuous, combinatorial, and strategic. | +| `optimization/convex.rs` | `optimization::convex` | 2,410 | 35 | 0 | 0 | Convex optimisation: gradient methods, quasi-Newton methods, proximal splitting, and constrained solvers. | +| `optimization/game_theory.rs` | `optimization::game_theory` | 3,326 | 41 | 0 | 11 | Game theory: equilibria, dynamics, cooperative solution concepts, auctions, and two-player search. | +| `optimization/integer.rs` | `optimization::integer` | 2,694 | 33 | 0 | 1 | Integer programming, dynamic programming, and combinatorial search. | +| `optimization/least_squares.rs` | `optimization::least_squares` | 371 | 3 | 0 | 1 | Nonlinear least squares: Levenberg-Marquardt. | +| `optimization/lp.rs` | `optimization::lp` | 2,600 | 13 | 8 | 3 | Linear programming: the simplex method, interior point methods, duality, and the classical models that reduce to a linear program. | +| `optimization/metaheuristics.rs` | `optimization::metaheuristics` | 1,577 | 15 | 0 | 2 | Derivative-free and population-based optimisation, and the benchmark landscapes used to tell one method from another. | +| `optimization/network.rs` | `optimization::network` | 1,383 | 17 | 1 | 1 | Network models and scheduling: project planning, flows on networks, and the sequencing rules that provably optimise a stated objective. | +| `particle_physics.rs` | `particle_physics` | 402 | 20 | 0 | 0 | Relativistic kinematics and scattering for particle collisions. | +| `patterns/mod.rs` | `patterns` | 14 | 0 | 0 | 0 | Geometric patterns: polygon algorithms, sampling distributions, phyllotaxis, tilings, symmetry groups, packings, space-filling curves, polyhedra,… | +| `patterns/aperiodic.rs` | `patterns::aperiodic` | 1,807 | 13 | 0 | 2 | Aperiodic tilings: Penrose P2 (kite/dart) and P3 (rhombs) by Robinson-triangle deflation, de Bruijn multigrid projection, Ammann-Beenker, the hat… | +| `patterns/knots.rs` | `patterns::knots` | 831 | 20 | 0 | 0 | Knots and space curves: parametric knot families, Frenet and rotation-minimizing frames, curvature/torsion estimates, and the classical knot… | +| `patterns/packing.rs` | `patterns::packing` | 1,130 | 17 | 0 | 0 | Circle and sphere packings: Descartes/Apollonian circles, lattice packings, random sequential adsorption, Doyle spirals, Ford circles, Steiner… | +| `patterns/phyllotaxis.rs` | `patterns::phyllotaxis` | 490 | 18 | 0 | 0 | Phyllotactic patterns and spirals: Vogel sunflowers, Fibonacci point sets, the classical spiral family, and parastichy analysis. | +| `patterns/polygon_ops.rs` | `patterns::polygon_ops` | 2,022 | 29 | 0 | 1 | 2-D polygon algorithms: triangulation, simplification, offsetting, Minkowski sums, boolean operations, clipping, decomposition, hulls, skeletons,… | +| `patterns/polyhedra.rs` | `patterns::polyhedra` | 2,032 | 32 | 14 | 2 | Polyhedra: Platonic/Archimedean/Catalan/Johnson solids, Goldberg and geodesic polyhedra, and Conway polyhedron operators. | +| `patterns/sampling.rs` | `patterns::sampling` | 1,220 | 27 | 0 | 0 | Random and low-discrepancy sampling: Poisson disk (Bridson), blue-noise ranking, stratified jitter, uniform samplers over shapes, random polygons… | +| `patterns/space_filling.rs` | `patterns::space_filling` | 755 | 20 | 0 | 0 | Space-filling curves and locality-preserving orders: Hilbert (2-D and 3-D), Peano, Morton/Z-order, Gray codes, and L-system curves (Sierpiński… | +| `patterns/symmetry.rs` | `patterns::symmetry` | 996 | 14 | 7 | 4 | Plane symmetry groups (the 17 wallpaper groups and 7 frieze groups), lattices, 3-D point groups, symmetry detection, and Hankin-style Islamic star… | +| `patterns/tilings.rs` | `patterns::tilings` | 1,107 | 10 | 18 | 3 | Plane tilings: regular and Archimedean (uniform) tilings, their Laves duals, hex-grid coordinate algebra, and a few classic non-edge-to-edge… | +| `photonics.rs` | `photonics` | 485 | 26 | 0 | 0 | Laser beams, optical fibre, and interferometry. | +| `plasma.rs` | `plasma` | 297 | 16 | 0 | 0 | Plasma parameters: the characteristic lengths, frequencies and speeds. | +| `propulsion.rs` | `propulsion` | 361 | 15 | 0 | 0 | Rocket propulsion and impulsive orbital transfers. | +| `quantum/mod.rs` | `quantum` | 411 | 27 | 0 | 0 | Quantum mechanics: the elementary relations here, with the wavefunction machinery and the Schrodinger solvers in submodules. | +| `quantum/algorithms.rs` | `quantum::algorithms` | 1,707 | 24 | 0 | 0 | Quantum algorithms on the state-vector simulator. | +| `quantum/circuit.rs` | `quantum::circuit` | 2,460 | 15 | 77 | 5 | A state-vector quantum circuit simulator, with density matrices and noise channels. | +| `quantum/schrodinger.rs` | `quantum::schrodinger` | 2,607 | 25 | 0 | 1 | Solvers for the Schrodinger equation, stationary and time dependent. | +| `quantum/solid_state.rs` | `quantum::solid_state` | 1,685 | 38 | 0 | 0 | Electrons and phonons in crystals: bands, densities of states, transport, and the standard model systems. | +| `quantum/spin.rs` | `quantum::spin` | 1,703 | 19 | 10 | 1 | Spin operators, quantum magnets, and magnetic resonance. | +| `quantum/wavefunction.rs` | `quantum::wavefunction` | 1,368 | 13 | 19 | 1 | One-dimensional wavefunctions, the standard eigenstates, and phase-space distributions. | +| `quaternion.rs` | `quaternion` | 562 | 2 | 16 | 1 | Unit quaternions for 3-D rotation. | +| `radiation.rs` | `radiation` | 335 | 14 | 0 | 0 | Thermal radiation and radiative transfer. | +| `relativity.rs` | `relativity` | 302 | 18 | 0 | 0 | Special relativity. | +| `resonance/mod.rs` | `resonance` | 42 | 0 | 0 | 0 | Resonance and vibration: single and coupled oscillators, acoustic and electromagnetic cavities, nonlinear resonance, and structural dynamics. | +| `resonance/cavity.rs` | `resonance::cavity` | 931 | 32 | 13 | 3 | Resonant cavities and structures: RLC circuits, Helmholtz resonators, strings, air columns, membranes, plates, beams, rooms, optical etalons, and… | +| `resonance/coupled.rs` | `resonance::coupled` | 828 | 6 | 18 | 1 | Coupled linear oscillators: normal modes, modal superposition, receptance, classic two-body systems, Kuramoto synchronization, and… | +| `resonance/nonlinear.rs` | `resonance::nonlinear` | 704 | 22 | 0 | 0 | Nonlinear resonance: the Duffing and van der Pol oscillators, parametric (Mathieu) stability, Fano interference, synchronization pulling/locking,… | +| `resonance/oscillator.rs` | `resonance::oscillator` | 636 | 9 | 19 | 2 | The damped harmonic oscillator m·x″ + c·x′ + k·x = F(t): closed-form responses in every damping regime, frequency-domain descriptions, and… | +| `resonance/structural.rs` | `resonance::structural` | 1,134 | 6 | 19 | 1 | Structural dynamics: finite-element bars and beams, modal analysis with general (consistent) mass matrices, Rayleigh damping, implicit time… | +| `rf.rs` | `rf` | 440 | 28 | 0 | 0 | Radio-frequency engineering: links, lines and noise. | +| `signal_processing/mod.rs` | `signal_processing` | 708 | 16 | 0 | 0 | Time-domain signal operations and test waveforms. | +| `sim/mod.rs` | `sim` | 21 | 0 | 0 | 0 | Time-stepping simulation engines. | +| `sim/cloth_sim.rs` | `sim::cloth_sim` | 970 | 2 | 10 | 3 | Verlet cloth and rope with spring constraints. | +| `sim/em_sim.rs` | `sim::em_sim` | 638 | 0 | 15 | 2 | FDTD electromagnetic simulation in one and two dimensions. | +| `sim/fluid_sim.rs` | `sim::fluid_sim` | 1,161 | 0 | 17 | 3 | Compact fluid solvers: column, shallow water, and 2-D Euler. | +| `sim/heat_sim.rs` | `sim::heat_sim` | 774 | 0 | 22 | 3 | Heat conduction and convection-diffusion on a grid. | +| `sim/rigid_body.rs` | `sim::rigid_body` | 681 | 2 | 19 | 2 | Rigid body dynamics in three dimensions. | +| `sim/wave_sim.rs` | `sim::wave_sim` | 682 | 0 | 14 | 2 | The wave equation in one and two dimensions. | +| `solid_mechanics.rs` | `solid_mechanics` | 380 | 23 | 0 | 0 | Strength of materials: stress, strain, elastic constants and beams. | +| `spatial/mod.rs` | `spatial` | 33 | 0 | 0 | 0 | Spatial data structures, transforms, geometric primitives, and queries. | +| `spatial/bvh.rs` | `spatial::bvh` | 513 | 0 | 10 | 1 | Bounding volume hierarchy over axis-aligned boxes. | +| `spatial/contain.rs` | `spatial::contain` | 527 | 20 | 0 | 0 | Orientation predicates and containment tests. | +| `spatial/distance.rs` | `spatial::distance` | 495 | 18 | 0 | 0 | Closest-point queries and set distances. | +| `spatial/frame.rs` | `spatial::frame` | 215 | 0 | 15 | 1 | Rigid coordinate frames (origin + unit-quaternion rotation). | +| `spatial/intersect.rs` | `spatial::intersect` | 908 | 23 | 0 | 1 | Intersection tests between the spatial primitives. | +| `spatial/kdtree.rs` | `spatial::kdtree` | 510 | 0 | 9 | 2 | k-d trees (3-D and 2-D) with median splits, plus a uniform spatial hash for broadphase neighbor queries. | +| `spatial/mat4.rs` | `spatial::mat4` | 504 | 0 | 21 | 1 | 4×4 homogeneous transform matrix (row-major storage, column-vector convention: p' = M·p). | +| `spatial/octree.rs` | `spatial::octree` | 342 | 1 | 2 | 1 | Barnes-Hut octree for N-body force approximation. | +| `spatial/primitives.rs` | `spatial::primitives` | 1,128 | 0 | 63 | 15 | Geometric primitive types shared by the intersection, distance, containment, and acceleration modules. | +| `spatial/projective.rs` | `spatial::projective` | 447 | 8 | 5 | 1 | Homogeneous 2-D projective geometry: points, lines, cross ratios, and plane homographies (Hartley & Zisserman, *Multiple View Geometry*, ch. | +| `spatial/quadtree.rs` | `spatial::quadtree` | 359 | 0 | 7 | 1 | Point quadtree with bucket capacity and depth limit. | +| `spatial/sdf.rs` | `spatial::sdf` | 731 | 37 | 0 | 0 | Signed distance fields: primitives, combinators, domain operators, and queries (sphere tracing, normals, AO, soft shadows). | +| `spatial/transform2d.rs` | `spatial::transform2d` | 308 | 0 | 15 | 1 | 2-D affine transforms stored as 3×3 homogeneous matrices (last row 0 0 1), column-vector convention: p' = M·p. | +| `special/mod.rs` | `special` | 26 | 0 | 0 | 0 | Special functions: error function family, gamma family, and beta functions. | +| `special/bessel.rs` | `special::bessel` | 528 | 12 | 0 | 0 | Bessel functions of integer order. | +| `special/beta.rs` | `special::beta` | 145 | 2 | 0 | 0 | Beta function and regularized incomplete beta. | +| `special/elliptic.rs` | `special::elliptic` | 333 | 7 | 0 | 0 | Elliptic integrals and physical applications. | +| `special/erf.rs` | `special::erf` | 335 | 3 | 0 | 0 | Error function family. | +| `special/expint.rs` | `special::expint` | 126 | 2 | 0 | 0 | Exponential integrals Ei(x) and E1(x). | +| `special/gamma.rs` | `special::gamma` | 219 | 4 | 0 | 0 | Gamma function family. | +| `special/legendre.rs` | `special::legendre` | 243 | 4 | 0 | 0 | Legendre polynomials, associated Legendre functions, real spherical harmonics, and Gauss-Legendre quadrature nodes. | +| `statistical_mechanics/mod.rs` | `statistical_mechanics` | 441 | 21 | 0 | 0 | Statistical mechanics: the elementary relations here, with lattice models and Monte Carlo in submodules. | +| `statistical_mechanics/ising.rs` | `statistical_mechanics::ising` | 2,004 | 13 | 23 | 4 | The Ising model and its relatives, by Monte Carlo. | +| `statistical_mechanics/kinetics.rs` | `statistical_mechanics::kinetics` | 2,806 | 36 | 3 | 2 | Chemical kinetics: rate laws, deterministic and stochastic reaction networks, enzyme saturation, equilibrium composition, oscillating mechanisms,… | +| `statistical_mechanics/lattice_models.rs` | `statistical_mechanics::lattice_models` | 1,199 | 17 | 0 | 0 | Lattice models: percolation, walks, growth, and avalanches. | +| `statistical_mechanics/md.rs` | `statistical_mechanics::md` | 3,237 | 12 | 36 | 3 | Molecular dynamics: pair potentials, a cell-list force evaluation, a symplectic integrator, thermostats and barostats, and the structural and… | +| `statistics/mod.rs` | `statistics` | 288 | 2 | 0 | 0 | Statistics: descriptive measures, probability distributions, and Fourier utilities. | +| `statistics/descriptive.rs` | `statistics::descriptive` | 114 | 12 | 0 | 0 | Descriptive statistics, error propagation, and weighted means. | +| `statistics/distributions.rs` | `statistics::distributions` | 1,013 | 7 | 13 | 12 | Probability distributions: densities, mass functions, and CDFs. | +| `statistics/fourier.rs` | `statistics::fourier` | 56 | 4 | 0 | 0 | Discrete Fourier transform utilities. | +| `statistics/inference.rs` | `statistics::inference` | 415 | 10 | 0 | 1 | Hypothesis tests and confidence intervals. | +| `statistics/resampling.rs` | `statistics::resampling` | 239 | 4 | 0 | 1 | Resampling methods: bootstrap, BCa bootstrap, permutation tests, and the jackknife. | +| `stochastic/mod.rs` | `stochastic` | 11 | 0 | 0 | 0 | Stochastic processes: Markov chains, Markov chain Monte Carlo, and hidden state models. | +| `stochastic/extreme.rs` | `stochastic::extreme` | 1,852 | 27 | 0 | 1 | Extreme value theory and copulas: the distribution of maxima, the distribution of exceedances, and the dependence structure between them. | +| `stochastic/hmm.rs` | `stochastic::hmm` | 1,451 | 4 | 26 | 4 | Hidden state models: hidden Markov models, smoothing, and particle filters. | +| `stochastic/markov.rs` | `stochastic::markov` | 1,952 | 0 | 37 | 3 | Finite Markov chains and Markov chain Monte Carlo. | +| `stochastic/point_process.rs` | `stochastic::point_process` | 1,373 | 25 | 0 | 0 | Point processes: random collections of points in time or space. | +| `stochastic/queueing.rs` | `stochastic::queueing` | 1,933 | 16 | 8 | 4 | Queueing theory: birth-death queues, Erlang loss and delay formulas, networks of queues, and continuous-time Markov chains. | +| `stochastic/rmt.rs` | `stochastic::rmt` | 1,217 | 18 | 0 | 0 | Random matrix theory: the classical ensembles, their limiting spectral laws, and the local statistics that distinguish correlated spectra from… | +| `stochastic/sde.rs` | `stochastic::sde` | 1,939 | 32 | 0 | 1 | Stochastic differential equations: simulation, convergence, and the densities the paths are distributed by. | +| `stochastic/timeseries.rs` | `stochastic::timeseries` | 3,979 | 28 | 32 | 6 | Time series analysis: correlation structure, stationarity, ARMA models, smoothing, volatility, and change detection. | +| `thermodynamics.rs` | `thermodynamics` | 808 | 52 | 0 | 0 | Thermodynamics: gases, heat transfer, cycles and phase change. | +| `transforms/mod.rs` | `transforms` | 54 | 0 | 0 | 0 | Discrete transforms: FFT (any length), DCT/DST, STFT, wavelets, Hilbert, Laplace inversion, Radon, and spectral estimation. | +| `transforms/dct.rs` | `transforms::dct` | 489 | 12 | 0 | 1 | Discrete cosine, sine, and Hartley transforms. | +| `transforms/fft.rs` | `transforms::fft` | 962 | 21 | 5 | 1 | Fast Fourier transforms. | +| `transforms/hilbert.rs` | `transforms::hilbert` | 570 | 13 | 0 | 0 | Hilbert transform, analytic signals, modulation, empirical mode decomposition, and causality (Kramers-Kronig) tools. | +| `transforms/laplace.rs` | `transforms::laplace` | 435 | 8 | 0 | 0 | Laplace-domain tools: numerical inverse transforms (fixed-Talbot and Gaver-Stehfest), the z-transform, transfer-function responses, and a discrete… | +| `transforms/radon.rs` | `transforms::radon` | 619 | 9 | 0 | 1 | Radon transform and tomographic reconstruction, plus Hankel/Abel transforms and Hough voting. | +| `transforms/spectral.rs` | `transforms::spectral` | 808 | 18 | 0 | 0 | Spectral estimation: periodogram, Welch averaging, multitaper (DPSS), parametric AR models (Burg, Yule-Walker), MUSIC, cross-spectra, coherence,… | +| `transforms/stft.rs` | `transforms::stft` | 695 | 10 | 8 | 1 | Short-time Fourier transform, spectrograms, Goertzel, chirp-z, and constant-Q analysis. | +| `transforms/wavelet.rs` | `transforms::wavelet` | 1,022 | 16 | 0 | 4 | Discrete and continuous wavelet transforms. | +| `transforms/wavelet_tables.rs` | `transforms::wavelet_tables` | 699 | 0 | 0 | 0 | Canonical orthogonal/biorthogonal scaling-filter tables (values from PyWavelets `wavelets_coeffs.template.h`, which in turn credits the classical… | +| `trigonometry.rs` | `trigonometry` | 493 | 33 | 0 | 0 | Triangle solving, trigonometric identities, and hyperbolic functions. | +| `units/mod.rs` | `units` | 813 | 54 | 0 | 0 | Unit conversions, dimensional analysis and the CODATA constants. | +| `units/dimensional.rs` | `units::dimensional` | 974 | 7 | 0 | 0 | Dimensional analysis: Buckingham's theorem, the named groups, natural units and the Planck scale. | +| `units/quantity.rs` | `units::quantity` | 998 | 7 | 17 | 3 | Values that carry their dimensions. | +| `vector_calculus.rs` | `vector_calculus` | 1,195 | 14 | 0 | 0 | Vector calculus operators and field theory for physics grids. | +| `verification/mod.rs` | `verification` | 63 | 0 | 0 | 0 | Kani proof harnesses. | +| `verification/core.rs` | `verification::core` | 27 | 0 | 0 | 0 | Kani harnesses for `crate::core`. | +| `verification/linalg.rs` | `verification::linalg` | 27 | 0 | 0 | 0 | Kani harnesses for `crate::linalg`. | +| `verification/physics.rs` | `verification::physics` | 236 | 0 | 0 | 0 | Kani harnesses for the Part 1 physics and numerics core. | +| `verification/spatial.rs` | `verification::spatial` | 41 | 0 | 0 | 0 | Kani harnesses for `crate::spatial`. | +| `waves.rs` | `waves` | 784 | 48 | 0 | 0 | Wave propagation: mechanical, acoustic and seismic. | diff --git a/docs/ROADMAP_PART4.md b/docs/ROADMAP_PART4.md index 7cc52bb..5b7e668 100644 --- a/docs/ROADMAP_PART4.md +++ b/docs/ROADMAP_PART4.md @@ -1,5 +1,26 @@ # ROADMAP PART 4: discrete math, exact arithmetic, stochastic processes, optimization, quantum, statistical mechanics, domains +> **Status: COMPLETE.** All thirty planned sessions are delivered, plus the +> two cross-references in "Cross-references and shared additions" that were +> not in the session list: `units::dimensional::dimensional_check_formula` +> (the `exact::symbolic` tie-in) and the `constants_codata` consolidation. +> +> Delivered against this plan: `exact/`, `discrete/`, `graph/`, `codes/`, +> `stochastic/`, `optimization/`, `quantum/`, `statistical_mechanics/`, +> `biophysics/`, `finance/`, `astrophysics/`, `fem/`, `learn/` and `units/`. +> The crate went from 2,981 to 4,193 unit tests and from 107 to 577 property +> tests over the course of it. +> +> The document below is kept as written — it is the specification the work was +> built against, and the function signatures in it are the ones that shipped. +> Where a signature changed in implementation the reason is recorded in the +> commit that changed it. Three specification readings that the plan left +> genuinely ambiguous are documented in the code rather than here: +> `quadratic_diophantine_solve` as a definite form, `frobenius_number` with a +> unit coin, and `stern_brocot_nth` indexed breadth-first. +> +> See the README for what the library now contains. + Same rules as Parts 1-3. This part covers everything computational that the repo still lacks after 1-3: exact and big-number arithmetic, number theory, combinatorics, graphs, error-correcting codes, stochastic diff --git a/examples/guide_02_orbit.rs b/examples/guide_02_orbit.rs new file mode 100644 index 0000000..ed6527f --- /dev/null +++ b/examples/guide_02_orbit.rs @@ -0,0 +1,68 @@ +//! Guide, chapter 2: a spacecraft in orbit. +//! +//! Run with `cargo run --example guide_02_orbit`. This file is the source +//! for that chapter of `docs/GUIDE.md`, and CI runs it, so the guide +//! cannot describe code that does not work. + +use rust_physics_engine::astrophysics::orbital_elements::OrbitalElements; +use rust_physics_engine::math::constants::{EARTH_MASS, EARTH_RADIUS, G}; +use rust_physics_engine::math::Vec3; +use rust_physics_engine::propulsion::hohmann_delta_v; + +fn main() { + // The gravitational parameter is what orbital mechanics actually uses; + // G and M never appear apart. + let mu = G * EARTH_MASS; + + // A circular orbit 400 km up, near enough the ISS. + let r = EARTH_RADIUS + 400e3; + let speed = (mu / r).sqrt(); + let position = Vec3::new(r, 0.0, 0.0); + let velocity = Vec3::new(0.0, speed, 0.0); + + // Going from a state vector to elements is the first thing you do with + // tracking data, because elements are what you can reason about. + let elements = OrbitalElements::from_state_vectors(position, velocity, mu); + println!("circular orbit at 400 km"); + println!(" speed {:.0} m/s", speed); + println!(" semi-major {:.1} km", elements.semi_major_axis / 1e3); + println!(" eccentricity {:.2e}", elements.eccentricity); + println!(" period {:.1} min", elements.period(mu) / 60.0); + println!(" bound? {}", elements.is_bound()); + + // A circular orbit has e = 0 to within rounding, and its period is + // Kepler's third law. Both are worth asserting rather than eyeballing. + assert!(elements.eccentricity < 1e-12); + let kepler = 2.0 * std::f64::consts::PI * (r.powi(3) / mu).sqrt(); + assert!((elements.period(mu) - kepler).abs() < 1e-6); + + // Now raise it to geostationary. A Hohmann transfer is two burns: one + // to enter an ellipse that touches both circles, one to circularise. + let r_geo = 42_164e3; + let (dv1, dv2) = hohmann_delta_v(mu, r, r_geo); + println!(); + println!("Hohmann transfer to geostationary"); + println!(" burn 1 {:.0} m/s", dv1); + println!(" burn 2 {:.0} m/s", dv2); + println!(" total {:.0} m/s", dv1 + dv2); + + // Both burns are prograde, and the first is the larger of the two -- + // it does most of the work of raising the apoapsis. + assert!(dv1 > 0.0 && dv2 > 0.0); + assert!(dv1 > dv2); + + // The transfer ellipse touches both circles, so its semi-major axis is + // the mean of the two radii and its period follows. Half of that is the + // flight time. + let a_transfer = 0.5 * (r + r_geo); + let transfer_time = std::f64::consts::PI * (a_transfer.powi(3) / mu).sqrt(); + println!(" flight time {:.1} hours", transfer_time / 3600.0); + + // Check the ellipse really does touch both circles, via vis-viva: + // v² = μ(2/r − 1/a). The speed at its low point is the circular speed + // plus the first burn. + let v_peri = (mu * (2.0 / r - 1.0 / a_transfer)).sqrt(); + assert!((v_peri - (speed + dv1)).abs() < 1e-6); + println!(); + println!("vis-viva at perigee agrees with circular speed + burn 1"); +} diff --git a/examples/guide_03_signal.rs b/examples/guide_03_signal.rs new file mode 100644 index 0000000..d71491d --- /dev/null +++ b/examples/guide_03_signal.rs @@ -0,0 +1,99 @@ +//! Guide, chapter 3: finding a tone buried in noise, and filtering it out. +//! +//! Run with `cargo run --example guide_03_signal`. CI runs it too, so the +//! guide chapter built from this file cannot go stale. + +use rust_physics_engine::dsp::fir::{fir_apply, fir_lowpass}; +use rust_physics_engine::dsp::windows::WindowKind; +use rust_physics_engine::monte_carlo::Rng; +use rust_physics_engine::transforms::fft::rfft; +use rust_physics_engine::transforms::spectral::welch; + +fn main() { + let fs = 8_000.0; // sample rate, Hz + let n = 4_096; // a power of two, so the FFT is radix-2 + + // Two tones and a lot of noise. 440 Hz is the one we want; 2,600 Hz is + // interference we intend to filter away. + let mut rng = Rng::new(0x5EED_1234); + let signal: Vec = (0..n) + .map(|i| { + let t = i as f64 / fs; + let wanted = (2.0 * std::f64::consts::PI * 440.0 * t).sin(); + let interference = 0.8 * (2.0 * std::f64::consts::PI * 2_600.0 * t).sin(); + let noise = 1.5 * (rng.next_f64() - 0.5); + wanted + interference + noise + }) + .collect(); + + // rfft returns only the non-negative frequencies, which is all a real + // signal has: bin k is at k·fs/n Hz. + let spectrum = rfft(&signal); + let peak = |from: f64, to: f64| -> (f64, f64) { + let lo = (from * n as f64 / fs) as usize; + let hi = (to * n as f64 / fs) as usize; + let mut best = (0.0, 0.0); + for (k, c) in spectrum.iter().enumerate().take(hi + 1).skip(lo) { + let mag = (c.re * c.re + c.im * c.im).sqrt(); + if mag > best.1 { + best = (k as f64 * fs / n as f64, mag); + } + } + best + }; + + let (f_wanted, m_wanted) = peak(300.0, 600.0); + let (f_interf, m_interf) = peak(2_400.0, 2_800.0); + println!("before filtering"); + println!(" tone found at {f_wanted:.0} Hz (magnitude {m_wanted:.0})"); + println!(" interference at {f_interf:.0} Hz (magnitude {m_interf:.0})"); + + // The FFT recovers both tones despite noise at more than the amplitude + // of the signal, because the noise is spread across every bin while a + // sinusoid concentrates into one. + assert!((f_wanted - 440.0).abs() < 5.0); + assert!((f_interf - 2_600.0).abs() < 5.0); + + // A windowed-sinc low-pass. The cutoff is in cycles per sample, so + // 1,000 Hz at fs = 8 kHz is 0.125. More taps means a sharper edge. + let taps = fir_lowpass(101, 1_000.0 / fs, WindowKind::Hamming); + let filtered = fir_apply(&taps, &signal); + + let spectrum = rfft(&filtered[..n]); + let peak2 = |from: f64, to: f64| -> f64 { + let lo = (from * n as f64 / fs) as usize; + let hi = (to * n as f64 / fs) as usize; + spectrum[lo..=hi] + .iter() + .map(|c| (c.re * c.re + c.im * c.im).sqrt()) + .fold(0.0, f64::max) + }; + let after_wanted = peak2(300.0, 600.0); + let after_interf = peak2(2_400.0, 2_800.0); + println!(); + println!("after a 1 kHz low-pass"); + println!(" 440 Hz kept magnitude {after_wanted:.0}"); + println!(" 2.6 kHz rejected magnitude {after_interf:.0}"); + println!( + " rejection {:.0} dB", + 20.0 * (m_interf / after_interf.max(1e-12)).log10() + ); + + // The tone in the passband survives; the one in the stopband does not. + assert!(after_wanted > 0.5 * m_wanted, "the passband tone was attenuated"); + assert!(after_interf < 0.05 * m_interf, "the stopband tone survived"); + + // Welch's method trades frequency resolution for a variance reduction, + // by averaging periodograms over overlapping segments. It is the right + // tool when you want the noise floor rather than the exact peak. + let (freqs, psd) = welch(&signal, fs, 512, 256, WindowKind::Hann); + let loudest = psd + .iter() + .enumerate() + .max_by(|a, b| a.1.partial_cmp(b.1).unwrap()) + .map(|(i, _)| freqs[i]) + .unwrap(); + println!(); + println!("Welch PSD over {} segments peaks at {loudest:.0} Hz", n / 256 - 1); + assert!((loudest - 440.0).abs() < 20.0); +} diff --git a/examples/guide_04_fem.rs b/examples/guide_04_fem.rs new file mode 100644 index 0000000..1658f65 --- /dev/null +++ b/examples/guide_04_fem.rs @@ -0,0 +1,94 @@ +//! Guide, chapter 4: solving a differential equation, and proving the +//! answer converges at the rate the theory predicts. +//! +//! Run with `cargo run --example guide_04_fem`. CI runs it too. + +use rust_physics_engine::fem::fem1d::{ + convergence_rate, fem_1d_error_h1_seminorm, fem_1d_error_l2, fem_1d_poisson, + fem_1d_quadratic, Bc, Fem1dSolution, +}; +use std::f64::consts::PI; + +fn main() { + // Solve −u″ = f on [0, 1] with u(0) = u(1) = 0. + // + // Choosing f = π² sin(πx) means the exact answer is u = sin(πx), which + // is what makes the error measurable rather than merely plausible. A + // solver you cannot check against a closed form is a solver you are + // trusting rather than testing. + let f = |x: f64| PI * PI * (PI * x).sin(); + let exact = |x: f64| (PI * x).sin(); + let d_exact = |x: f64| PI * (PI * x).cos(); + + println!("−u\u{2033} = \u{3c0}\u{b2}sin(\u{3c0}x) on [0,1], u(0) = u(1) = 0"); + println!("exact solution u = sin(\u{3c0}x)\n"); + + // Refine the mesh and watch the error fall. + let counts = [8usize, 16, 32, 64, 128]; + let mut hs = Vec::new(); + let mut l2 = Vec::new(); + let mut h1 = Vec::new(); + + println!(" P1 elements"); + println!(" {:>6} {:>6} {:>12} {:>12}", "cells", "h", "L2 error", "H1 error"); + for &n in &counts { + let values = fem_1d_poisson(&f, 0.0, 1.0, (Bc::Dirichlet(0.0), Bc::Dirichlet(0.0)), n) + .expect("the Poisson problem is well posed"); + let solution = Fem1dSolution::new(0.0, 1.0, 1, values).expect("nodal values fit P1"); + + let h = 1.0 / n as f64; + let e_l2 = fem_1d_error_l2(&solution, &exact); + let e_h1 = fem_1d_error_h1_seminorm(&solution, &d_exact); + println!(" {n:>6} {h:>6.4} {e_l2:>12.3e} {e_h1:>12.3e}"); + hs.push(h); + l2.push(e_l2); + h1.push(e_h1); + } + + // The rate is the slope of log(error) against log(h). For linear + // elements the theory says 2 in L2 and 1 in H1 -- one order is lost to + // differentiating, because the energy norm measures the derivative. + let rate_l2 = convergence_rate(&l2, &hs).expect("enough refinements"); + let rate_h1 = convergence_rate(&h1, &hs).expect("enough refinements"); + println!("\n measured rate L2 {rate_l2:.2} H1 {rate_h1:.2}"); + println!(" theory L2 2.00 H1 1.00"); + assert!((rate_l2 - 2.0).abs() < 0.1, "L2 rate {rate_l2} is not 2"); + assert!((rate_h1 - 1.0).abs() < 0.1, "H1 rate {rate_h1} is not 1"); + + // Quadratic elements buy an order in each norm for the same mesh. + let one = |_: f64| 1.0; + let zero = |_: f64| 0.0; + let mut hs2 = Vec::new(); + let mut l2_p2 = Vec::new(); + + println!("\n P2 elements"); + println!(" {:>6} {:>6} {:>12}", "cells", "h", "L2 error"); + for &n in &counts[..4] { + let values = fem_1d_quadratic( + &one, + &zero, + &f, + 0.0, + 1.0, + (Bc::Dirichlet(0.0), Bc::Dirichlet(0.0)), + n, + ) + .expect("well posed"); + let solution = Fem1dSolution::new(0.0, 1.0, 2, values).expect("nodal values fit P2"); + let h = 1.0 / n as f64; + let e = fem_1d_error_l2(&solution, &exact); + println!(" {n:>6} {h:>6.4} {e:>12.3e}"); + hs2.push(h); + l2_p2.push(e); + } + let rate_p2 = convergence_rate(&l2_p2, &hs2).expect("enough refinements"); + println!("\n measured rate L2 {rate_p2:.2}"); + println!(" theory L2 3.00"); + assert!((rate_p2 - 3.0).abs() < 0.15, "P2 L2 rate {rate_p2} is not 3"); + + // What makes this a *proof* rather than a plot is that the rate is + // predicted before it is measured. An error that merely shrinks tells + // you nothing; an error that shrinks at exactly h² tells you the + // discretisation is the one you think it is. + println!("\nboth rates match the theory, so the discretisation is correct"); +} diff --git a/examples/guide_05_correctness.rs b/examples/guide_05_correctness.rs new file mode 100644 index 0000000..0b596e0 --- /dev/null +++ b/examples/guide_05_correctness.rs @@ -0,0 +1,110 @@ +//! Guide, chapter 5: the tools for not being wrong. +//! +//! Dimensions checked in the type, arithmetic without rounding, and +//! Buckingham's theorem as an exact null space. +//! +//! Run with `cargo run --example guide_05_correctness`. CI runs it too. + +use rust_physics_engine::exact::rational::Rational; +use rust_physics_engine::exact::symbolic::Expr; +use rust_physics_engine::units::dimensional::{buckingham_pi, dimensional_check_formula}; +use rust_physics_engine::units::quantity::{parse_quantity, unit_convert, Dim, Quantity}; + +fn main() { + // ---- 1. dimensions travel with the value ------------------------- + // + // The Mars Climate Orbiter was lost to arithmetic a computer performed + // correctly on numbers that meant something other than the receiving + // code assumed. A Quantity carries seven exponents, so the mistake + // becomes a type error instead of a trajectory. + let force = Quantity::newtons(4.45); + let distance = Quantity::meters(2.0); + let work = force.mul(&distance).expect("force times distance"); + + println!("dimensions"); + println!(" 4.45 N x 2 m = {:.2} {}", work.value, work.dim); + assert_eq!(work.dim, Dim::new(2, 1, -2, 0, 0, 0, 0)); // joules, exactly + + let time = Quantity::seconds(3.0); + println!(" adding a force to a time -> {}", force.add(&time).unwrap_err()); + assert!(force.add(&time).is_err()); + + // Square roots only exist when every exponent is even, which is a + // refusal rather than a rounding decision: there is no square root of + // a metre. + let area = Quantity::new(9.0, Dim::new(2, 0, 0, 0, 0, 0, 0)); + println!(" sqrt(9 m^2) = {:.1} {}", area.sqrt().unwrap().value, area.sqrt().unwrap().dim); + assert!(Quantity::meters(9.0).sqrt().is_err()); + + // Parsing and conversion, for when the units arrive as text. + let g = parse_quantity("9.81 m/s^2").expect("a readable quantity"); + println!(" \"9.81 m/s^2\" parses to {} {}", g.value, g.dim); + let mps = unit_convert(3.6, "km/h", "m/s").expect("same dimension"); + println!(" 3.6 km/h = {mps:.1} m/s"); + assert!((mps - 1.0).abs() < 1e-12); + + // ---- 2. checking a formula, not a number ------------------------- + // + // Both sides of `x + v` are perfectly good floats, so no amount of + // running the formula finds the mistake. Walking the expression does. + let vars = [ + ("l", Dim::LENGTH), + ("g", Dim::new(1, 0, -2, 0, 0, 0, 0)), + ("t", Dim::TIME), + ("omega", Dim::new(0, 0, -1, 0, 0, 0, 0)), + ]; + let over_g = Expr::pow(Expr::var("g"), Expr::c(-1.0)); + let pendulum = Expr::Sqrt(Box::new(Expr::mul(vec![Expr::var("l"), over_g]))); + println!("\nformula checking"); + println!(" sqrt(l/g) has dimension {}", dimensional_check_formula(&pendulum, &vars).unwrap()); + assert_eq!(dimensional_check_formula(&pendulum, &vars).unwrap(), Dim::TIME); + + // A transcendental needs a pure number, because its series adds x to + // x³. sin(omega*t) is meaningful; sin(t) is a missing timescale. + let good = Expr::Sin(Box::new(Expr::mul(vec![Expr::var("omega"), Expr::var("t")]))); + let bad = Expr::Sin(Box::new(Expr::var("t"))); + println!(" sin(omega*t) checks out; sin(t) does not"); + assert!(dimensional_check_formula(&good, &vars).is_ok()); + assert!(dimensional_check_formula(&bad, &vars).is_err()); + + // ---- 3. Buckingham's theorem, exactly ---------------------------- + // + // Pipe flow: density, speed, diameter, viscosity. Four quantities, + // three independent dimensions, so exactly one dimensionless group. + let pipe = [ + Dim::new(-3, 1, 0, 0, 0, 0, 0), // density kg/m^3 + Dim::new(1, 0, -1, 0, 0, 0, 0), // speed m/s + Dim::LENGTH, // diameter m + Dim::new(-1, 1, -1, 0, 0, 0, 0), // viscosity Pa s + ]; + let groups = buckingham_pi(&pipe).expect("a well-posed problem"); + println!("\nBuckingham's theorem"); + println!(" 4 quantities, rank 3 -> {} group", groups.len()); + let exponents: Vec = groups[0].iter().map(|r| format!("{r}")).collect(); + println!(" exponents (rho, u, d, mu): {}", exponents.join(", ")); + println!(" that is rho^-1 u^-1 d^-1 mu, which is 1/Re -- the theorem finds"); + println!(" a basis for the null space, not the name anybody gave it"); + assert_eq!(groups.len(), 1); + + // The computation runs over exact rationals, not floats, because a + // group is exactly in the null space or it is not -- and one that + // cancelled to 1e-16 would be a rounding error reported as physics. + println!(" computed over Rational, so the cancellation is exact, not 1e-16"); + assert!(groups[0].iter().all(|r| *r == Rational::from_i64(-1, 1) || *r == Rational::one())); + + // ---- 4. arithmetic without rounding ------------------------------ + let tenth = Rational::from_i64(1, 10); + let fifth = Rational::from_i64(1, 5); + let sum = tenth.add(&fifth); + println!("\nexact arithmetic"); + println!(" 0.1 + 0.2 in f64 = {:.17}", 0.1 + 0.2); + println!(" 1/10 + 1/5 exact = {sum}"); + assert_ne!(0.1 + 0.2, 0.3); + assert_eq!(sum, Rational::from_i64(3, 10)); + + // An f64 is a dyadic rational, and from_f64_exact gives the value it + // genuinely holds rather than the decimal it is printed as. + let as_stored = Rational::from_f64_exact(0.1).expect("finite"); + println!(" and 0.1 as an f64 is really {as_stored}"); + assert_ne!(as_stored, Rational::from_i64(1, 10)); +} diff --git a/examples/readme_quickstart.rs b/examples/readme_quickstart.rs new file mode 100644 index 0000000..aa4a865 --- /dev/null +++ b/examples/readme_quickstart.rs @@ -0,0 +1,33 @@ +//! The Quick start snippet from README.md, kept compiling so it cannot rot. +//! Any edit here must be mirrored in the README and vice versa. + +use rust_physics_engine::classical::projectile_range; +use rust_physics_engine::exact::rational::Rational; +use rust_physics_engine::math::constants::{C, G}; +use rust_physics_engine::units::quantity::{Dim, Quantity}; + +fn main() { + + // Ballistics: v₀ = 50 m/s, θ = 45°, g = 9.81 m/s² + let range = projectile_range(50.0, std::f64::consts::FRAC_PI_4, 9.81); + assert!((range - 254.841_997_961).abs() < 1e-9); + + // Constants come from one table. A black hole's Schwarzschild radius: + let solar_mass = 1.989e30; + let r_s = 2.0 * G * solar_mass / (C * C); // about 2.95 km + + // Quantities carry their dimensions, and addition checks them. + let v = Quantity::new(3.0, Dim::new(1, 0, -1, 0, 0, 0, 0)); // m/s + let t = Quantity::new(2.0, Dim::TIME); + let d = v.mul(&t).unwrap(); // 6 m — a length, exactly + assert!(v.add(&t).is_err()); // a velocity is not a time + + // Exact rational arithmetic over arbitrary-precision integers. + let third = Rational::from_i64(1, 3); + let one = third.mul(&Rational::from_i64(3, 1)); + assert_eq!(one, Rational::one()); // not 0.9999999999999999 + + println!("range = {range:.6} m"); + println!("r_s = {:.1} m", r_s); + println!("d = {} {}", d.value, d.dim); +} diff --git a/src/acoustics.rs b/src/acoustics.rs index 3099894..004ebc0 100644 --- a/src/acoustics.rs +++ b/src/acoustics.rs @@ -1,3 +1,16 @@ +//! Room acoustics, psychoacoustic scales, and musical pitch. +//! +//! Reverberation by Sabine (`RT60 = 0.161 V / A`) and by Eyring, which +//! differ in how they treat a very absorptive room: Sabine's formula is a +//! diffuse-field approximation that never reaches zero however absorptive +//! the surfaces, while Eyring's does. Room modes, critical distance and +//! the mass-law transmission loss follow. +//! +//! The perceptual scales -- mel, bark, ERB, A-weighting, equal-loudness +//! phon -- map physical frequency and level onto what a listener reports, +//! and are fits to listening data rather than derivations. Musical pitch +//! is here too: equal temperament, cents, and MIDI note conversion. + use crate::math::constants::PI; // ── Sabine constant: 0.161 (derived from 24×ln(10)/c ≈ 0.161 for speed of sound ~343 m/s) ── diff --git a/src/astrophysics/collisions.rs b/src/astrophysics/collisions.rs index 96cc45c..0aa62c8 100644 --- a/src/astrophysics/collisions.rs +++ b/src/astrophysics/collisions.rs @@ -1,3 +1,14 @@ +//! Impacts, mergers, and collision probability. +//! +//! Impact geometry and speed (including the gravitational focusing that +//! makes the impact speed at least the escape velocity, however slowly the +//! bodies approach), perfectly inelastic merger of mass and momentum, and +//! the energy released. +//! +//! Crater scaling and the collision probability for objects sharing a +//! volume of space follow, along with the debris-flux relations used for +//! orbital collision risk. + use crate::math::Vec3; use crate::math::constants::G; diff --git a/src/astrophysics/gravitational_waves.rs b/src/astrophysics/gravitational_waves.rs index d2ce23f..d039afd 100644 --- a/src/astrophysics/gravitational_waves.rs +++ b/src/astrophysics/gravitational_waves.rs @@ -1,3 +1,14 @@ +//! Gravitational radiation from a compact binary. +//! +//! Quadrupole-formula results for an inspiralling binary: the emitted +//! luminosity, the wave frequency (twice the orbital frequency), the +//! strain amplitude at a given distance, and the time remaining to merger. +//! +//! The chirp mass `ℳ = (m₁m₂)^(3/5)/(m₁+m₂)^(1/5)` is the combination +//! that governs all of them -- it is the parameter the inspiral waveform +//! actually determines, which is why it is measured far better than either +//! individual mass. + use crate::math::Vec3; use crate::math::constants::{G, C, PI}; diff --git a/src/astrophysics/habitable_zone.rs b/src/astrophysics/habitable_zone.rs index d035c7a..28e79e6 100644 --- a/src/astrophysics/habitable_zone.rs +++ b/src/astrophysics/habitable_zone.rs @@ -1,3 +1,14 @@ +//! Habitable zone boundaries and tidal locking. +//! +//! Inner and outer edges scale as the square root of the stellar +//! luminosity, with the conventional coefficients: 0.95 AU and 1.37 AU per +//! square root of a solar luminosity. +//! +//! Also the mass-luminosity relation for main-sequence stars, equilibrium +//! temperature for a given albedo, and the tidal locking timescale -- +//! which matters here because low-mass stars have close-in habitable +//! zones, so their habitable planets are likely to be locked. + use crate::math::constants; /// Solar luminosity L☉ (W), re-exported from [`constants`]. diff --git a/src/astrophysics/lagrange.rs b/src/astrophysics/lagrange.rs index 265bd90..ca9f0b4 100644 --- a/src/astrophysics/lagrange.rs +++ b/src/astrophysics/lagrange.rs @@ -1,3 +1,14 @@ +//! The five Lagrange points of the circular restricted three-body problem. +//! +//! L1, L2 and L3 lie on the line through the two masses and are found by +//! solving a quintic numerically; L4 and L5 sit at the vertices of +//! equilateral triangles with the two masses and are exact. +//! +//! The collinear points are unstable saddles -- a spacecraft there needs +//! station-keeping -- while L4 and L5 are stable for a mass ratio below +//! about 1/24.96, which is why Jupiter's Trojan asteroids stay put. +//! The Hill radius is here as well. + use crate::math::Vec3; /// Computes the Hill sphere radius: r_H = d (m / 3M)^(1/3). diff --git a/src/astrophysics/magnetosphere.rs b/src/astrophysics/magnetosphere.rs index d6da79d..056dfcf 100644 --- a/src/astrophysics/magnetosphere.rs +++ b/src/astrophysics/magnetosphere.rs @@ -1,3 +1,13 @@ +//! Planetary dipole fields and the magnetopause. +//! +//! The magnetic dipole field in vector form, field-line tracing by +//! integration along the field, and the magnetopause standoff distance -- +//! where magnetic pressure balances the solar wind's dynamic pressure, +//! which is what sets the size of a magnetosphere. +//! +//! Field strength falls as `1/r³`, so the standoff distance depends only +//! weakly (as the sixth root) on the wind pressure. + use crate::math::Vec3; use crate::math::constants::PI; diff --git a/src/astrophysics/mod.rs b/src/astrophysics/mod.rs index 7879fd6..bbb9a8b 100644 --- a/src/astrophysics/mod.rs +++ b/src/astrophysics/mod.rs @@ -1,3 +1,23 @@ +//! Astrodynamics and astrophysics. +//! +//! Orbits are the core. [`kepler`] solves Kepler's equation for elliptic, +//! parabolic and hyperbolic orbits; [`orbital_elements`] converts between +//! state vectors and Keplerian elements; [`maneuvers`] covers Hohmann and +//! bi-elliptic transfers, plane changes, phasing and J2 secular rates; and +//! [`lambert`] solves for the transfer orbit connecting two positions in a +//! given time. +//! +//! [`time_systems`] and [`coords`] are the bookkeeping that makes those +//! answers refer to anything real -- Julian dates, UT1/TAI/TT/TDB, +//! sidereal time, and the equatorial, ecliptic, galactic, horizontal and +//! ITRF frames with precession and nutation. +//! +//! Many-body gravity is handled by [`nbody`] with a leapfrog integrator +//! and [`octree`] for Barnes-Hut O(N log N) forces. The remaining modules +//! cover [`tidal`] forces and Roche limits, [`lagrange`] points, +//! [`gravitational_waves`], [`magnetosphere`] field-line tracing, +//! [`habitable_zone`] boundaries, and [`collisions`] and impact cratering. + pub mod nbody; /// Barnes-Hut octree (moved to `crate::spatial::octree`; re-exported here /// for backwards compatibility). diff --git a/src/astrophysics/nbody.rs b/src/astrophysics/nbody.rs index 415c603..dcd28bf 100644 --- a/src/astrophysics/nbody.rs +++ b/src/astrophysics/nbody.rs @@ -1,3 +1,17 @@ +//! Direct N-body gravitational simulation. +//! +//! Velocity Verlet integration, chosen because it is symplectic: it +//! conserves a nearby "shadow" energy exactly rather than drifting, so +//! orbits stay closed over long integrations where Runge-Kutta of the same +//! order would spiral. +//! +//! Softening replaces `1/r²` with `1/(r² + ε²)` to keep close encounters +//! from producing unbounded accelerations, at the cost of biasing the +//! force at short range. Includes energy and momentum diagnostics, and +//! system generators. +//! +//! Cost is O(N²) per step. For large N use [`crate::astrophysics::octree`]. + use crate::math::Vec3; use crate::math::constants::G; diff --git a/src/astrophysics/orbital_elements.rs b/src/astrophysics/orbital_elements.rs index 21f8367..2b1a6da 100644 --- a/src/astrophysics/orbital_elements.rs +++ b/src/astrophysics/orbital_elements.rs @@ -1,3 +1,18 @@ +//! Keplerian elements: conversion, propagation, and the anomalies. +//! +//! State vectors to elements and back -- semi-major axis, eccentricity, +//! inclination, longitude of ascending node, argument of periapsis and +//! true anomaly -- via the specific orbital energy, the angular momentum +//! and the eccentricity vector. +//! +//! The three anomalies (true, eccentric and mean) and the conversions +//! between them, with Kepler's equation solved by Newton iteration. +//! Periapsis and apoapsis distances and speeds, orbital period, and +//! propagation forward in time complete the module. +//! +//! For a solver that also handles parabolic and hyperbolic orbits and near +//! e = 1, see [`crate::astrophysics::kepler`]. + use crate::math::Vec3; use crate::math::constants::PI; diff --git a/src/astrophysics/tidal.rs b/src/astrophysics/tidal.rs index e1424fa..c390a4e 100644 --- a/src/astrophysics/tidal.rs +++ b/src/astrophysics/tidal.rs @@ -1,3 +1,14 @@ +//! Tidal forces and the Roche limit. +//! +//! The tidal acceleration is the *difference* in gravitational pull across +//! a body, so it falls as `1/r³` rather than `1/r²` -- which is why the +//! Moon raises larger tides on Earth than the far more massive Sun does. +//! +//! The Roche limit is given in both the rigid and fluid forms; the fluid +//! limit is the larger, because a fluid body deforms and so becomes easier +//! to pull apart. Tidal heating, the locking timescale and the tidal +//! tensor complete the module. + use crate::math::Vec3; use crate::math::constants::G; diff --git a/src/atmosphere.rs b/src/atmosphere.rs index 63534c2..d67302c 100644 --- a/src/atmosphere.rs +++ b/src/atmosphere.rs @@ -1,3 +1,15 @@ +//! The standard atmosphere, humidity, and near-surface wind. +//! +//! The barometric formula and the ISA lapse-rate model give pressure, +//! temperature and density against altitude, plus the pressure and density +//! altitudes an aircraft altimeter reports. Humidity is covered by the +//! Magnus formulation for dew point and relative humidity. +//! +//! Wind includes the power-law shear profile, the wind power density that +//! sets a turbine's available energy (`P/A = ½ρv³`, so a doubling of wind +//! speed is eight times the power), the Beaufort scale, and the Coriolis +//! parameter `f = 2Ω sin φ`. + use crate::math::constants; // Atmospheric constants diff --git a/src/audio/effects.rs b/src/audio/effects.rs index 3ec03bb..b908900 100644 --- a/src/audio/effects.rs +++ b/src/audio/effects.rs @@ -48,7 +48,7 @@ impl DelayLine { a * (1.0 - f) + b * f } - /// Alias of [`read`] for tap taps. + /// Alias of [`Self::read`]. #[must_use] pub fn tap(&self, d: usize) -> f64 { self.read(d) diff --git a/src/biophysics/mod.rs b/src/biophysics/mod.rs index a2b4800..cc273c2 100644 --- a/src/biophysics/mod.rs +++ b/src/biophysics/mod.rs @@ -111,7 +111,7 @@ pub fn nernst_potential(temperature: f64, z: f64, c_out: f64, c_in: f64) -> f64 } /// Goldman-Hodgkin-Katz voltage equation for K⁺, Na⁺, and Cl⁻. -/// Vm = (RT/F) × ln((Pk[K]o + Pna[Na]o + Pcl[Cl]i) / (Pk[K]i + Pna[Na]i + Pcl[Cl]o)) +/// `Vm = (RT/F) × ln((Pk[K]o + Pna[Na]o + Pcl[Cl]i) / (Pk[K]i + Pna[Na]i + Pcl[Cl]o))` pub fn goldman_potential( temperature: f64, pk: f64, @@ -138,12 +138,12 @@ pub fn resting_membrane_potential_typical() -> f64 { // ── Enzyme Kinetics ── -/// Michaelis-Menten kinetics: v = Vmax × [S] / (Km + [S]) +/// Michaelis-Menten kinetics: `v = Vmax × [S] / (Km + [S])` pub fn michaelis_menten(vmax: f64, km: f64, substrate: f64) -> f64 { vmax * substrate / (km + substrate) } -/// Competitive inhibition: v = Vmax × [S] / (Km(1 + [I]/Ki) + [S]) +/// Competitive inhibition: `v = Vmax × [S] / (Km(1 + [I]/Ki) + [S])` pub fn michaelis_menten_inhibited( vmax: f64, km: f64, @@ -155,7 +155,7 @@ pub fn michaelis_menten_inhibited( vmax * substrate / (km * (1.0 + inhibitor / ki) + substrate) } -/// Lineweaver-Burk transform: returns (1/[S], 1/v) for double-reciprocal plot +/// Lineweaver-Burk transform: returns `(1/[S], 1/v)` for double-reciprocal plot pub fn lineweaver_burk(vmax: f64, km: f64, substrate: f64) -> (f64, f64) { assert!(substrate > 0.0, "substrate must be positive"); let v = michaelis_menten(vmax, km, substrate); @@ -163,7 +163,7 @@ pub fn lineweaver_burk(vmax: f64, km: f64, substrate: f64) -> (f64, f64) { (1.0 / substrate, 1.0 / v) } -/// Hill equation for cooperative binding: v = Vmax × [S]^n / (K^n + [S]^n) +/// Hill equation for cooperative binding: `v = Vmax × [S]^n / (K^n + [S]^n)` pub fn hill_equation(vmax: f64, k: f64, substrate: f64, n: f64) -> f64 { let s_n = substrate.powf(n); let k_n = k.powf(n); diff --git a/src/chemistry.rs b/src/chemistry.rs index 440fb96..851ee01 100644 --- a/src/chemistry.rs +++ b/src/chemistry.rs @@ -1,3 +1,14 @@ +//! Reaction kinetics, chemical thermodynamics and electrochemistry. +//! +//! Rate laws for first- and second-order decay and the Arrhenius +//! temperature dependence `k = A exp(−Eₐ/RT)`; the Gibbs free energy and +//! its relation to the equilibrium constant, `ΔG° = −RT ln K`, with the +//! van 't Hoff equation for how K moves with temperature; and Hess's law. +//! +//! Electrochemistry covers the Nernst equation, cell potentials and +//! Faraday electrolysis. Solution chemistry covers pH and pOH, molarity, +//! dilution and osmotic pressure. + use crate::math::constants; /// Faraday constant (C/mol). @@ -21,18 +32,18 @@ pub fn half_life_first_order(rate_constant: f64) -> f64 { f64::ln(2.0) / rate_constant } -/// First-order concentration decay: [A] = [A]₀ × e^(-kt) +/// First-order concentration decay: `[A] = [A]₀ × e^(-kt)` pub fn concentration_first_order(c0: f64, rate_constant: f64, time: f64) -> f64 { c0 * (-rate_constant * time).exp() } -/// Second-order integrated rate law: 1/[A] = 1/[A]₀ + kt, returns [A] +/// Second-order integrated rate law: `1/[A] = 1/[A]₀ + kt`, returns `[A]` pub fn concentration_second_order(c0: f64, rate_constant: f64, time: f64) -> f64 { assert!(c0 > 0.0, "initial concentration must be positive"); 1.0 / (1.0 / c0 + rate_constant * time) } -/// General rate law: r = k × Π([Ci]^ni) +/// General rate law: `r = k × Π([Ci]^ni)` pub fn reaction_rate(k: f64, concentrations: &[f64], orders: &[f64]) -> f64 { assert_eq!( concentrations.len(), diff --git a/src/classical.rs b/src/classical.rs index cbf60f9..cd21f36 100644 --- a/src/classical.rs +++ b/src/classical.rs @@ -1,3 +1,17 @@ +//! Newtonian mechanics: kinematics, dynamics, and the harmonic +//! oscillator. +//! +//! Linear and rotational motion under constant acceleration, forces and +//! momentum, work, energy and power, collisions in one dimension from +//! perfectly elastic to perfectly inelastic, moments of inertia for the +//! standard bodies, and circular motion. +//! +//! The oscillator section runs from the undamped period through the +//! damped response -- damping ratio, logarithmic decrement, quality factor +//! -- to the driven steady state and its resonance, and ends with the +//! normal frequencies of two coupled oscillators. For the same problem +//! solved numerically, or with more than two masses, see [`crate::resonance`]. + use crate::math::Vec3; // ── Kinematics ── diff --git a/src/color_science.rs b/src/color_science.rs index d792f3a..59f4539 100644 --- a/src/color_science.rs +++ b/src/color_science.rs @@ -1,3 +1,15 @@ +//! Colour: the standard spaces, the transforms between them, and +//! perceptual measures. +//! +//! RGB to and from HSV, HSL and CIE XYZ, with the sRGB transfer function +//! kept separate from the linear values -- the distinction that most +//! colour bugs come from, since averaging or blending is only meaningful +//! in linear light. +//! +//! Also spectral colour (wavelength to RGB), the Planckian locus +//! (blackbody temperature to RGB, and the correlated colour temperature +//! back), relative luminance and the WCAG contrast ratio. + /// Visible spectrum lower bound (nm). const WAVELENGTH_MIN_NM: f64 = 380.0; /// Visible spectrum upper bound (nm). @@ -164,7 +176,7 @@ pub fn blackbody_to_rgb(temperature_k: f64) -> (f64, f64, f64) { (r / CHANNEL_MAX, g / CHANNEL_MAX, b / CHANNEL_MAX) } -/// Convert linear RGB [0,1] to HSV. H in [0,360), S and V in [0,1]. +/// Convert linear RGB `[0,1]` to HSV. H in `[0,360)`, S and V in `[0,1]`. #[must_use] pub fn rgb_to_hsv(r: f64, g: f64, b: f64) -> (f64, f64, f64) { let max = r.max(g).max(b); @@ -189,7 +201,7 @@ pub fn rgb_to_hsv(r: f64, g: f64, b: f64) -> (f64, f64, f64) { (h, s, v) } -/// Convert HSV to linear RGB. H in [0,360), S and V in [0,1]. +/// Convert HSV to linear RGB. H in `[0,360)`, S and V in `[0,1]`. #[must_use] pub fn hsv_to_rgb(h: f64, s: f64, v: f64) -> (f64, f64, f64) { let c = v * s; @@ -214,7 +226,7 @@ pub fn hsv_to_rgb(h: f64, s: f64, v: f64) -> (f64, f64, f64) { (r1 + m, g1 + m, b1 + m) } -/// Convert linear RGB [0,1] to HSL. H in [0,360), S and L in [0,1]. +/// Convert linear RGB `[0,1]` to HSL. H in `[0,360)`, S and L in `[0,1]`. #[must_use] pub fn rgb_to_hsl(r: f64, g: f64, b: f64) -> (f64, f64, f64) { let max = r.max(g).max(b); @@ -243,7 +255,7 @@ pub fn rgb_to_hsl(r: f64, g: f64, b: f64) -> (f64, f64, f64) { (h, s, l) } -/// Convert HSL to linear RGB. H in [0,360), S and L in [0,1]. +/// Convert HSL to linear RGB. H in `[0,360)`, S and L in `[0,1]`. #[must_use] pub fn hsl_to_rgb(h: f64, s: f64, l: f64) -> (f64, f64, f64) { let c = (1.0 - (2.0 * l - 1.0).abs()) * s; diff --git a/src/continuum_mechanics.rs b/src/continuum_mechanics.rs index eabef29..a3855a7 100644 --- a/src/continuum_mechanics.rs +++ b/src/continuum_mechanics.rs @@ -1,3 +1,15 @@ +//! Stress and strain as tensors, and the yield criteria built on them. +//! +//! The stress tensor with its invariants, principal stresses, and the +//! split into hydrostatic and deviatoric parts -- the split that matters +//! because metals yield on the deviatoric part alone, which is why the von +//! Mises criterion ignores hydrostatic pressure entirely. +//! +//! Strain in both the small-strain and Green-Lagrange forms, the isotropic +//! 3-D Hooke's law `σᵢⱼ = λ δᵢⱼ ε_kk + 2μ εᵢⱼ` and its compliance +//! inverse, plane stress and plane strain, and the von Mises, Tresca, +//! Mohr-Coulomb and Drucker-Prager yield criteria. + use crate::linalg::Mat3; // ── Stress Tensor ──────────────────────────────────────────────────────────── diff --git a/src/control_systems/mod.rs b/src/control_systems/mod.rs index dba087d..c85fc28 100644 --- a/src/control_systems/mod.rs +++ b/src/control_systems/mod.rs @@ -1,3 +1,17 @@ +//! Linear control: system response, stability margins and PID tuning. +//! +//! First- and second-order step and impulse responses in closed form, and +//! the parameters that characterise them -- natural frequency, damping +//! ratio, rise and settling time, percent overshoot, bandwidth. +//! +//! Stability is assessed through the gain and phase margins, which say how +//! much extra gain or delay the loop tolerates before it oscillates. +//! Steady-state error is given by system type. +//! +//! PID tuning uses the Ziegler-Nichols rules. They are a starting point +//! rather than an answer: they were derived for a quarter-amplitude decay +//! and typically give an aggressive loop that wants detuning. + use crate::math::constants::PI; // ── Rise-time and settling-time constants ────────────────────────────── diff --git a/src/core/dual.rs b/src/core/dual.rs index b263c30..a010db8 100644 --- a/src/core/dual.rs +++ b/src/core/dual.rs @@ -168,7 +168,7 @@ pub fn gradient(f: impl Fn(&[Dual]) -> Dual, x: &[f64]) -> Vec { grad } -/// Jacobian matrix J[i][j] = ∂fᵢ/∂xⱼ of a vector-valued function. +/// Jacobian matrix `J[i][j] = ∂fᵢ/∂xⱼ` of a vector-valued function. /// /// # Panics /// Panics if `f` returns an empty vector or `x` is empty. diff --git a/src/curves.rs b/src/curves.rs index eef5c2d..eba22e8 100644 --- a/src/curves.rs +++ b/src/curves.rs @@ -1,3 +1,14 @@ +//! Plane curves: conics, Bézier curves, and parametric families. +//! +//! The conic sections with their eccentricities, foci and the +//! discriminant that classifies a general quadratic; quadratic and cubic +//! Bézier curves in 2-D and 3-D; and parametric circles, ellipses, +//! spirals, Lissajous figures, cycloids and helices. +//! +//! Arc length and signed curvature close the module. For subdivision +//! surfaces and B-spline or NURBS patches see [`crate::mesh::surfaces`]; +//! for space curves with Frenet frames see [`crate::patterns::knots`]. + use crate::math::Vec3; use crate::math::constants::PI; diff --git a/src/dsp/windows.rs b/src/dsp/windows.rs index 5d531d4..d640b6d 100644 --- a/src/dsp/windows.rs +++ b/src/dsp/windows.rs @@ -282,25 +282,26 @@ pub fn kaiser_beta_for_attenuation(db: f64) -> f64 { // --- Pre-Part-3 generators (wrap `window` with the original symmetric // convention) --- -/// Generate a Hann window of length n: w[k] = 0.5·(1 - cos(2πk/(n-1))) +/// Generate a Hann window of length n: `w[k] = 0.5·(1 - cos(2πk/(n-1)))` #[must_use] pub fn hann_window(n: usize) -> Vec { window(WindowKind::Hann, n, false) } -/// Generate a Hamming window of length n: w[k] = 0.54 - 0.46·cos(2πk/(n-1)) +/// Generate a Hamming window of length n: `w[k] = 0.54 - 0.46·cos(2πk/(n-1))` #[must_use] pub fn hamming_window(n: usize) -> Vec { window(WindowKind::Hamming, n, false) } -/// Generate a Blackman window of length n: w[k] = 0.42 - 0.5·cos(2πk/(n-1)) + 0.08·cos(4πk/(n-1)) +/// Generate a Blackman window of length n: + /// `w[k] = 0.42 - 0.5·cos(2πk/(n-1)) + 0.08·cos(4πk/(n-1))` #[must_use] pub fn blackman_window(n: usize) -> Vec { window(WindowKind::Blackman, n, false) } -/// Generate a rectangular (uniform) window of length n: w[k] = 1 for all k +/// Generate a rectangular (uniform) window of length n: `w[k] = 1` for all k #[must_use] pub fn rectangular_window(n: usize) -> Vec { window(WindowKind::Rect, n, false) diff --git a/src/electromagnetism.rs b/src/electromagnetism.rs index 1e5530c..0254c3c 100644 --- a/src/electromagnetism.rs +++ b/src/electromagnetism.rs @@ -1,3 +1,17 @@ +//! Classical electromagnetism, from Coulomb's law to radiating dipoles. +//! +//! Electrostatics (Coulomb force and field, potential, Gauss flux, +//! capacitance), magnetostatics (the force on a moving charge, the field +//! of a wire, solenoid and toroid, dipole moments and torques), induction +//! (Faraday and motional EMF, self and mutual inductance), and circuits +//! from Ohm's law through RC transients to the AC steady state -- complex +//! reactance, RLC impedance, resonance, quality factor and bandwidth, +//! power factor, and transformer ratios. +//! +//! The wave section covers the free-space relations: propagation speed, +//! the Poynting magnitude, energy density, the impedance of free space +//! `Z₀ = μ₀c ≈ 376.73 Ω`, dipole radiation and the Larmor power. + use crate::math::{Vec3, constants}; // ── Electrostatics ── diff --git a/src/electronics.rs b/src/electronics.rs index 277c124..f091fa5 100644 --- a/src/electronics.rs +++ b/src/electronics.rs @@ -1,3 +1,14 @@ +//! Semiconductor device physics. +//! +//! Carrier statistics -- the intrinsic concentration, Fermi-Dirac +//! occupancy, the thermal voltage `kT/q` -- and transport by drift and +//! diffusion, linked by the Einstein relation `D/μ = kT/q`. +//! +//! Then the devices: the PN junction's built-in potential and depletion +//! width, the Shockley diode equation, MOSFET drain current in the linear +//! and saturation regimes, and solar cells through open-circuit voltage, +//! fill factor and efficiency. + use crate::math::constants::{E_CHARGE, K_B}; // --------------------------------------------------------------------------- diff --git a/src/fluid_instabilities.rs b/src/fluid_instabilities.rs index b73b20d..d181f8c 100644 --- a/src/fluid_instabilities.rs +++ b/src/fluid_instabilities.rs @@ -1,3 +1,18 @@ +//! When a fluid configuration stops being stable, and how fast it comes +//! apart. +//! +//! Each entry here is a growth rate or a threshold. Rayleigh-Taylor for a +//! heavy fluid over a light one, with the Atwood number and the most +//! unstable wavelength; Kelvin-Helmholtz for a velocity shear; +//! Rayleigh-Bénard convection through the Rayleigh number and its critical +//! value; Plateau-Rayleigh for the breakup of a liquid column into drops; +//! Richtmyer-Meshkov for a shock crossing an interface; and the Jeans +//! criterion, which is the same instability applied to a self-gravitating +//! gas cloud and so sets the mass at which a cloud collapses into a star. +//! +//! The Richardson number and its stability test cover stratified shear +//! flow. + use crate::math::constants; // ── Constants ──────────────────────────────────────────────────────────────── diff --git a/src/fluids.rs b/src/fluids.rs index 088546a..2eccefe 100644 --- a/src/fluids.rs +++ b/src/fluids.rs @@ -1,3 +1,19 @@ +//! Fluid statics and single-phase flow. +//! +//! Statics: hydrostatic pressure, buoyancy and flotation, Pascal's +//! principle. Inviscid flow: continuity, Bernoulli, Torricelli, the +//! Venturi meter. Viscous flow: Stokes drag, the drag equation and +//! terminal velocity, Poiseuille's law, the Darcy-Weisbach head loss. +//! Compressible flow: Mach number, stagnation and isentropic ratios. +//! +//! Surface tension, capillary rise, vorticity, circulation and the +//! Kutta-Joukowski lift round it out, along with the dimensionless groups +//! that decide which regime you are in -- Reynolds, Froude, Weber, Bond, +//! Peclet, Marangoni, Archimedes. +//! +//! These are the closed-form relations. For flow solved on a grid or with +//! particles see [`crate::cfd`]. + use crate::math::constants; // ── Pressure ── diff --git a/src/fractals/attractors.rs b/src/fractals/attractors.rs index 4eb2abe..b015c86 100644 --- a/src/fractals/attractors.rs +++ b/src/fractals/attractors.rs @@ -728,7 +728,7 @@ pub fn delay_embedding(series: &[f64], dim: usize, delay: usize) -> Vec .collect() } -/// Recurrence plot: R[i,j] = true when embedded states i and j are +/// Recurrence plot: `R[i,j]` is true when embedded states i and j are /// within `eps` (row-major over the n embedded points). #[must_use] pub fn recurrence_plot(series: &[f64], embed_dim: usize, delay: usize, eps: f64) -> Vec { diff --git a/src/fractals/automata.rs b/src/fractals/automata.rs index 2bb5ca2..368a9a5 100644 --- a/src/fractals/automata.rs +++ b/src/fractals/automata.rs @@ -633,7 +633,7 @@ pub struct Turmite { pub pos: (usize, usize), pub dir: u8, pub state: u8, - /// Indexed by [state][color]. + /// Indexed by `[state][color]`. pub table: Vec>, } @@ -830,7 +830,7 @@ pub struct LifeLike3D { } impl LifeLike3D { - /// Parses "B/S" where counts are comma-free + /// Parses `"B/S"` where counts are comma-free /// digit runs; multi-digit counts (10-26) are written with /// parentheses, e.g. "B(10)(11)/S(12)". /// diff --git a/src/fractals/lsystem.rs b/src/fractals/lsystem.rs index 0ccb72c..451cfa6 100644 --- a/src/fractals/lsystem.rs +++ b/src/fractals/lsystem.rs @@ -516,7 +516,7 @@ pub mod presets { LSystem::new("F", 25.7).rule('F', "F[+F]F[-F]F") } - /// ABOP fig 1.24b: F → F[+F]F[−F][F] at 20°. + /// ABOP fig 1.24b: `F → F[+F]F[−F][F]` at 20°. #[must_use] pub fn plant_b() -> LSystem { LSystem::new("F", 20.0).rule('F', "F[+F]F[-F][F]") @@ -534,13 +534,13 @@ pub mod presets { LSystem::new("X", 20.0).rule('X', "F[+X]F[-X]+X").rule('F', "FF") } - /// ABOP fig 1.24e: X → F[+X][−X]FX, F → FF at 25.7°. + /// ABOP fig 1.24e: `X → F[+X][−X]FX`, `F → FF` at 25.7°. #[must_use] pub fn plant_e() -> LSystem { LSystem::new("X", 25.7).rule('X', "F[+X][-X]FX").rule('F', "FF") } - /// ABOP fig 1.24f: X → F−[[X]+X]+F[+FX]−X, F → FF at 22.5°. + /// ABOP fig 1.24f: `X → F−[[X]+X]+F[+FX]−X`, `F → FF` at 22.5°. #[must_use] pub fn plant_f() -> LSystem { LSystem::new("X", 22.5).rule('X', "F-[[X]+X]+F[+FX]-X").rule('F', "FF") diff --git a/src/fractals/mod.rs b/src/fractals/mod.rs index bd94038..e8fce26 100644 --- a/src/fractals/mod.rs +++ b/src/fractals/mod.rs @@ -1,3 +1,19 @@ +//! Fractals: escape-time sets, attractors, automata and noise. +//! +//! The module root holds the classic escape-time sets computed directly -- +//! Mandelbrot with smooth (continuous) iteration counts, Julia, burning +//! ship, Newton fractals and the Sierpinski gasket. +//! +//! The submodules generalise each direction: [`escape_time`] for a generic +//! iteration engine, [`attractors`] for chaotic flows and maps, +//! [`ifs`] for iterated function systems and the chaos game, +//! [`lsystem`] for Lindenmayer rewriting, [`automata`] for cellular +//! automata and growth, and [`noise`] for Perlin, OpenSimplex2, Worley and +//! fBm. +//! +//! For the dynamical-systems view -- Lyapunov exponents and bifurcation -- +//! see [`crate::nonlinear`]. + pub mod attractors; pub mod automata; pub mod escape_time; diff --git a/src/general_relativity.rs b/src/general_relativity.rs index 8676c0f..8695d76 100644 --- a/src/general_relativity.rs +++ b/src/general_relativity.rs @@ -1,3 +1,21 @@ +//! General relativity: black holes and cosmology. +//! +//! The Schwarzschild solution -- the metric components, the horizon at +//! `r_s = 2GM/c²`, proper time and gravitational redshift, the photon +//! sphere at `1.5 r_s` and the innermost stable circular orbit at +//! `3 r_s`, with the effective potential and the orbital energy and +//! angular momentum that produce them. The Kerr solution adds rotation: +//! the horizon, the ergosphere, the shifted ISCO, and the frame-dragging +//! rate. +//! +//! Cosmology covers the Friedmann equation for the Hubble parameter, the +//! critical density, redshift-distance relations, luminosity distance, +//! lookback time, and the scale factor and CMB temperature at a given +//! redshift. +//! +//! For four-vectors and curved-spacetime tensor machinery see +//! [`crate::manifold::spacetime`] and [`crate::manifold::metric`]. + use crate::math::constants::{G, C, PI}; const C2: f64 = C * C; diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 12fd5d9..a8c8908 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -1,3 +1,15 @@ +//! Areas, volumes and surface areas of the standard shapes. +//! +//! Plane figures (circle, ellipse, triangle by base-height and by Heron's +//! formula, regular polygon, sector, annulus) and solids (sphere, +//! cylinder, cone, ellipsoid, torus, frustum, capsule), with perimeters +//! and surface areas alongside. +//! +//! Closed-form mensuration only. For triangle solving see +//! [`crate::trigonometry`], for curves and conics see [`crate::curves`], +//! for polygon algorithms such as triangulation and offsetting see +//! [`crate::patterns::polygon_ops`], and for meshes see [`crate::mesh`]. + use crate::math::constants::PI; // --- 2D Areas --- diff --git a/src/geophysics.rs b/src/geophysics.rs index 21415b8..acd1971 100644 --- a/src/geophysics.rs +++ b/src/geophysics.rs @@ -1,3 +1,18 @@ +//! The solid Earth: gravity, seismology, and heat. +//! +//! Gravity surveying -- the latitude formula, the free-air and Bouguer +//! corrections, the resulting anomaly, and Airy isostatic compensation. +//! +//! Seismology: P- and S-wave travel times, epicentral distance from the +//! S−P lag, the Richter and moment magnitude scales, and seismic moment +//! and energy. The moment magnitude is the one to use for large events, +//! because Richter saturates. +//! +//! Heat flow: pressure and temperature with depth, the geothermal +//! gradient, and geothermal power. Plate tectonics closes the module with +//! Euler-pole plate velocities and the square-root-of-age law for +//! seafloor depth. + use crate::math::constants; // ── Gravity & Geoid constants ──────────────────────────────────────── diff --git a/src/gravitation.rs b/src/gravitation.rs index 784315f..2864dfd 100644 --- a/src/gravitation.rs +++ b/src/gravitation.rs @@ -1,3 +1,18 @@ +//! Newtonian gravity and two-body orbits. +//! +//! The inverse-square force and its potential energy, the field of a point +//! mass, escape and circular orbital velocity, and Kepler's third law in +//! both directions. The vis-viva equation `v² = μ(2/r − 1/a)` ties speed +//! to position on any conic orbit, and the specific orbital energy fixes +//! which conic it is. +//! +//! Also the Roche limit, the Hill sphere, the Schwarzschild radius and +//! gravitational time dilation -- the last two are the points at which +//! Newtonian gravity stops being enough; see [`crate::general_relativity`]. +//! +//! For orbits propagated rather than characterised, and for transfers +//! between them, see [`crate::astrophysics`]. + use crate::math::{Vec3, constants}; /// Gravitational force magnitude between two masses: F = G * m1 * m2 / r^2 diff --git a/src/information_theory.rs b/src/information_theory.rs index c9824c6..1e02b60 100644 --- a/src/information_theory.rs +++ b/src/information_theory.rs @@ -1,3 +1,18 @@ +//! Shannon information: entropy, divergence, and channel capacity. +//! +//! Entropy in bits and in nats, the maximum-entropy bound for a given +//! alphabet, and the entropy rate. Then the relations between two +//! distributions: cross entropy, Kullback-Leibler divergence, and the +//! Jensen-Shannon divergence -- which unlike KL is symmetric and bounded, +//! which is why it is the one that behaves like a distance. +//! +//! Mutual information and conditional entropy connect the two, and the +//! binary entropy function gives the capacity of a binary symmetric +//! channel as `C = 1 − H₂(p)`. Fisher information and the Cramér-Rao +//! bound cover the estimation side. +//! +//! For codes that approach these limits see [`crate::codes`]. + // --------------------------------------------------------------------------- // Shannon Entropy // --------------------------------------------------------------------------- diff --git a/src/learn/cluster.rs b/src/learn/cluster.rs index 9f20a97..037e20e 100644 --- a/src/learn/cluster.rs +++ b/src/learn/cluster.rs @@ -176,7 +176,7 @@ pub fn kmeans_pp_init( /// common enough to matter. const RESTARTS: usize = 10; -/// Lloyd's algorithm, restarted [`RESTARTS`] times from independent +/// Lloyd's algorithm, restarted `RESTARTS` (10) times from independent /// k-means++ starts, keeping the run with the lowest inertia. /// /// The result carries the winning run's inertia history, which is diff --git a/src/lib.rs b/src/lib.rs index 3e55681..32e0ae4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,77 @@ +//! A zero-dependency library for physics, mathematics and engineering +//! computation. +//! +//! # What this is for +//! +//! Every routine here is written so that something about it can be +//! *checked*: against a closed form, against a conservation law, against an +//! independent implementation of the same quantity, or against an exact +//! identity over integers. A test that only asserts a function ran is not +//! evidence. Where a result is approximate its error has a stated bound +//! derived from the method; where it is exact the assertion uses `==`. +//! +//! That principle decides the shape of the API. Solvers return +//! [`Result`] rather than panicking on non-convergence, so a caller can +//! tell "did not converge" from "converged to this". Functions validate +//! their arguments, and the guards are written `!(x > 0.0)` rather than +//! `x <= 0.0` so that NaN is rejected too. Physical constants come from +//! one table, [`math::constants`], and the values fixed by the 2019 SI +//! redefinition are exact. +//! +//! # Finding your way around +//! +//! The crate is wide -- 71 top-level modules. `docs/MODULE_MAP.md` in the +//! repository is a generated map of every module with its size and +//! summary. The rough shape: +//! +//! | Area | Modules | +//! |---|---| +//! | Numeric primitives | [`core`], [`math`], [`linalg`], [`numerical`], [`special`] | +//! | Exact and symbolic | [`exact`], [`discrete`], [`graph`], [`codes`] | +//! | Classical physics | [`classical`], [`gravitation`], [`solid_mechanics`], [`continuum_mechanics`], [`resonance`] | +//! | Thermal and statistical | [`thermodynamics`], [`statistical_mechanics`], [`radiation`] | +//! | Electromagnetic | [`electromagnetism`], [`electronics`], [`rf`], [`photonics`], [`plasma`], [`magnetohydrodynamics`] | +//! | Waves and signals | [`waves`], [`optics`], [`acoustics`], [`transforms`], [`dsp`], [`signal_processing`], [`audio`] | +//! | Fluids | [`fluids`], [`cfd`], [`fluid_instabilities`], [`propulsion`] | +//! | Modern physics | [`relativity`], [`general_relativity`], [`quantum`], [`particle_physics`], [`nuclear`], [`neutronics`] | +//! | Space | [`astrophysics`] | +//! | PDE solvers | [`fem`], [`sim`], [`fields`], [`vector_calculus`] | +//! | Life and chemistry | [`chemistry`], [`biophysics`] | +//! | Probability and data | [`statistics`], [`stochastic`], [`monte_carlo`], [`information_theory`], [`learn`] | +//! | Decisions | [`optimization`], [`finance`] | +//! | Geometry | [`geometry`], [`curves`], [`trigonometry`], [`quaternion`], [`manifold`], [`spatial`], [`mesh`] | +//! | Patterns | [`fractals`], [`patterns`], [`nonlinear`] | +//! | Reference and utility | [`units`], [`materials`], [`color_science`], [`control_systems`], [`atmosphere`], [`geophysics`], [`error`] | +//! +//! # Conventions +//! +//! **Units are SI** unless a function's documentation says otherwise, and +//! angles are radians. [`units`] converts, and [`units::quantity`] carries +//! dimensions in the type so that adding a velocity to a time is an error +//! rather than a number. +//! +//! **`f64` throughout**, except where exactness is the point: [`exact`] +//! works over arbitrary-precision integers and rationals, and +//! [`units::dimensional`] computes null spaces over +//! [`exact::rational::Rational`] because a group of quantities is exactly +//! dimensionless or it is not. +//! +//! **Randomness comes from [`monte_carlo::Rng`]**, a linear congruential +//! generator that returns its raw state. The low bits therefore have a +//! short period, so use [`monte_carlo::Rng::below`] for any small-integer +//! draw rather than `next_u64() % n`. +//! +//! # Example +//! +//! ``` +//! use rust_physics_engine::units::quantity::{Dim, Quantity}; +//! +//! let v = Quantity::new(3.0, Dim::new(1, 0, -1, 0, 0, 0, 0)); // m/s +//! let t = Quantity::new(2.0, Dim::TIME); +//! assert_eq!(v.mul(&t).unwrap().dim, Dim::LENGTH); // exactly a length +//! assert!(v.add(&t).is_err()); // and not a time +//! ``` + // Style allowances for a numerics codebase: index loops mirror the math // notation in matrix/stencil kernels, and public signatures follow the // roadmap's frozen APIs even where clippy would prefer fewer arguments or diff --git a/src/linalg/matrix.rs b/src/linalg/matrix.rs index eee524d..32892ca 100644 --- a/src/linalg/matrix.rs +++ b/src/linalg/matrix.rs @@ -102,7 +102,7 @@ impl Matrix { &self.data[r * self.cols..(r + 1) * self.cols] } - /// Transpose: B[c][r] = A[r][c]. + /// Transpose: `B[c][r] = A[r][c]`. #[must_use] pub fn transpose(&self) -> Self { let mut out = Self::zeros(self.cols, self.rows); diff --git a/src/linalg/mod.rs b/src/linalg/mod.rs index aa8ba90..2b38fed 100644 --- a/src/linalg/mod.rs +++ b/src/linalg/mod.rs @@ -1,3 +1,21 @@ +//! Dense and sparse linear algebra. +//! +//! [`Matrix`] is the dense row-major `f64` type everything here operates +//! on. The factorizations are chosen by what the matrix is: [`lu`] with +//! partial pivoting for a general square solve, [`mod@cholesky`] for symmetric +//! positive-definite (half the work, and it fails cleanly if the matrix is +//! not), [`qr`] by Householder reflections for least squares, [`mod@svd`] by +//! one-sided Jacobi for rank and pseudo-inverse, and [`tridiagonal`] for +//! the Thomas algorithm in O(n). +//! +//! [`eigen`] provides the symmetric eigenproblem and general eigenvalues. +//! [`sparse`] provides CSR storage with conjugate gradient and a +//! Jacobi-preconditioned variant, for the large systems that the PDE +//! solvers in [`crate::fem`] produce. +//! +//! Note that `pcg_jacobi`'s tolerance is relative to the norm of the +//! right-hand side, not absolute. + pub mod cholesky; pub mod eigen; pub mod lu; @@ -63,7 +81,7 @@ impl Mat3 { + d[0][2] * (d[1][0] * d[2][1] - d[1][1] * d[2][0]) } - /// Returns the transpose of this matrix: A^T[i][j] = A[j][i]. + /// Returns the transpose of this matrix: `A^T[i][j] = A[j][i]`. #[must_use] pub fn transpose(&self) -> Self { let d = &self.data; diff --git a/src/linalg/tridiagonal.rs b/src/linalg/tridiagonal.rs index 2d43b62..7963eec 100644 --- a/src/linalg/tridiagonal.rs +++ b/src/linalg/tridiagonal.rs @@ -1,7 +1,7 @@ //! Tridiagonal linear solve (Thomas algorithm). //! //! Reference: Press et al., *Numerical Recipes*, §2.4. Solves -//! sub[i-1]·x[i-1] + diag[i]·x[i] + sup[i]·x[i+1] = rhs[i] in O(n). +//! `sub[i-1]·x[i-1] + diag[i]·x[i] + sup[i]·x[i+1] = rhs[i]` in O(n). use crate::error::SolveError; diff --git a/src/magnetohydrodynamics.rs b/src/magnetohydrodynamics.rs index eedea4f..b94a4fe 100644 --- a/src/magnetohydrodynamics.rs +++ b/src/magnetohydrodynamics.rs @@ -1,3 +1,16 @@ +//! Magnetohydrodynamics: a conducting fluid and the field frozen into it. +//! +//! The dimensionless numbers first, because they decide the regime: +//! magnetic Reynolds (advection against diffusion, and so whether the +//! field is frozen in), Lundquist, Hartmann, and the plasma beta -- the +//! ratio of thermal to magnetic pressure, which says whether the field +//! or the gas is in charge. +//! +//! Wave speeds: Alfvén, and the slow and fast magnetosonic branches. +//! Equilibria: pinch pressure balance, the Bennett condition, and the +//! Grad-Shafranov beta limit. Reconnection is covered by the Sweet-Parker +//! rate and the associated electric field. + use crate::math::constants::{K_B, MU_0, PI}; // ── Frozen-in flux threshold ──────────────────────────────────────────── diff --git a/src/manifold/clifford.rs b/src/manifold/clifford.rs index 6cd16cb..25b63f9 100644 --- a/src/manifold/clifford.rs +++ b/src/manifold/clifford.rs @@ -167,7 +167,7 @@ impl Multivector { out } - /// Scalar product _0. + /// Scalar product `_0`. #[must_use] pub fn scalar_product(&self, o: &Self) -> f64 { let mut s = 0.0; @@ -398,7 +398,7 @@ impl Multivector { out } - /// Logarithm of a rotor R = _0 + _2 (bivector generator). + /// Logarithm of a rotor `R = _0 + _2` (bivector generator). #[must_use] pub fn log(&self) -> Option { let s = self.coeffs[0]; @@ -677,7 +677,7 @@ impl Multivector { } } -/// Basis-blade multiplication table: table[a][b] = (sign, result mask). +/// Basis-blade multiplication table: `table[a][b] = (sign, result mask)`. #[must_use] pub fn cayley_table(p: usize, q: usize, r: usize) -> Vec> { let n = 1 << (p + q + r); diff --git a/src/manifold/metric.rs b/src/manifold/metric.rs index 5f0130e..32fc26f 100644 --- a/src/manifold/metric.rs +++ b/src/manifold/metric.rs @@ -741,7 +741,7 @@ impl Metric { } /// Max residual of the first Bianchi identity - /// R_{i[jkl]} : R_ijkl + R_iklj + R_iljk = 0, normalized by the largest + /// `R_{i[jkl]}` : `R_ijkl + R_iklj + R_iljk = 0`, normalized by the largest /// Riemann component. #[must_use] pub fn bianchi_identity_residual(&self, p: &VecN) -> f64 { diff --git a/src/manifold/polytope4.rs b/src/manifold/polytope4.rs index 4606c61..7b6708e 100644 --- a/src/manifold/polytope4.rs +++ b/src/manifold/polytope4.rs @@ -1736,7 +1736,7 @@ pub fn kissing_number_known(n: usize) -> Option { // High-dimensional phenomena // --------------------------------------------------------------------------- -/// (n-1)-volume of the slice of the unit n-cube [0,1]^n by the hyperplane +/// (n-1)-volume of the slice of the unit n-cube `[0,1]^n` by the hyperplane /// sum(x) = s, times sqrt(n) (the Irwin-Hall density scaled to a volume). #[must_use] pub fn hypercube_slicing_volume(n: usize, s: f64) -> f64 { diff --git a/src/materials/common.rs b/src/materials/common.rs index 6c60a04..42bdad8 100644 --- a/src/materials/common.rs +++ b/src/materials/common.rs @@ -1,3 +1,10 @@ +//! Engineering solids: metals, alloys, polymers and ceramics. +//! +//! Density, Young's modulus, yield and tensile strength, Poisson's ratio, +//! thermal conductivity and expansion, and specific heat. Room-temperature +//! values; a specific alloy, temper or grade will differ, sometimes +//! substantially. + /// An engineering material with mechanical and thermal properties. /// /// All values use SI units: diff --git a/src/materials/elements.rs b/src/materials/elements.rs index acff1ec..df1381c 100644 --- a/src/materials/elements.rs +++ b/src/materials/elements.rs @@ -1,3 +1,14 @@ +//! The 118 chemical elements. +//! +//! Atomic number, symbol, name, atomic mass, density, melting and boiling +//! points, and thermal and electrical conductivity, with lookup by atomic +//! number, symbol or name. +//! +//! Densities are for the standard state at room temperature, so gases are +//! quoted at STP. Where an element has no stable isotope the atomic mass +//! is that of the longest-lived one, and properties that have never been +//! measured are absent rather than guessed. + /// Classification of an element within the periodic table. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ElementCategory { diff --git a/src/materials/fluids.rs b/src/materials/fluids.rs index ae9d3c1..92e94f5 100644 --- a/src/materials/fluids.rs +++ b/src/materials/fluids.rs @@ -1,3 +1,13 @@ +//! Common liquids. +//! +//! Density, dynamic and kinematic viscosity, surface tension, speed of +//! sound, specific heat, and boiling and freezing points, at room +//! temperature and one atmosphere. +//! +//! Viscosity is the strongly temperature-dependent one: it can change by a +//! factor of several over a few tens of degrees, so a single figure is +//! only a starting point. + /// A fluid (liquid) with its mechanical and thermal properties at 20 degrees C /// unless otherwise noted in the entry. /// diff --git a/src/materials/gases.rs b/src/materials/gases.rs index 6aa03a3..40fd119 100644 --- a/src/materials/gases.rs +++ b/src/materials/gases.rs @@ -1,3 +1,13 @@ +//! Common gases. +//! +//! Molar mass, density at STP, specific heat at constant pressure and the +//! specific heat ratio `γ`, thermal conductivity, viscosity and the speed +//! of sound. +//! +//! `γ` is the entry most often needed: it fixes the adiabatic relations +//! and the speed of sound `c = √(γRT/M)`, and it follows the molecular +//! structure -- about 5/3 for a monatomic gas, 7/5 for a diatomic one. + /// A gas with its thermodynamic and transport properties at STP. /// /// All values use SI units: diff --git a/src/materials/mod.rs b/src/materials/mod.rs index b209bf1..7b85e4c 100644 --- a/src/materials/mod.rs +++ b/src/materials/mod.rs @@ -1,3 +1,16 @@ +//! Reference property tables. +//! +//! Lookup data rather than computation: [`elements`] carries all 118 +//! elements with atomic mass, density, melting and boiling points and +//! thermal and electrical conductivity; [`common`] carries engineering +//! solids; [`fluids`] carries liquids with density, viscosity, surface +//! tension and speed of sound; and [`gases`] carries molar mass, specific +//! heat ratio and thermal conductivity. +//! +//! Values are room-temperature and one-atmosphere unless stated. They are +//! reference figures for calculation, not a substitute for a datasheet on +//! a specific alloy or grade. + pub mod elements; pub mod common; pub mod gases; diff --git a/src/math.rs b/src/math.rs index a64d5c2..064ac2b 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,3 +1,21 @@ +//! Vectors and the crate's table of physical constants. +//! +//! [`Vec2`] and [`Vec3`] with the usual algebra -- addition, scaling, dot +//! and cross products, norms, normalization, projection, reflection, +//! rotation and interpolation. +//! +//! [`constants`] is the single table the rest of the crate refers back +//! to, and it is deliberately one table: duplicate definitions elsewhere +//! are re-exports of it, and a test enforces that they agree. The values +//! fixed by the 2019 SI redefinition -- `C`, `H`, `HBAR`, `E_CHARGE`, +//! `K_B`, `N_A` -- are exact by definition rather than measured. Constants +//! that are products of others, such as `FARADAY = N_A · E_CHARGE`, are +//! computed from their factors rather than transcribed, so they cannot +//! disagree with them. +//! +//! For the 2022 CODATA set with units attached see +//! [`crate::units::quantity::constants_codata`]. + use std::ops::{Add, Sub, Mul, Neg}; /// 2D vector (fluid grids, planar geometry). diff --git a/src/mesh/isosurface.rs b/src/mesh/isosurface.rs index e9dc296..d8ca120 100644 --- a/src/mesh/isosurface.rs +++ b/src/mesh/isosurface.rs @@ -456,7 +456,7 @@ fn mc_table() -> &'static Vec> { /// Extracts the isosurface by marching cubes (Lorensen & Cline 1987; /// the case table is generated by face-consistent cycle construction, -/// see [`mc_table`]). Output vertices are shared across cells (keyed +/// see `mc_table`). Output vertices are shared across cells (keyed /// by grid edge), so the mesh is watertight wherever the surface does /// not leave the grid. #[must_use] diff --git a/src/monte_carlo/mod.rs b/src/monte_carlo/mod.rs index fb76548..d462d97 100644 --- a/src/monte_carlo/mod.rs +++ b/src/monte_carlo/mod.rs @@ -1,3 +1,19 @@ +//! Monte Carlo methods and the random number generator behind them. +//! +//! Integration (plain, 2-D, and importance-sampled), random walks in one +//! to three dimensions, the Wiener and Ornstein-Uhlenbeck processes, +//! Langevin dynamics, and Metropolis-Hastings sampling with a +//! worked Ising example. +//! +//! # A warning about [`Rng`] +//! +//! It is a linear congruential generator that returns its raw state, so +//! the low bits have a short period: `next_u64() % m` for a power-of-two +//! `m` cycles through a handful of values -- `% 2` gives 0,1,0,1 and `% 4` +//! gives 0,3,2,1 forever. Use [`Rng::below`], which takes the high bits, +//! for any small-integer draw. It is adequate for simulation and testing +//! and is not cryptographically secure. + use crate::math::constants::K_B; const LCG_MULTIPLIER: u64 = 6_364_136_223_846_793_005; diff --git a/src/neutronics.rs b/src/neutronics.rs index f0bd794..cb4202d 100644 --- a/src/neutronics.rs +++ b/src/neutronics.rs @@ -1,3 +1,19 @@ +//! Reactor physics: criticality, neutron diffusion, and shielding. +//! +//! Criticality through the six-factor formula and `k_eff`, with +//! reactivity and the reactor period. Neutron transport in diffusion +//! theory: the diffusion coefficient and length, migration length, +//! thermal utilization, and the flux in a slab. +//! +//! Cross sections and reaction rates convert between microscopic and +//! macroscopic pictures, including the 1/v absorption law. Operations +//! covers reactor power, burnup and decay heat. +//! +//! Shielding closes with attenuation, half- and tenth-value layers, and +//! the buildup factor that corrects the exponential law for scattered +//! photons -- the correction that matters, since ignoring it +//! underestimates the dose behind a thick shield. + use crate::math::constants; // ── Neutron Multiplication ── diff --git a/src/nonlinear.rs b/src/nonlinear.rs index c76a068..408a788 100644 --- a/src/nonlinear.rs +++ b/src/nonlinear.rs @@ -1,3 +1,18 @@ +//! Chaos in low-dimensional systems. +//! +//! The logistic map and its period-doubling route to chaos, the Hénon +//! map, and the Lorenz and Rössler flows given as derivative functions to +//! hand to an integrator from [`crate::numerical`]. +//! +//! Lyapunov exponents are the quantitative test: a positive exponent means +//! nearby trajectories separate exponentially, which is what makes a +//! system chaotic rather than merely complicated. Dimension estimators -- +//! box counting and the correlation dimension -- measure the attractor +//! that results. +//! +//! For strange attractors as drawable objects, escape-time fractals and +//! cellular automata see [`crate::fractals`]. + // Chaos theory and nonlinear dynamics: logistic maps, Lyapunov exponents, // strange attractors, fractal dimension estimators, and fixed-point analysis. diff --git a/src/nuclear.rs b/src/nuclear.rs index a0321fa..d8a3d87 100644 --- a/src/nuclear.rs +++ b/src/nuclear.rs @@ -1,3 +1,16 @@ +//! Radioactive decay, nuclear binding, and dosimetry. +//! +//! Exponential decay in its several parameterisations -- decay constant, +//! half-life, mean lifetime -- and activity. Binding energy from the mass +//! defect, binding energy per nucleon (the curve whose peak at iron-56 is +//! why both fission and fusion release energy), and reaction Q-values. +//! +//! Nuclear size follows `R = R₀A^(1/3)`, giving a roughly constant +//! nuclear density. Dosimetry covers absorbed and equivalent dose and the +//! inverse-square falloff of intensity with distance. +//! +//! For reactor-scale neutron transport see [`crate::neutronics`]. + use crate::math::constants; // ── Radioactive Decay ── diff --git a/src/numerical/interpolate.rs b/src/numerical/interpolate.rs index 90514f7..348d4db 100644 --- a/src/numerical/interpolate.rs +++ b/src/numerical/interpolate.rs @@ -304,7 +304,7 @@ fn catmull_rom_weights(u: f64) -> [f64; 4] { } /// Uniform Catmull-Rom spline through `points`, parameterized so that -/// t = i lands exactly on points[i] (t ∈ [0, n−1]; endpoints use +/// `t = i` lands exactly on `points[i]` (`t ∈ [0, n−1]`; endpoints use /// duplicated boundary points). /// /// # Panics diff --git a/src/numerical/ode/explicit.rs b/src/numerical/ode/explicit.rs index 93c8657..da36e32 100644 --- a/src/numerical/ode/explicit.rs +++ b/src/numerical/ode/explicit.rs @@ -37,7 +37,7 @@ pub fn rk4_solve( } /// Single RK4 step for a system of ODEs (vector state). -/// f(t, y) returns a Vec of derivatives matching the length of y. +/// `f(t, y)` returns a `Vec` of derivatives matching the length of `y`. #[must_use] pub fn rk4_step_vec( f: &dyn Fn(f64, &[f64]) -> Vec, diff --git a/src/optics.rs b/src/optics.rs index 6d9b890..385ee96 100644 --- a/src/optics.rs +++ b/src/optics.rs @@ -1,3 +1,18 @@ +//! Geometric and wave optics. +//! +//! Refraction by Snell's law, the critical angle for total internal +//! reflection, and the Brewster angle at which reflected light is fully +//! polarized. Imaging through the thin-lens and mirror equations, +//! magnification, lens power, combined focal lengths and the lensmaker's +//! radius of curvature. +//! +//! Wave optics covers single-slit minima, double-slit maxima, the grating +//! equation, thin-film interference, and the Rayleigh resolution criterion +//! `θ = 1.22 λ/D`. Malus's law closes it. +//! +//! For Gaussian beams, fibre optics and ray transfer matrices see +//! [`crate::photonics`]. + use crate::math::constants; // ── Reflection and Refraction ── diff --git a/src/optimization/mod.rs b/src/optimization/mod.rs index 17bbb07..9b11759 100644 --- a/src/optimization/mod.rs +++ b/src/optimization/mod.rs @@ -1,3 +1,17 @@ +//! Optimization: continuous, combinatorial, and strategic. +//! +//! The module root holds the scalar and unconstrained-gradient methods -- +//! golden section and Brent for a bracketed minimum of one variable, then +//! gradient descent with and without momentum, Adam, numerical gradients, +//! and the regression and curve fitting built on them. +//! +//! The submodules take it further: [`lp`] for linear programming and +//! duality, [`integer`] for branch-and-bound and dynamic programming, +//! [`network`] for flows and scheduling, [`convex`] for L-BFGS, proximal +//! methods and ADMM, [`metaheuristics`] for the derivative-free and +//! population-based methods, [`game_theory`] for equilibria and +//! cooperative solutions, and [`least_squares`] for Levenberg-Marquardt. + // Numerical optimization algorithms: 1D search, gradient-based, derivative-free, // and linear/nonlinear least-squares fitting. diff --git a/src/particle_physics.rs b/src/particle_physics.rs index 9af65ac..a4a77d0 100644 --- a/src/particle_physics.rs +++ b/src/particle_physics.rs @@ -1,3 +1,19 @@ +//! Relativistic kinematics and scattering for particle collisions. +//! +//! Invariant mass -- the quantity every collider analysis is built on, +//! because it is the same in every frame -- along with centre-of-mass +//! energy for colliding and fixed-target geometries, and the Lorentz boost +//! of energy and longitudinal momentum. +//! +//! The collider coordinates: rapidity, pseudorapidity and transverse +//! momentum, chosen because rapidity differences are boost invariant along +//! the beam. Scattering by the Rutherford cross section and the +//! Breit-Wigner resonance shape, with the width-lifetime relation +//! `Γτ = ħ` and branching ratios. +//! +//! Also the conservation-law checks -- charge, lepton number, baryon +//! number -- that say whether a proposed reaction can happen at all. + use crate::math::constants::{C, E_CHARGE, HBAR, K_E}; // --------------------------------------------------------------------------- diff --git a/src/photonics.rs b/src/photonics.rs index 330cb02..5a6d804 100644 --- a/src/photonics.rs +++ b/src/photonics.rs @@ -1,3 +1,16 @@ +//! Laser beams, optical fibre, and interferometry. +//! +//! Gaussian beam propagation: waist, Rayleigh range, radius and curvature +//! against distance, divergence, the Gouy phase, and on-axis intensity. +//! +//! Fibre through the numerical aperture, acceptance angle, and the +//! V-number that decides single- versus multi-mode operation, plus +//! attenuation and dispersion broadening. Ray transfer (ABCD) matrices +//! compose optical elements by matrix multiplication. +//! +//! Coherence length and time, fringe visibility, and the Fabry-Pérot +//! transmission with its free spectral range close the module. + use crate::math::constants; // ── Fiber Optics Constants ────────────────────────────────────────────────── diff --git a/src/plasma.rs b/src/plasma.rs index d1dc734..8e65f32 100644 --- a/src/plasma.rs +++ b/src/plasma.rs @@ -1,3 +1,20 @@ +//! Plasma parameters: the characteristic lengths, frequencies and speeds. +//! +//! The Debye length is where it starts -- the distance over which a +//! plasma screens a charge, and therefore the scale below which "plasma" +//! stops being the right description. The Debye number counts particles +//! in that sphere, and a plasma is only collective if that number is +//! large. +//! +//! Frequencies: electron and ion plasma frequencies, and the cyclotron +//! frequencies in a magnetic field, with the associated Larmor radius. +//! Speeds: thermal, ion-acoustic, Alfvén and magnetosonic. Plus magnetic +//! pressure, plasma beta, the skin depth, the Coulomb logarithm and the +//! collision frequency. +//! +//! For a conducting fluid treated as a continuum see +//! [`crate::magnetohydrodynamics`]. + use crate::math::constants::{C, E_CHARGE, EPSILON_0, K_B, M_ELECTRON, MU_0, PI}; /// λD = √(ε₀kT / (nq²)) diff --git a/src/propulsion.rs b/src/propulsion.rs index fd9798b..167f849 100644 --- a/src/propulsion.rs +++ b/src/propulsion.rs @@ -1,3 +1,18 @@ +//! Rocket propulsion and impulsive orbital transfers. +//! +//! The Tsiolkovsky equation `Δv = v_e ln(m₀/m_f)` and the specific +//! impulse and mass ratio around it, thrust with and without the +//! pressure-thrust term, staged Δv, and the gravity-turn loss that makes +//! the ideal Δv an underestimate for a launch. +//! +//! Transfers: Hohmann Δv and time, the bi-elliptic alternative (which +//! wins beyond a radius ratio of about 11.94), and plane changes. Nozzle +//! design covers exit velocity, throat area and the area ratio for a given +//! exit Mach number. +//! +//! For Lambert targeting, J2 effects and orbit propagation see +//! [`crate::astrophysics`]. + use crate::math::constants::{PI, R as GAS_R}; // ── Rocket Equation ── diff --git a/src/quantum/circuit.rs b/src/quantum/circuit.rs index 39cbc3b..d379db0 100644 --- a/src/quantum/circuit.rs +++ b/src/quantum/circuit.rs @@ -57,7 +57,7 @@ impl QState { /// The all-zeros computational basis state. /// /// # Errors - /// Returns an error for zero qubits or more than [`MAX_QUBITS`]. + /// Returns an error for zero qubits or more than `MAX_QUBITS` (26). pub fn zero(n: usize) -> Result { Self::basis(n, 0) } diff --git a/src/quaternion.rs b/src/quaternion.rs index b81fe3d..00edf92 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -1,3 +1,17 @@ +//! Unit quaternions for 3-D rotation. +//! +//! [`Quaternion`] with the full algebra -- Hamilton product, conjugate, +//! inverse, norm and normalization -- and conversion to and from axis-angle, +//! Euler angles and rotation matrices. +//! +//! Quaternions are used for orientation rather than Euler angles because +//! they compose without gimbal lock and interpolate smoothly: [`slerp`] +//! moves along the great circle at constant angular rate, and [`nlerp`] is +//! the cheaper normalized-linear approximation to it. +//! +//! For the Lie-group view of the same object, and for rotations in four +//! dimensions, see [`crate::manifold::lie`]. + use std::ops::{Add, Mul, Neg, Sub}; use crate::math::constants::PI; diff --git a/src/radiation.rs b/src/radiation.rs index 8b863f4..fabc99a 100644 --- a/src/radiation.rs +++ b/src/radiation.rs @@ -1,3 +1,18 @@ +//! Thermal radiation and radiative transfer. +//! +//! The Stefan-Boltzmann law `j = σT⁴`, Wien's displacement of the +//! spectral peak, and the colour and brightness temperatures that invert +//! them. +//! +//! Transfer through an absorbing medium: optical depth, the Beer-Lambert +//! law, and the photon mean free path. Radiation pressure for absorbing +//! and reflecting surfaces. Surface exchange via Kirchhoff's law +//! (emissivity equals absorptivity at equilibrium), view factors, and +//! net radiative exchange between surfaces. +//! +//! For the Planck spectrum itself see [`crate::quantum`]; for reactor and +//! photon shielding see [`crate::neutronics`]. + use crate::math::constants; // Wien's displacement constant in the frequency domain: f_max = WIEN_FREQ_CONSTANT * T diff --git a/src/relativity.rs b/src/relativity.rs index 162d3b9..de35e36 100644 --- a/src/relativity.rs +++ b/src/relativity.rs @@ -1,3 +1,17 @@ +//! Special relativity. +//! +//! The Lorentz factor and the kinematic consequences -- time dilation, +//! length contraction, the velocity-addition law that keeps `c` a limit, +//! and the Lorentz transformation of position and time. +//! +//! Dynamics: relativistic momentum and kinetic energy, total and rest +//! energy, and the energy-momentum relation `E² = (pc)² + (mc²)²`. The +//! relativistic Doppler shift for approaching and receding sources. +//! +//! Also proper time and the spacetime interval, whose sign classifies a +//! separation as timelike, spacelike or null -- the invariant that +//! replaces separate notions of distance and duration. + use crate::math::constants; /// Lorentz factor: γ = 1 / sqrt(1 - v^2/c^2) diff --git a/src/rf.rs b/src/rf.rs index 0f612af..32d4ff6 100644 --- a/src/rf.rs +++ b/src/rf.rs @@ -1,3 +1,18 @@ +//! Radio-frequency engineering: links, lines and noise. +//! +//! Link budgets built from free-space path loss, the Friis transmission +//! equation, antenna gain and effective area, EIRP, beamwidth, +//! directivity and fade margin. +//! +//! Transmission lines: characteristic impedance of coax, velocity factor, +//! guide wavelength, and the mismatch quantities -- VSWR, return loss, +//! mismatch loss. Conductors are covered by the skin depth +//! `δ = √(2ρ/ωμ)`, which is why RF current flows in a thin surface layer. +//! +//! Noise and units: thermal noise power and floor in dBm, signal-to-noise +//! ratio, the Shannon capacity of the resulting channel, and conversions +//! between watts, dBm, ratios and decibels. + use crate::math::constants; // ── EM Spectrum Classification ── diff --git a/src/signal_processing/mod.rs b/src/signal_processing/mod.rs index 4e1667c..05bfbfa 100644 --- a/src/signal_processing/mod.rs +++ b/src/signal_processing/mod.rs @@ -1,3 +1,18 @@ +//! Time-domain signal operations and test waveforms. +//! +//! Convolution, cross- and autocorrelation, normalization, windowing, and +//! the simple smoothers -- moving average, exponential moving average, and +//! the median filter, which unlike the other two removes impulsive noise +//! without smearing an edge. +//! +//! Waveform generators (sine, square, sawtooth, triangle, noise, chirp) +//! provide test signals. +//! +//! This module is the elementary layer and re-exports the pieces of +//! [`crate::transforms`] and [`crate::dsp`] most often wanted alongside +//! it. For FFTs of any length go to [`mod@crate::transforms::fft`]; for filter +//! *design* go to [`crate::dsp`]. + // The FFT moved to `transforms::fft` and the window generators and // first-order RC filters to `dsp` (Step 0 of roadmap Part 3); everything // stays importable from its old path here. @@ -22,7 +37,7 @@ const LCG_INCREMENT: u64 = 1442695040888963407; // --- Convolution & Correlation --- -/// Linear convolution of signal with kernel: y[n] = Σ s[i]·k[n-i] +/// Linear convolution of signal with kernel: `y[n] = Σ s[i]·k[n-i]` #[must_use] pub fn convolve(signal: &[f64], kernel: &[f64]) -> Vec { if signal.is_empty() || kernel.is_empty() { @@ -111,7 +126,7 @@ pub fn moving_average(signal: &[f64], window_size: usize) -> Vec { output } -/// Exponential moving average filter: y[n] = α·x[n] + (1-α)·y[n-1] +/// Exponential moving average filter: `y[n] = α·x[n] + (1-α)·y[n-1]` #[must_use] pub fn exponential_moving_average(signal: &[f64], alpha: f64) -> Vec { if signal.is_empty() { @@ -158,7 +173,7 @@ pub fn median_filter(signal: &[f64], window_size: usize) -> Vec { // --- Signal Generation --- -/// Generate a sine wave: x[n] = A·sin(2πf·n/fs) for n samples over given duration +/// Generate a sine wave: `x[n] = A·sin(2πf·n/fs)` for n samples over given duration #[must_use] pub fn sine_wave(frequency: f64, sample_rate: f64, duration: f64, amplitude: f64) -> Vec { assert!(sample_rate > 0.0, "sample rate must be positive"); diff --git a/src/sim/cloth_sim.rs b/src/sim/cloth_sim.rs index d6d2996..5b7c92e 100644 --- a/src/sim/cloth_sim.rs +++ b/src/sim/cloth_sim.rs @@ -1,3 +1,15 @@ +//! Verlet cloth and rope with spring constraints. +//! +//! Particles are advanced by position Verlet, which stores the previous +//! position rather than a velocity: it is stable under stiff constraints +//! and conserves energy far better than explicit Euler at the same step +//! size, because velocity is inferred from the positions rather than +//! integrated separately. +//! +//! Structural, shear and bend springs are then satisfied by iterated +//! position projection -- more iterations gives a stiffer cloth -- with +//! pinning, sphere and floor collision, and wind and gravity forces. + use crate::math::Vec3; const DEFAULT_GRAVITY_Y: f64 = -9.81; diff --git a/src/sim/em_sim.rs b/src/sim/em_sim.rs index 0efff1f..71646a3 100644 --- a/src/sim/em_sim.rs +++ b/src/sim/em_sim.rs @@ -1,3 +1,18 @@ +//! FDTD electromagnetic simulation in one and two dimensions. +//! +//! Explicit leapfrog on a Yee-style grid: the electric and magnetic fields +//! are staggered by half a cell and half a time step, so each is updated +//! from the curl of the other and the scheme is second-order accurate with +//! no matrix to solve. +//! +//! Supports dielectric media, hard and soft sources, PEC (perfectly +//! conducting) walls and Mur first-order absorbing boundaries. Stability +//! requires the Courant condition, and the limit is set by the fastest +//! medium in the grid -- that is, the smallest relative permittivity. +//! +//! For a Yee grid with Berenger split-field PML, photonic band gaps and +//! waveguide cutoff, see [`crate::fem::fdtd`]. + use crate::math::constants::{C, EPSILON_0, MU_0, PI}; // ── Mur ABC boundary storage ── diff --git a/src/sim/fluid_sim.rs b/src/sim/fluid_sim.rs index 2ff5baa..6942eea 100644 --- a/src/sim/fluid_sim.rs +++ b/src/sim/fluid_sim.rs @@ -1,3 +1,15 @@ +//! Compact fluid solvers: column, shallow water, and 2-D Euler. +//! +//! A draining column for the simplest case, a 1-D shallow-water solver, +//! and a 2-D incompressible Euler solver that advects velocity and then +//! restores `∇·u = 0` by pressure projection -- subtracting the gradient +//! of a pressure field found by solving a Poisson equation, which is what +//! makes the result divergence-free. +//! +//! Written to be read and to run interactively. For well-balanced schemes, +//! Riemann solvers and the rest of the research-grade machinery see +//! [`crate::cfd`]. + // Grid-based fluid simulation solvers. // // Three models at increasing fidelity: diff --git a/src/sim/heat_sim.rs b/src/sim/heat_sim.rs index 171cca1..e7e7d79 100644 --- a/src/sim/heat_sim.rs +++ b/src/sim/heat_sim.rs @@ -1,3 +1,14 @@ +//! Heat conduction and convection-diffusion on a grid. +//! +//! Explicit finite differences in two and three dimensions, with Dirichlet +//! and Neumann boundaries, sources, and an advection term for +//! convection-diffusion. +//! +//! Explicit stepping is only conditionally stable: the step must satisfy +//! `α Δt / Δx² ≤ 1/4` in 2-D and `1/6` in 3-D, so halving the grid spacing +//! quarters the allowable time step. The stability limit is provided as a +//! function rather than left to the caller to remember. + // Heat conduction and convection simulation on structured grids. // // ## Governing PDEs @@ -40,9 +51,9 @@ pub struct HeatConduction2D { pub nx: usize, /// Number of grid points in y. pub ny: usize, - /// Grid spacing in x [m]. + /// Grid spacing in x (m). pub dx: f64, - /// Grid spacing in y [m]. + /// Grid spacing in y (m). pub dy: f64, /// Thermal diffusivity α = k/(ρcₚ) [m²/s]. pub diffusivity: f64, @@ -307,7 +318,7 @@ pub struct ConvectionDiffusion1D { pub field: Vec, /// Number of grid points. pub nx: usize, - /// Grid spacing [m]. + /// Grid spacing (m). pub dx: f64, /// Advection velocity [m/s]. pub velocity: f64, diff --git a/src/sim/mod.rs b/src/sim/mod.rs index 5c1add0..c71fe87 100644 --- a/src/sim/mod.rs +++ b/src/sim/mod.rs @@ -1,3 +1,18 @@ +//! Time-stepping simulation engines. +//! +//! Where the rest of the crate evaluates a relation, these advance a state +//! forward in time: [`rigid_body`] for 3-D dynamics with quaternion +//! orientation and Euler's equations, [`fluid_sim`] for shallow water and +//! 2-D incompressible Euler, [`heat_sim`] for conduction and +//! convection-diffusion, [`wave_sim`] for the wave equation with Mur +//! absorbing boundaries, [`em_sim`] for FDTD electromagnetics, and +//! [`cloth_sim`] for Verlet cloth and rope. +//! +//! These are compact, readable integrators intended for interactive use +//! and for seeing the physics behave. For the research-grade schemes -- +//! Riemann solvers, WENO, lattice Boltzmann, SPH -- see [`crate::cfd`]; +//! for finite elements and a Yee-grid FDTD with PML see [`crate::fem`]. + pub mod fluid_sim; pub mod heat_sim; pub mod em_sim; diff --git a/src/sim/rigid_body.rs b/src/sim/rigid_body.rs index c97b1e6..ba7e316 100644 --- a/src/sim/rigid_body.rs +++ b/src/sim/rigid_body.rs @@ -1,3 +1,19 @@ +//! Rigid body dynamics in three dimensions. +//! +//! State is position, linear velocity, orientation as a unit quaternion, +//! and angular velocity. Rotation uses a quaternion rather than Euler +//! angles because it composes without gimbal lock and stays well +//! conditioned under renormalization. +//! +//! Angular motion follows Euler's equations, which carry the `ω × Iω` +//! term -- the reason a freely spinning body with three distinct moments +//! of inertia tumbles rather than spinning steadily about an intermediate +//! axis. +//! +//! Includes inertia tensors for the standard bodies, force and torque +//! accumulation, sphere-sphere collision detection, and impulse-based +//! collision response with restitution. + use crate::math::Vec3; use crate::quaternion::Quaternion; diff --git a/src/sim/wave_sim.rs b/src/sim/wave_sim.rs index d335339..38120a8 100644 --- a/src/sim/wave_sim.rs +++ b/src/sim/wave_sim.rs @@ -1,3 +1,14 @@ +//! The wave equation in one and two dimensions. +//! +//! Explicit second-order finite differences on `∂²u/∂t² = c²∇²u`, with +//! fixed, free, and Mur first-order absorbing boundaries. The absorbing +//! condition passes a normally-incident wave out of the domain exactly and +//! degrades with the angle of incidence. +//! +//! Stability requires the Courant number `r = cΔt/Δx` to satisfy `r ≤ 1` +//! in 1-D and `r ≤ 1/√2` in 2-D. At exactly `r = 1` in one dimension the +//! scheme is an exact shift and has no dispersion error at all. + // Wave equation simulation on structured grids using finite differences. // // PDE (1D): ∂²u/∂t² = c² ∂²u/∂x² @@ -84,7 +95,7 @@ impl WaveEquation1D { } /// Advance one time step using the leapfrog scheme with fixed endpoints - /// u[0] = u[nx-1] = 0. + /// `u[0] = u[nx-1] = 0`. pub fn step(&mut self, dt: f64) { let r2 = (self.wave_speed * dt / self.dx).powi(2); @@ -105,9 +116,13 @@ impl WaveEquation1D { /// /// Interior update is identical to `step`. At the boundaries the outgoing /// characteristic is approximated: - /// u[0]^{n+1} = u[1]^n + (r - 1)/(r + 1) (u[1]^{n+1} - u[0]^n) - /// u[nx-1]^{n+1} = u[nx-2]^n + (r - 1)/(r + 1) (u[nx-2]^{n+1} - u[nx-1]^n) - /// where r = c dt / dx. + /// + /// ```text + /// u[0]^{n+1} = u[1]^n + (r - 1)/(r + 1) (u[1]^{n+1} - u[0]^n) + /// u[nx-1]^{n+1} = u[nx-2]^n + (r - 1)/(r + 1) (u[nx-2]^{n+1} - u[nx-1]^n) + /// ``` + /// + /// where `r = c dt / dx`. /// /// These conditions absorb normally-incident waves perfectly (first order /// in angle of incidence for oblique waves). diff --git a/src/solid_mechanics.rs b/src/solid_mechanics.rs index 2bcb3ad..ddf2b15 100644 --- a/src/solid_mechanics.rs +++ b/src/solid_mechanics.rs @@ -1,3 +1,19 @@ +//! Strength of materials: stress, strain, elastic constants and beams. +//! +//! Engineering and true stress and strain, and the elastic constants with +//! the identities that connect them -- any two of `E`, `G`, `K` and `ν` +//! determine the other two for an isotropic material, and the conversions +//! are all here. +//! +//! Beam bending: cantilever and simply-supported deflections, bending +//! moment and stress, and second moments of area for rectangular and +//! circular sections. Design closes with the von Mises equivalent stress, +//! the safety factor, and strain energy density. +//! +//! For the tensor formulation and yield surfaces see +//! [`crate::continuum_mechanics`]; for finite-element beams and modal +//! analysis see [`crate::resonance::structural`]. + use crate::math::constants::PI; // --------------------------------------------------------------------------- diff --git a/src/spatial/octree.rs b/src/spatial/octree.rs index dd16cb5..758f7a4 100644 --- a/src/spatial/octree.rs +++ b/src/spatial/octree.rs @@ -1,3 +1,15 @@ +//! Barnes-Hut octree for N-body force approximation. +//! +//! Direct summation costs O(N²). The octree groups distant bodies and +//! treats each group as a single mass at its centre of mass, which brings +//! the cost to O(N log N). +//! +//! The approximation is controlled by `theta`: a node is used as a whole +//! when its width divided by the distance to it is below that threshold. +//! Smaller `theta` is more accurate and slower, and `theta = 0` degenerates +//! to direct summation. The conventional default of 0.5 is +//! [`BH_THETA`]. + use crate::math::Vec3; use crate::math::constants::G; use crate::astrophysics::nbody::Body; diff --git a/src/statistics/fourier.rs b/src/statistics/fourier.rs index 500dc84..8cab80a 100644 --- a/src/statistics/fourier.rs +++ b/src/statistics/fourier.rs @@ -7,21 +7,21 @@ use crate::fractals::Complex; use crate::transforms::fft::{fft_any, ifft_any, rfft}; -/// Discrete Fourier Transform: X[k] = Σ x[n]·e^(-j2πkn/N), returns (real, imag) pairs +/// Discrete Fourier Transform: `X[k] = Σ x[n]·e^(-j2πkn/N)`, returns (real, imag) pairs #[must_use] pub fn dft(signal: &[f64]) -> Vec<(f64, f64)> { let buf: Vec = signal.iter().map(|&x| Complex::new(x, 0.0)).collect(); fft_any(&buf).iter().map(|c| (c.re, c.im)).collect() } -/// Inverse DFT: x[n] = (1/N)·Σ X[k]·e^(j2πkn/N) +/// Inverse DFT: `x[n] = (1/N)·Σ X[k]·e^(j2πkn/N)` #[must_use] pub fn inverse_dft(spectrum: &[(f64, f64)]) -> Vec { let buf: Vec = spectrum.iter().map(|&(re, im)| Complex::new(re, im)).collect(); ifft_any(&buf).iter().map(|c| c.re).collect() } -/// Power spectrum: |X[k]|² = Re² + Im² for each frequency bin. +/// Power spectrum: `|X[k]|² = Re² + Im²` for each frequency bin. /// /// Uses the real FFT and reconstructs the upper half from conjugate /// symmetry. Output length always equals `signal.len()`. diff --git a/src/thermodynamics.rs b/src/thermodynamics.rs index 7056ac5..a935ffa 100644 --- a/src/thermodynamics.rs +++ b/src/thermodynamics.rs @@ -1,3 +1,21 @@ +//! Thermodynamics: gases, heat transfer, cycles and phase change. +//! +//! The ideal gas law in each of its four solved forms, and the kinetic +//! picture behind it -- average kinetic energy, RMS speed, mean free path. +//! Work and entropy change along isothermal, isobaric and adiabatic paths. +//! +//! Heat transfer by all three mechanisms: Fourier conduction (with an +//! explicit 1-D stepper and its stability limit), Newton's law of cooling +//! and convection, and radiative exchange. The dimensionless groups that +//! classify convection -- Grashof, Rayleigh, Prandtl, Nusselt, Biot -- +//! are here too. +//! +//! Cycles through the Carnot efficiency and the coefficients of +//! performance for refrigerators and heat pumps; phase change through +//! latent heat, Clausius-Clapeyron, boiling-point elevation, freezing-point +//! depression, and wet-steam quality. Temperature scale conversions round +//! it out. + use crate::math::constants; // ── Ideal Gas Law ── diff --git a/src/transforms/fft.rs b/src/transforms/fft.rs index 1451e7c..7fb8d05 100644 --- a/src/transforms/fft.rs +++ b/src/transforms/fft.rs @@ -62,7 +62,7 @@ fn fft_in_place(buf: &mut [Complex], sign: f64) { } } -/// Forward FFT: X[k] = Σ x[n]·e^(−j2πkn/N). +/// Forward FFT: `X[k] = Σ x[n]·e^(−j2πkn/N)`. /// /// # Panics /// Panics unless `input.len()` is a power of two. Use [`fft_any`] for @@ -75,7 +75,7 @@ pub fn fft(input: &[Complex]) -> Vec { buf } -/// Inverse FFT: x[n] = (1/N)·Σ X[k]·e^(j2πkn/N). +/// Inverse FFT: `x[n] = (1/N)·Σ X[k]·e^(j2πkn/N)`. /// /// # Panics /// Panics unless `input.len()` is a power of two. Use [`ifft_any`] for @@ -210,7 +210,7 @@ pub fn ifft_any(x: &[Complex]) -> Vec { } /// FFT of a real signal, returning the n/2 + 1 non-redundant bins -/// (bins k > n/2 satisfy X[n−k] = X[k]*). Any length. +/// (bins `k > n/2` satisfy `X[n−k] = X[k]*`). Any length. #[must_use] pub fn rfft(input: &[f64]) -> Vec { let n = input.len(); diff --git a/src/trigonometry.rs b/src/trigonometry.rs index 9d44af9..ef837df 100644 --- a/src/trigonometry.rs +++ b/src/trigonometry.rs @@ -1,3 +1,17 @@ +//! Triangle solving, trigonometric identities, and hyperbolic functions. +//! +//! The laws of sines and cosines in both directions -- side from angles +//! and angle from sides -- and the SAS triangle area. +//! +//! The identities are provided as functions rather than left to the caller +//! to expand: sum and difference, double and half angle, and +//! product-to-sum. The hyperbolic family includes the reciprocals (`sech`, +//! `csch`, `coth`) and inverses that `f64` does not provide directly. +//! +//! Angle utilities close the module: normalization to `[0, 2π)` or +//! `(−π, π]`, the signed shortest difference between two angles, and +//! classification as acute, right or obtuse. + use crate::math::constants::PI; const TWO_PI: f64 = 2.0 * PI; diff --git a/src/waves.rs b/src/waves.rs index b3ce8f7..18a51d0 100644 --- a/src/waves.rs +++ b/src/waves.rs @@ -1,3 +1,21 @@ +//! Wave propagation: mechanical, acoustic and seismic. +//! +//! The kinematic relations (`v = fλ` and the wavenumber-frequency pair), +//! displacement, energy density and intensity, and the inverse-square +//! falloff of a spherical wave. The Doppler effect in both classical and +//! relativistic forms, with the Mach cone angle for supersonic sources. +//! +//! Standing waves on strings and in open and closed pipes, beats, and +//! superposition. Boundaries are handled by impedance: the reflection and +//! transmission coefficients follow from the impedance mismatch, which is +//! also why they carry a sign. +//! +//! Acoustics covers the speed of sound in a gas, sound pressure level and +//! the decibel scale, and absorption and penetration depth. Seismology +//! covers P-, S-, Rayleigh and Love wave speeds. Diffraction closes with +//! the Fraunhofer single-slit pattern, the Airy disk radius and the +//! Fresnel number. + use crate::math::constants; // ── Wave Basics ── diff --git a/tools/__pycache__/gen_module_map.cpython-311.pyc b/tools/__pycache__/gen_module_map.cpython-311.pyc new file mode 100644 index 0000000..a00593a Binary files /dev/null and b/tools/__pycache__/gen_module_map.cpython-311.pyc differ diff --git a/tools/check_module_docs.py b/tools/check_module_docs.py new file mode 100755 index 0000000..b6b71cf --- /dev/null +++ b/tools/check_module_docs.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +"""Fail if any source file lacks a `//!` module summary. + +Rustdoc does not warn about a missing module doc -- `missing_docs` covers +items, not modules -- so an undocumented module shows up as a blank page +in the generated documentation and as an empty row in +`docs/MODULE_MAP.md`. Nothing catches that but this. + +A file passes when its first line of substance (ignoring blank lines and +inner attributes such as `#![allow(...)]`) is a `//!` comment. + + python3 tools/check_module_docs.py +""" + +from __future__ import annotations + +import os +import sys + +SRC = "src" + + +def has_module_doc(path: str) -> bool: + with open(path, encoding="utf-8", errors="replace") as fh: + for line in fh: + stripped = line.strip() + if not stripped or stripped.startswith("#!["): + continue + return stripped.startswith("//!") + return False # an empty file documents nothing + + +def main() -> int: + if not os.path.isdir(SRC): + print("run from the repository root", file=sys.stderr) + return 2 + + missing, total = [], 0 + for root, _dirs, files in os.walk(SRC): + for name in sorted(files): + if not name.endswith(".rs"): + continue + total += 1 + path = os.path.join(root, name) + if not has_module_doc(path): + missing.append(path) + + if missing: + print(f"{len(missing)} of {total} source files have no `//!` module doc:", + file=sys.stderr) + for path in missing: + print(f" {path}", file=sys.stderr) + return 1 + + print(f"all {total} source files carry a module doc") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/gen_module_map.py b/tools/gen_module_map.py new file mode 100755 index 0000000..e5fead8 --- /dev/null +++ b/tools/gen_module_map.py @@ -0,0 +1,341 @@ +#!/usr/bin/env python3 +"""Generate docs/MODULE_MAP.md from the source tree. + +The map is generated rather than written by hand so that it cannot drift +out of date: `--check` re-derives it and fails if the committed file +differs, which is what CI runs. + +Every figure in the output comes from parsing the sources -- module +summary from the first `//!` line, counts of public items, lines of +code. Nothing is transcribed. + + python3 tools/gen_module_map.py # rewrite docs/MODULE_MAP.md + python3 tools/gen_module_map.py --check # exit 1 if it is stale +""" + +from __future__ import annotations + +import os +import re +import sys + +SRC = "src" +OUT = "docs/MODULE_MAP.md" + +# Groupings for the top-level listing. Anything not named here is +# collected under "Other" so a new module shows up rather than vanishing. +AREAS: list[tuple[str, list[str]]] = [ + ("Numeric foundations", ["core", "math", "linalg", "numerical", "special", "error"]), + ("Exact and symbolic", ["exact", "discrete", "graph", "codes"]), + ("Classical mechanics", ["classical", "gravitation", "solid_mechanics", + "continuum_mechanics", "resonance", "geophysics"]), + ("Thermal and statistical", ["thermodynamics", "statistical_mechanics", "radiation"]), + ("Electromagnetism", ["electromagnetism", "electronics", "rf", "photonics", + "plasma", "magnetohydrodynamics"]), + ("Waves and signals", ["waves", "optics", "acoustics", "transforms", "dsp", + "signal_processing", "audio"]), + ("Fluids", ["fluids", "cfd", "fluid_instabilities", "propulsion"]), + ("Modern physics", ["relativity", "general_relativity", "quantum", + "particle_physics", "nuclear", "neutronics"]), + ("Space", ["astrophysics"]), + ("PDE solvers", ["fem", "sim", "fields", "vector_calculus"]), + ("Chemistry and life", ["chemistry", "biophysics"]), + ("Probability and data", ["statistics", "stochastic", "monte_carlo", + "information_theory", "learn"]), + ("Decisions", ["optimization", "finance"]), + ("Geometry", ["geometry", "curves", "trigonometry", "quaternion", "manifold", + "spatial", "mesh"]), + ("Patterns and chaos", ["fractals", "patterns", "nonlinear"]), + ("Reference and utility", ["units", "materials", "color_science", + "control_systems", "atmosphere", "verification"]), +] + +PUB_FN = re.compile(r"pub (?:const |async |unsafe |extern )*fn ") +PUB_TYPE = re.compile(r"pub (?:struct|enum|trait) ") +IMPL_START = re.compile(r"(?:unsafe\s+)?impl[\s<]") + + +def scan(path: str) -> dict: + """Public item counts, line count and summary for one source file. + + Three things this has to get right, each of which it got wrong first: + + * **Methods against free functions** are told apart by the enclosing + `impl` block, not by indentation. An indented `pub fn` inside + `pub mod presets { ... }` is a free function, and there are 98 of + those; counting indentation put every one of them in the wrong + column. + * **Public types** are matched on the stripped line, so a `pub enum` + inside an inline `pub mod` is counted rather than skipped. + * **Test items** are skipped by tracking brace depth from + `#[cfg(test)]`, so a test helper never inflates the public surface. + + The count is syntactic: a type generated by a macro is counted once + where the macro defines it, not once per expansion. + """ + free = meth = types = 0 + depth = 0 + test_depth: int | None = None + impl_stack: list[int] = [] + pending_impl: int | None = None + summary_parts: list[str] = [] + in_summary = True + total = 0 + + with open(path, encoding="utf-8", errors="replace") as fh: + for line in fh: + total += 1 + stripped = line.strip() + + if in_summary: + if stripped.startswith("//!"): + text = stripped[3:].strip() + if text: + summary_parts.append(text) + elif summary_parts: + in_summary = False + elif stripped and not stripped.startswith("#!["): + in_summary = False + + if test_depth is None and stripped.startswith("#[cfg(test)]"): + test_depth = depth + + # Leave any impl bodies this line closed before classifying it. + while impl_stack and depth <= impl_stack[-1]: + impl_stack.pop() + + if test_depth is None: + if PUB_FN.match(stripped): + if impl_stack: + meth += 1 + else: + free += 1 + if PUB_TYPE.match(stripped): + types += 1 + + if pending_impl is None and IMPL_START.match(stripped): + pending_impl = depth + depth += line.count("{") - line.count("}") + # An impl header can carry a where clause over several lines, so + # the body starts at whichever line actually opens the brace. + if pending_impl is not None: + if depth > pending_impl: + impl_stack.append(pending_impl) + pending_impl = None + elif stripped.endswith(";"): + pending_impl = None # not an impl after all + if test_depth is not None and depth <= test_depth: + test_depth = None + + summary = " ".join(summary_parts) + # First sentence only, and never longer than a table cell wants. + match = re.match(r"(.+?[.!?])(?:\s|$)", summary) + if match: + summary = match.group(1) + summary = summary.replace("|", r"\|") + if len(summary) > 150: + summary = summary[:147].rsplit(" ", 1)[0] + "…" + return {"free": free, "meth": meth, "types": types, + "lines": total, "summary": summary or "—"} + + +def public_top_levels() -> set[str]: + """Top-level modules declared `pub mod` in lib.rs. + + `verification` is declared as a bare `mod`, so it is compiled and + tested but not part of the public API. Counting it as a public module + would make the totals here disagree with the README. + """ + out = set() + with open(os.path.join(SRC, "lib.rs"), encoding="utf-8") as fh: + for line in fh: + if line.startswith("pub mod "): + out.add(line.strip()[len("pub mod "):].rstrip(";")) + return out + + +def collect() -> dict[str, dict]: + """Every source file, keyed by its Rust module path.""" + out = {} + for root, _dirs, files in os.walk(SRC): + for name in sorted(files): + if not name.endswith(".rs"): + continue + path = os.path.join(root, name) + rel = os.path.relpath(path, SRC) + mod = rel[:-3].replace(os.sep, "::") + if mod.endswith("::mod"): + mod = mod[:-5] + out[mod] = scan(path) | {"path": path, "rel": rel} + return out + + +def render(mods: dict[str, dict]) -> str: + tops = sorted({m.split("::")[0] for m in mods if m != "lib"}) + public = public_top_levels() + private = [t for t in tops if t not in public] + named = {n for _, names in AREAS for n in names} + areas = AREAS + [("Other", sorted(set(tops) - named))] + + total_lines = sum(m["lines"] for m in mods.values()) + total_free = sum(m["free"] for m in mods.values()) + total_meth = sum(m["meth"] for m in mods.values()) + total_types = sum(m["types"] for m in mods.values()) + + L: list[str] = [] + L.append("# Module map") + L.append("") + L.append("**Generated file — do not edit.** Produced by") + L.append("[`tools/gen_module_map.py`](../tools/gen_module_map.py) from the source") + L.append("tree; CI fails if it is out of date. Regenerate with:") + L.append("") + L.append("```bash") + L.append("python3 tools/gen_module_map.py") + L.append("```") + L.append("") + L.append("Every figure below is parsed from the sources. Summaries are the first") + L.append("sentence of each module's `//!` documentation. Public-item counts exclude") + L.append("anything inside `#[cfg(test)]`, and tell a method from a free function by") + L.append("the enclosing `impl` block rather than by indentation -- an indented") + L.append("`pub fn` inside an inline `pub mod` is a free function, and there are 175") + L.append("of those.") + L.append("") + L.append("The count is syntactic, so an item generated by a macro is counted once") + L.append("where the macro defines it rather than once per expansion. That affects") + L.append("two places: `units::quantity`, whose `unit_ctor!` generates about thirty") + L.append("constructors from one template, and `spatial::kdtree`, whose macro") + L.append("generates two tree types from one.") + L.append("") + L.append(f"**{len(mods) - 1} modules** across **{len(public)} public top-level " + f"modules**, **{total_lines:,} lines** in " + f"**{len(mods)} files** (the modules plus the crate root `src/lib.rs`), " + f"**{total_free:,} public functions** and **{total_meth:,} public methods**, " + f"**{total_types:,} public types**.") + if private: + names = ", ".join(f"`{p}`" for p in private) + L.append("") + L.append(f"{names} is compiled and tested but declared `mod` rather than " + "`pub mod`, so it is not part of the public API and is excluded from " + "the module count above.") + L.append("") + + # ---- tree ------------------------------------------------------- + # Rendered recursively over the module hierarchy. Doing it with one + # flat pass loses any directory below the first: numerical/ode/ came + # out as an `ode.rs` sibling with adaptive.rs and friends hoisted up + # beside bvp.rs, which is not where they live. + def children_of(prefix: str) -> list[str]: + """Immediate children of a module path, directories and files.""" + depth = prefix.count("::") + 1 if prefix else 0 + seen = [] + for mod in mods: + if mod == "lib" or mod == prefix: + continue + if prefix and not mod.startswith(prefix + "::"): + continue + parts = mod.split("::") + if len(parts) <= depth: + continue + name = "::".join(parts[:depth + 1]) + if name not in seen: + seen.append(name) + return sorted(seen) + + def subtree_lines(mod: str) -> int: + """Lines in a module and everything beneath it.""" + total = mods[mod]["lines"] if mod in mods else 0 + total += sum(mods[m]["lines"] for m in mods + if m != "lib" and m.startswith(mod + "::")) + return total + + def emit(prefix: str, indent: str) -> None: + kids = children_of(prefix) + for i, kid in enumerate(kids): + last = i == len(kids) - 1 + stem = "└── " if last else "├── " + leaf = kid.split("::")[-1] + grandkids = children_of(kid) + tag = "" + if not prefix and kid not in public: + tag = " (private)" + if grandkids: + label = leaf + "/" + n = subtree_lines(kid) + else: + label = leaf + ".rs" + n = mods[kid]["lines"] + width = max(4, 28 - len(indent)) + L.append(f"{indent}{stem}{label:<{width}}{n:>8,}{tag}") + if grandkids: + emit(kid, indent + (" " if last else "│ ")) + + L.append("## Tree") + L.append("") + L.append("A directory's figure is its own `mod.rs` plus everything beneath it.") + L.append("") + L.append("```") + L.append(f"src/{' ' * 28}{'lines':>8}") + L.append(f"├── {'lib.rs':<28}{mods['lib']['lines']:>8,} (crate root)") + emit("", "") + L.append("```") + L.append("") + + # ---- by area ---------------------------------------------------- + L.append("## By area") + L.append("") + for area, names in areas: + present = [n for n in names if n in tops] + if not present: + continue + L.append(f"### {area}") + L.append("") + L.append("| Module | Lines | Public fns | Types | What it is |") + L.append("|---|--:|--:|--:|---|") + for name in present: + subs = sorted(m for m in mods + if m != "lib" and (m == name or m.startswith(name + "::"))) + lines = sum(mods[s]["lines"] for s in subs) + fns = sum(mods[s]["free"] + mods[s]["meth"] for s in subs) + types = sum(mods[s]["types"] for s in subs) + summary = mods[name]["summary"] if name in mods else "—" + L.append(f"| **`{name}`** | {lines:,} | {fns:,} | {types:,} | {summary} |") + L.append("") + + # ---- every module ---------------------------------------------- + L.append("## Every module") + L.append("") + L.append("| Path | Module | Lines | Fns | Methods | Types | Summary |") + L.append("|---|---|--:|--:|--:|--:|---|") + for mod in sorted(mods): + if mod == "lib": + continue + m = mods[mod] + L.append(f"| `{m['rel']}` | `{mod}` | {m['lines']:,} | {m['free']} " + f"| {m['meth']} | {m['types']} | {m['summary']} |") + L.append("") + return "\n".join(L) + + +def main() -> int: + if not os.path.isdir(SRC): + print("run from the repository root", file=sys.stderr) + return 2 + text = render(collect()) + check = "--check" in sys.argv + existing = open(OUT, encoding="utf-8").read() if os.path.exists(OUT) else None + if check: + if existing == text: + print(f"{OUT} is up to date") + return 0 + print(f"{OUT} is STALE — run `python3 {sys.argv[0]}` and commit the result", + file=sys.stderr) + return 1 + os.makedirs(os.path.dirname(OUT), exist_ok=True) + with open(OUT, "w", encoding="utf-8") as fh: + fh.write(text) + print(f"wrote {OUT}") + return 0 + + +if __name__ == "__main__": + sys.exit(main())