hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

commit 117e865fc88083e3ffc81f258297bbe6f8139088
parent f6b0a5046e32ed5be9f201ba2283add5020a6360
Author: triesap <tyson@radroots.org>
Date:   Mon, 21 Sep 2026 12:55:27 +0000

core: add bounded exact quantity arithmetic

Diffstat:
Asrc/hyf_core/domain/quantity.mojo | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/test_domain.mojo | 31+++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+), 0 deletions(-)

diff --git a/src/hyf_core/domain/quantity.mojo b/src/hyf_core/domain/quantity.mojo @@ -0,0 +1,104 @@ +from std.collections import Optional + + +@fieldwise_init +struct Quantity(Copyable, Movable): + var value: Int + var scale: Int + var unit: String + var dimension: String + var qualifier: String + + +def _pow10(exponent: Int) -> Int: + var result = 1 + for _ in range(exponent): + result *= 10 + return result + + +def _checked_mul10(value: Int, times: Int) raises -> Int: + var result = value + for _ in range(times): + var before = result + result = before * 10 + if before != 0 and result // 10 != before: + raise Error("quantity overflow") + return result + + +def _checked_add(left: Int, right: Int) raises -> Int: + var result = left + right + if left > 0 and right > 0 and result < 0: + raise Error("quantity overflow") + if left < 0 and right < 0 and result >= 0: + raise Error("quantity overflow") + return result + + +def new_quantity( + value: Int, scale: Int, unit: String, dimension: String, qualifier: String +) raises -> Quantity: + if scale < 0 or scale > 9: + raise Error("quantity scale must be between 0 and 9") + if qualifier != "exact" and qualifier != "approximate": + raise Error("quantity qualifier must be 'exact' or 'approximate'") + if unit.strip() == "" or dimension.strip() == "": + raise Error("quantity requires unit and dimension") + return Quantity( + value=value, + scale=scale, + unit=String(unit), + dimension=String(dimension), + qualifier=String(qualifier), + ) + + +def quantity_rescale(quantity: Quantity, target_scale: Int) raises -> Quantity: + if target_scale < quantity.scale: + raise Error("quantity rescale must not reduce precision") + var value = _checked_mul10(quantity.value, target_scale - quantity.scale) + var result = quantity.copy() + result.value = value + result.scale = target_scale + return result^ + + +def _compatible(left: Quantity, right: Quantity) raises: + if left.unit != right.unit: + raise Error("quantity units differ: " + left.unit + " vs " + right.unit) + if left.dimension != right.dimension: + raise Error("quantity dimensions differ") + + +def quantity_add(left: Quantity, right: Quantity) raises -> Quantity: + _compatible(left, right) + var scale = left.scale if left.scale > right.scale else right.scale + var scaled_left = quantity_rescale(left, scale) + var scaled_right = quantity_rescale(right, scale) + var qualifier = "exact" + if left.qualifier == "approximate" or right.qualifier == "approximate": + qualifier = "approximate" + return new_quantity( + _checked_add(scaled_left.value, scaled_right.value), + scale, + left.unit, + left.dimension, + qualifier, + ) + + +def quantity_compare(left: Quantity, right: Quantity) raises -> Int: + _compatible(left, right) + var scale = left.scale if left.scale > right.scale else right.scale + var scaled_left = quantity_rescale(left, scale).value + var scaled_right = quantity_rescale(right, scale).value + if scaled_left < scaled_right: + return -1 + if scaled_left > scaled_right: + return 1 + return 0 + + +def quantity_is_negative(quantity: Quantity) -> Bool: + return quantity.value < 0 diff --git a/tests/test_domain.mojo b/tests/test_domain.mojo @@ -99,3 +99,34 @@ def test_field_known_zero_distinct_from_unknown_and_false() raises: validate_field_consistency(unknown) var approximate = known_approximate_field("80", "span") assert_equal(approximate.qualifier, "approximate") + + +from hyf_core.domain.quantity import ( + new_quantity, + quantity_add, + quantity_compare, + quantity_is_negative, + quantity_rescale, +) + + +def test_quantity_exact_compare_and_scale() raises: + var a = new_quantity(8000, 2, "kg", "mass", "exact") + var b = new_quantity(80, 0, "kg", "mass", "exact") + assert_equal(quantity_compare(a, b), 0) + var c = new_quantity(50, 0, "kg", "mass", "exact") + assert_equal(quantity_compare(c, b), -1) + assert_equal(quantity_rescale(b, 2).value, 8000) + + +def test_quantity_add_overflow_and_approximation() raises: + var approx = new_quantity(80, 0, "lb", "mass", "approximate") + var exact = new_quantity(5, 0, "lb", "mass", "exact") + var total = quantity_add(approx, exact) + assert_equal(total.value, 85) + assert_equal(total.qualifier, "approximate") + var huge = new_quantity(9223372036854775807, 0, "kg", "mass", "exact") + with assert_raises(): + _ = quantity_add(huge, exact) + var adjustment = new_quantity(-5, 0, "kg", "mass", "exact") + assert_true(quantity_is_negative(adjustment))