Scientific measurements
Declare measurement uncertainty and physical units, preserve shared error sources, and follow complete native examples into the EvidenceTensor API and sensor workflows.
aner.science provides native measurement uncertainty through EvidenceTensor: nominal values, physical units and retained error source identity travel together through supported affine operations. The module supports explicitly exact values, unknown uncertainty and a declared source aware measurement model. It runs on frozen CPU Float64 values and needs no external service or data package.
Start with the complete small example below, then use the EvidenceTensor API reference for constructor details, overloads, diagnostics and resource costs. Shared calibration sensor fusion develops the same model into a longer application with a frozen physical relationship and intentional failure. These pages are references and applications within aner.science; they do not require importing a deeper module name.
Choose the value contract
| Need | Value and import | Next page |
|---|---|---|
| Numerical arrays and differentiation | Tensor from aner.tensor or aner.nn | Tensor |
| Coordinates and physical units | SemanticTensor from aner.tensor | SemanticTensor |
| Units plus explicitly declared measurement uncertainty | EvidenceTensor from aner.science | EvidenceTensor |
| Row identity, population roles and learned preprocessing | AdaptiveFrame from aner.data | AdaptiveFrame and FeatureLedger |
Import aner.tensor alongside aner.science when creating numerical literals or SemanticTensor values. Ordinary Tensor operations and neural losses consume numerical values; they do not infer or propagate measurement uncertainty. A variance alone does not define a Gaussian distribution, confidence interval or prediction probability.
Measurement workflow
- Declare nominal values and physical units. Use
science.calibratedfor independent reading noise plus one common calibration source, orscience.measurementsto specify independent base sources and their coefficients explicitly. - Select observations with
gather_rows. Selection retains the original source identities, including repeated observations. - Combine compatible observations through
add,subtractor the two operandmean; convert units or apply a frozen physicalaffinerelationship. - Read the nominal value, variance, standard uncertainty or covariance. Use
summary/explainand source map accessors to inspect the declared model. - At a values only interoperability boundary, call
export_values(reason)and retain its report. The numerical consumer then receives nominal values without the evidence contracts.
Two separate constructor calls create separate source registries. Reusing the same names or numeric settings does not prove independence or a known correlation between them. Declare related readings together, then gather them from that one value. Unknown uncertainty is not zero: covariance, variance and supported propagation refuse an unknown model.
Run a complete example
After installing Aner, save the following program as science_basics.aner, or use the bundled source. With the bundle's examples directory in the current folder, run:
aner check examples/science_basics.aner
aner run examples/science_basics.anerThe complete fixture is in source. No CSV file, database, GPU or network is required; the default CPU Float64 configuration is sufficient.
// CPU Float64 measurements with independent reading noise and shared calibration.
import aner.tensor
import aner.science
let readings = science.calibrated([[20.0], [22.0]], "degC", 0.2, 0.3)
let first = readings.gather_rows(List(0))
let second = readings.gather_rows(List(1))
let fused = science.mean(first, second)
let difference = first.subtract(second)
print("Fused temperature")
print(fused.item())
print(fused.unit())
print("Fused variance is 0.11 within tolerance")
print(fused.variance() > 0.109999999999 && fused.variance() < 0.110000000001)
print("Shared covariance is 0.09 within tolerance")
let shared = science.covariance(readings, 0, 0, readings, 1, 0)
print(shared > 0.089999999999 && shared < 0.090000000001)
print("Difference temperature")
print(difference.item())
print(difference.unit())
print("Difference variance is 0.08 within tolerance")
print(difference.variance() > 0.079999999999 && difference.variance() < 0.080000000001)
print("A reading minus itself has zero variance")
print(first.subtract(first).variance())
print("Kelvin conversion retains the source model")
let kelvin = fused.convert("K")
print(kelvin.item() > 294.149999999 && kelvin.item() < 294.150000001)
print(kelvin.variance() > 0.109999999999 && kelvin.variance() < 0.110000000001)Expected output:
Fused temperature
21.0
degC
Fused variance is 0.11 within tolerance
true
Shared covariance is 0.09 within tolerance
true
Difference temperature
-2.0
delta_degC
Difference variance is 0.08 within tolerance
true
A reading minus itself has zero variance
0.0
Kelvin conversion retains the source model
true
trueEach observation has variance 0.2² + 0.3² = 0.13 degC². Their covariance is the shared calibration variance 0.09 degC². The mean has variance 0.11 degC²; the difference has variance 0.08 delta_degC². Converting an absolute temperature to Kelvin changes the nominal offset, while retaining the same physical variance. Tolerance checks keep the example reproducible across harmless Float64 formatting differences.
If you save the source outside the bundle, use aner check science_basics.aner and aner run science_basics.aner instead. Explicit source coefficients provides a second complete program covering measurements, exact, unknown and acknowledged numerical export; its expected output and assumptions are in the EvidenceTensor reference.
API map
All functions below are native and require import aner.science. EvidenceTensor receivers also support the corresponding method spelling, such as value.variance() or value.convert("K"). The full typed signatures appear in the EvidenceTensor reference.
| Call and inputs | Result and contract |
|---|---|
science.calibrated(values: Tensor, unit: String, noise_stddev: Float64, calibration_stddev: Float64) | EvidenceTensor; one column frozen CPU Float64 readings, independent per reading noise and one independent common calibration source. Standard deviations are finite, nonnegative and expressed in the corresponding difference unit. |
science.measurements(values: SemanticTensor, source_names: List, stddevs: List, coefficients: Tensor, error_unit: String, independence: String) | EvidenceTensor; explicit independent sources. Names are unique Strings, standard deviations are Float64 values, independence is exactly "independent", and coefficients have one row per scalar value and one column per source. |
science.exact(values: SemanticTensor) | EvidenceTensor; an explicit declaration of zero measurement uncertainty, retaining units and coordinates. |
science.unknown(values: SemanticTensor) | EvidenceTensor; nominal values and context with no quantified uncertainty. |
science.gather_rows(self: EvidenceTensor, indices: List) | EvidenceTensor; nonempty zero based Int64 row selection, retaining source identities. |
science.add(self: EvidenceTensor, other: EvidenceTensor) | EvidenceTensor; compatible shape, coordinate domain, unit dimensions and known source relationships. Ordinary addition of two absolute temperatures fails. |
science.subtract(self: EvidenceTensor, other: EvidenceTensor) | EvidenceTensor; source aware difference; compatible absolute temperatures yield a difference unit. |
science.mean(self: EvidenceTensor, other: EvidenceTensor) | EvidenceTensor; elementwise average of exactly two compatible values, including absolute temperatures. It is not an all rows reduction. |
science.convert(self: EvidenceTensor, unit: String) | EvidenceTensor; supported compatible unit conversion. Variance scales by the squared conversion scale; an offset does not change it. |
science.affine(self: EvidenceTensor, slope: Float64, intercept: Float64, slope_unit: String, output_unit: String) | EvidenceTensor; frozen physical slope × input + intercept, with the intercept expressed in the output unit. Input, slope and output must be non absolute quantities with compatible dimensions. |
science.item(self: EvidenceTensor) | Float64; nominal readout from a 1 × 1 value, including an unknown model. |
science.unit(self: EvidenceTensor) | String; the declared homogeneous physical unit. |
science.variance(self: EvidenceTensor) or science.variance(self, row: Int64, column: Int64) | Float64; variance in squared units. The no index overload requires a scalar; indexed reads use zero based in bounds cells. Unknown uncertainty fails. |
science.standard_uncertainty(self: EvidenceTensor) or science.standard_uncertainty(self, row: Int64, column: Int64) | Float64; nonnegative square root of variance, in the corresponding difference unit. The no index overload requires a scalar. |
science.covariance(self: EvidenceTensor, row: Int64, column: Int64, other: EvidenceTensor, other_row: Int64, other_column: Int64) | Float64; covariance between two selected cells whose source relationship is known, in the product of their difference units. |
science.summary(self: EvidenceTensor), science.explain(self: EvidenceTensor) | String; shape, units, uncertainty state, source map allocation, backend and declared assumptions. These are inspection reports, not serialized evidence artifacts. |
science.source_entries(self: EvidenceTensor) | Int64; active nonzero source coefficients, not a count of independent observations. |
science.source_bytes(self: EvidenceTensor) | Int64; allocated source map vector buffers, including capacity. It excludes the source registry and process RSS. |
science.export_values(self: EvidenceTensor, reason: String) | ContextExport; explicit projection of nominal values. export.values() returns a Tensor; export.report() describes erased contracts and records uncertainty_consumed=false. |
Errors and current limits
Wrong Aner argument types or missing imports fail aner check. Scientific runtime failures are source located R3503 diagnostics with a semantic code such as E_UNIT_INCOMPATIBLE, E_CORRELATION_UNKNOWN, E_AXIS_ALIGNMENT, E_EVIDENCE_UNSUPPORTED, E_BACKEND_UNSUPPORTED, E_NUMERIC or E_RESOURCE_BUDGET. An error stops the operation; uncertainty is never silently replaced with zero or discarded by propagation.
Evidence construction requires frozen CPU Float64 values, at most 65,536 scalar cells and at most 262,144 active source coefficients. The explicit measurements constructor admits at most 4,096 base sources; each source name is a unique nonempty UTF-8 String of at most 128 bytes without control characters. Fitted contextual transformations retain at most 64 registered operation records. Nonzero errors that underflow or overflow the supported Float64 representation fail explicitly.
The current model covers declared affine source relationships. General nonlinear uncertainty propagation, GPU evidence kernels, source map persistence, arbitrary covariance matrices, Monte Carlo distributions and uncertainty aware neural training remain future functionality. See the EvidenceTensor reference for precise time/space costs and the SemanticTensor unit registry for accepted unit names.