Added complex and covariance matrix quantity math - #11
Conversation
2e5d14c to
a85cfb3
Compare
a85cfb3 to
03b87ba
Compare
There was a problem hiding this comment.
Pull request overview
This PR extends Dcc::QuantityMath with multivariate uncertainty propagation via covariance matrices and introduces a Cartesian complex quantity built on that multivariate model, ensuring correlations are preserved across chained operations.
Changes:
- Add
Dcc::QuantityMath::Matrixwith covariance validation (symmetry/PSD) and Jacobian-based propagation (C_y = J C J^T). - Add
Dcc::QuantityMath::Complexbacked by a 2-elementMatrix, with full 2×2 covariance propagation through+ - * /. - Add
Dcc::QuantityMath.exact_covarianceandSQRT_PRECISIONto ensure covariance math is performed at unlimited BigDecimal precision, plus comprehensive specs for the new functionality.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| lib/dcc/quantity_math.rb | Adds SQRT_PRECISION, autoloads Matrix/Complex, and introduces exact_covariance to run covariance math with BigDecimal.limit(0). |
| lib/dcc/quantity_math/matrix.rb | Implements multivariate quantity representation with covariance validation and Jacobian-based propagation. |
| lib/dcc/quantity_math/complex.rb | Implements complex arithmetic and covariance propagation using a 2-element Matrix, including bounded derivative precision for division. |
| spec/dcc/quantity_math/matrix_spec.rb | Adds unit, shape, symmetry/PSD validation, propagation, and BigDecimal.limit restoration tests for Matrix. |
| spec/dcc/quantity_math/complex_spec.rb | Adds arithmetic, covariance propagation (including chaining), division edge cases, and reduced-limit stability tests for Complex. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (2)
lib/dcc/quantity_math/matrix.rb:40
Matrix#[]always returns aRealwith a non-niluncertainty(computed viasqrt), even when the variance is exactly zero. In this codebaseReal#uncertain?is based onuncertainty.nil?, so a zero-variance element currently becomes "uncertain" and will print± 0/propagate as uncertain when used in furtherRealarithmetic (e.g.,Complex#realfor an exact complex). Consider treating a zero variance as exact and returninguncertainty: nilin that case.
def [](index)
ensure_index!(index)
Real.new(value: values[index], unit: units[index],
uncertainty: covariance[index][index].sqrt(SQRT_PRECISION))
end
lib/dcc/quantity_math/complex.rb:156
Complex#to_salways renders± <uncertainty>for both components. For an exact complex (covariancediagonal entries are zero), this produces output like± 0, which is inconsistent withQuantity#to_s/Real#to_s(they omit the uncertainty entirely when exact) and can be misleading to users reading formatted quantities. Consider omitting the± …part per component when its uncertainty is zero.
def to_s
re, im = matrix.values
u_re, u_im = matrix.uncertainties
sign = im.negative? ? "-" : "+"
suffix = unit ? " #{unit}" : ""
"(#{re} ± #{u_re}) #{sign} (#{im.abs} ± #{u_im})i#{suffix}"
end
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (1)
lib/dcc/quantity_math/matrix.rb:40
Matrix#[]always constructs aRealwith a non-nil uncertainty (it usessqrt(variance)even when the variance is exactly 0). In this codebase,Quantity#uncertain?is defined as!uncertainty.nil?, so a zero-variance element currently becomes "uncertain" and renders as± 0.0, which contradicts the intended semantics for exact values (andComplex's own rendering logic for zero variance).
def [](index)
ensure_index!(index)
Real.new(value: values[index], unit: units[index],
uncertainty: covariance[index][index].sqrt(SQRT_PRECISION))
end
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (1)
TODO.complete/29-uncertainty-propagation.md:15
- This says
ComplexandMatrixtake exact BigDecimal square roots, butBigDecimal#sqrt(SQRT_PRECISION)is still a rounded approximation (just much higher precision thanFloat). Reword to avoid implying the result is mathematically exact.
- `Real` propagates uncertainty through `Math.sqrt(x.to_f)`
(`lib/dcc/quantity_math/real.rb:79`, `:90`), so RSS and fractional results
are capped at double precision rather than honouring the BigDecimal
precision the design notes describe. `Complex` and `Matrix` do take exact
BigDecimal square roots.
Adds Cartesian complex arithmetic and multivariate covariance propagation to Dcc::QuantityMath.
Complexis built on a two-elementMatrix, so the propagation formula lives in oneplace. An earlier version kept the two parts independent, which gave wrong answers once
you chained operations.
(z1 * z2) * z3came out 0.2625 instead of 0.3897.Known and accepted:
compose_unit/inverse_unitare duplicated fromreal.rb. Two copies, not three.Extracting them means editing a file outside this PR.
\ohm\cdot\ohm). That is whatRealalready does.==/hashon the new classes. A real gap, but that is its own feature.x.div(ONE, n)is BigDecimal's way of rounding to n digits, not a stray division.BigDecimal.limitis changed inside a block, butsave_limitrestores it even on raise.SQRT_PRECISIONandDERIVATIVE_PRECISIONare both 30 and mean different things. Keptseparate on purpose so changing one does not drag the other.