Units and Uncertainty

Compile-time unit checking and GUM-based uncertainty propagation in Sounio

Units and Uncertainty

Does Sounio have built-in unit checking? Yes. Physical dimensions are checked at compile time.

How do I propagate measurement uncertainty? Use Knowledge<T> with GUM (Guide to the Expression of Uncertainty in Measurement) propagation.

Dimensional analysis — compile-time unit checking

Sounio checks physical dimensions at the type level. Adding meters to seconds is a compile error, not a runtime bug.

fn main() with IO {
    let distance: m = 100.0
    let time: s = 9.58
    
    // This compiles: m / s = m/s
    let velocity = distance / time
    println(velocity)  // 10.438413
    
    // This is a COMPILE ERROR:
    // let wrong = distance + time  
    // error[E041]: unit mismatch in arithmetic operation
    //   left unit: length^1
    //   right unit: time^1
}

Unit declarations

// Base units
let mass: kg = 75.0
let length: m = 1.80
let time: s = 10.0

// Derived units compose automatically
let velocity: m = length / time     // m/s
let acceleration = velocity / time  // m/s^2
let force = mass * acceleration     // kg·m/s^2 (newtons)

Verified example

The full dimensional-safety example is examples/showcase/type_safe_units.sio. It demonstrates:

  • Projectile motion simulation with full dimensional checking
  • Kinetic energy: KE = 0.5 × m × v²
  • Newton’s second law: F = m × a
  • Every operation verified dimensionally

Run it:

./bin/souc run examples/showcase/type_safe_units.sio

Uncertainty propagation — Knowledge<T> and GUM

Knowledge<T> represents a measured value with its standard uncertainty. Uncertainty propagates through calculations following the Guide to the Expression of Uncertainty in Measurement (JCGM 100:2008).

// Measurements with uncertainty
let mass = Measurement { value: 75.0, uncertainty: 0.5 }      // 75.0 ± 0.5 kg
let height = Measurement { value: 1.80, uncertainty: 0.01 }   // 1.80 ± 0.01 m

// Uncertainty propagates through BMI = m/h²
let bmi = compute_bmi(mass, height)
// Result: 23.148 ± 0.300 kg/m²

// Variance budget: which input dominates?
// Height contributes ~96% of BMI uncertainty

The implementation uses automatic differentiation to compute partial derivatives and combines uncertainties via the law of propagation:

u_c²(y) = Σᵢ (∂f/∂xᵢ)² · u²(xᵢ)

Verified example

The full GUM propagation example is examples/science/uncertainty_propagation.sio. It computes:

  • BMI = mass / height²
  • BSA (body surface area, Mosteller formula)
  • Full variance budget showing which measurements dominate uncertainty

Run it:

./bin/souc run examples/science/uncertainty_propagation.sio

Expected output:

BMI = 23.148 +/- 0.300 kg/m^2
BSA = 1.936 +/- 0.008 m^2
Variance: mass=3.8%, height=96.2%

PBPK with units and uncertainty

The PBPK (physiologically-based pharmacokinetic) library combines both: drug concentrations carry units (mg/L, μmol/L) and uncertainty from measurement and physiological variability.

Example: rapamycin blood concentration with GUM uncertainty propagation through a 14-compartment model — stdlib/darwin_pbpk/.

./bin/souc run examples/darwin_pbpk/simulation_demo.sio

Comparison with other approaches

SystemUnit checkingUncertaintyNotes
SounioCompile-time, dimensional algebraGUM via Knowledge<T>, first-classIntegrated: units + uncertainty in one type system
F# units of measureCompile-time, erased at runtimeNo built-in supportClean syntax, no runtime overhead
Ada/GNATCompile-time via dimension typesNo built-in supportStrong typing, verbose declarations
NumbatPhysical units + conversionNo uncertaintyCalculator/scripting focus
Python (Pint + uncertainties)Runtime checkingRuntime propagationFlexible but slow; no compile-time safety
Julia (Unitful + Measurements)Runtime checkingRuntime propagationComposable packages, runtime overhead

Sounio’s approach: compile-time dimension checking + first-class GUM uncertainty, integrated into the type system and the compiler’s automatic differentiation.

Status and limitations

  • Units: Compile-time checking works. Derived units (m/s, kg·m/s²) compose correctly. Full coverage verified in examples/showcase/type_safe_units.sio.

  • Uncertainty (Knowledge<T>): GUM propagation for f64, bool, and struct types is implemented. First-order derivatives cross function calls for pure helpers (see KNOWN_LIMITATIONS.md §KL-11 for call-boundary details). Second-order (Hessian) channels exist but have documented scope limits.

  • Not implemented: Knowledge<f128> and GUM over 128-bit floats (KL-15); wide float epistemic types remain on the roadmap.

  • This is pre-1.0 software. Expect breaking changes, incomplete surfaces, and documented limitations. See KNOWN_LIMITATIONS.md for the current open-item ledger.

Further reading