feat: math core v3 engine upgrade
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
"""Property-based tests for v3 macro and competitive layers.
|
||||
|
||||
Validates:
|
||||
- Property 13: Noisy-OR normalized exposure is bounded in [0, 1]
|
||||
- Property 14: Competitive LLR is clamped to [-1.25, 1.25]
|
||||
- Property 15: Graph attenuation is zero beyond max distance
|
||||
|
||||
Requirements: 9.1, 9.2, 10.3, 10.4, 10.5
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from hypothesis import given, settings
|
||||
from hypothesis import strategies as st
|
||||
|
||||
from services.aggregation.interpolation import (
|
||||
compute_macro_llr,
|
||||
compute_normalized_macro_exposure,
|
||||
)
|
||||
from services.aggregation.signal_propagation import (
|
||||
compute_competitive_llr,
|
||||
compute_shrunk_correlation,
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Strategies
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
unit_floats = st.floats(min_value=0.0, max_value=1.0, allow_nan=False, allow_infinity=False)
|
||||
llr_source_values = st.floats(min_value=-5.0, max_value=5.0, allow_nan=False, allow_infinity=False)
|
||||
distances_valid = st.integers(min_value=1, max_value=3)
|
||||
distances_beyond = st.integers(min_value=4, max_value=10)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Feature: math-core-v3-engine, Property 13: Noisy-OR normalized exposure
|
||||
# is bounded in [0, 1]
|
||||
# ---------------------------------------------------------------------------
|
||||
# **Validates: Requirements 9.1, 9.2**
|
||||
|
||||
|
||||
@settings(max_examples=100)
|
||||
@given(
|
||||
geo=unit_floats,
|
||||
supply=unit_floats,
|
||||
commodity=unit_floats,
|
||||
sector=unit_floats,
|
||||
)
|
||||
def test_property_13_noisy_or_exposure_bounded(
|
||||
geo: float,
|
||||
supply: float,
|
||||
commodity: float,
|
||||
sector: float,
|
||||
) -> None:
|
||||
"""Property 13: Noisy-OR normalized exposure is bounded in [0, 1].
|
||||
|
||||
For any overlap values O_k in [0, 1] for each dimension (geo, supply,
|
||||
commodity, sector) with fixed positive weights, the normalized macro
|
||||
exposure E_macro SHALL be in [0.0, 1.0], reaching exactly 1.0 when
|
||||
all O_k = 1.0. (Use tier="regional" with dampener=1.0 for this
|
||||
property test)
|
||||
"""
|
||||
overlaps = {
|
||||
"geo": geo,
|
||||
"supply": supply,
|
||||
"commodity": commodity,
|
||||
"sector": sector,
|
||||
}
|
||||
e_macro = compute_normalized_macro_exposure(overlaps, tier="regional")
|
||||
|
||||
# Must be bounded in [0, 1] with regional dampener = 1.0
|
||||
assert 0.0 <= e_macro <= 1.0, (
|
||||
f"E_macro={e_macro} out of bounds [0, 1] for overlaps={overlaps}"
|
||||
)
|
||||
|
||||
|
||||
@settings(max_examples=1)
|
||||
@given(st.just(None))
|
||||
def test_property_13_max_exposure_is_one(_: None) -> None:
|
||||
"""Property 13 (edge): E_macro reaches exactly 1.0 when all O_k = 1.0."""
|
||||
overlaps = {"geo": 1.0, "supply": 1.0, "commodity": 1.0, "sector": 1.0}
|
||||
e_macro = compute_normalized_macro_exposure(overlaps, tier="regional")
|
||||
assert e_macro == 1.0, f"Expected 1.0 when all overlaps=1.0, got {e_macro}"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Feature: math-core-v3-engine, Property 14: Competitive LLR is clamped
|
||||
# to [-1.25, 1.25]
|
||||
# ---------------------------------------------------------------------------
|
||||
# **Validates: Requirements 10.3, 10.4, 10.5**
|
||||
|
||||
|
||||
@settings(max_examples=100)
|
||||
@given(
|
||||
llr_source=llr_source_values,
|
||||
rho_rolling=unit_floats,
|
||||
n_observations=st.integers(min_value=1, max_value=500),
|
||||
same_sector=st.booleans(),
|
||||
d_network=distances_valid,
|
||||
pattern_confidence=unit_floats,
|
||||
)
|
||||
def test_property_14_competitive_llr_clamped(
|
||||
llr_source: float,
|
||||
rho_rolling: float,
|
||||
n_observations: int,
|
||||
same_sector: bool,
|
||||
d_network: int,
|
||||
pattern_confidence: float,
|
||||
) -> None:
|
||||
"""Property 14: Competitive LLR is clamped to [-1.25, 1.25].
|
||||
|
||||
For any source LLR, shrunk correlation (non-negative), graph distance
|
||||
(1-3), and pattern confidence in [0,1], the computed competitive LLR
|
||||
SHALL be in [-1.25, 1.25].
|
||||
"""
|
||||
rho_effective = compute_shrunk_correlation(
|
||||
rho_rolling=rho_rolling,
|
||||
n_observations=n_observations,
|
||||
same_sector=same_sector,
|
||||
)
|
||||
|
||||
# rho_effective should be non-negative per definition
|
||||
assert rho_effective >= 0.0, f"rho_effective={rho_effective} is negative"
|
||||
|
||||
llr_competitive = compute_competitive_llr(
|
||||
llr_source=llr_source,
|
||||
rho_effective=rho_effective,
|
||||
d_network=d_network,
|
||||
pattern_confidence=pattern_confidence,
|
||||
)
|
||||
|
||||
assert -1.25 <= llr_competitive <= 1.25, (
|
||||
f"Competitive LLR={llr_competitive} out of bounds [-1.25, 1.25] "
|
||||
f"for llr_source={llr_source}, rho_effective={rho_effective}, "
|
||||
f"d_network={d_network}, pattern_confidence={pattern_confidence}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Feature: math-core-v3-engine, Property 15: Graph attenuation is zero
|
||||
# beyond max distance
|
||||
# ---------------------------------------------------------------------------
|
||||
# **Validates: Requirements 10.4, 10.5**
|
||||
|
||||
|
||||
@settings(max_examples=100)
|
||||
@given(
|
||||
llr_source=llr_source_values,
|
||||
rho_effective=unit_floats,
|
||||
d_network=distances_beyond,
|
||||
pattern_confidence=unit_floats,
|
||||
)
|
||||
def test_property_15_zero_attenuation_beyond_max_distance(
|
||||
llr_source: float,
|
||||
rho_effective: float,
|
||||
d_network: int,
|
||||
pattern_confidence: float,
|
||||
) -> None:
|
||||
"""Property 15: Graph attenuation is zero beyond max distance.
|
||||
|
||||
For any inputs where graph distance > 3, the computed attenuation
|
||||
SHALL be 0.0, producing zero competitive LLR regardless of other
|
||||
parameters.
|
||||
"""
|
||||
llr_competitive = compute_competitive_llr(
|
||||
llr_source=llr_source,
|
||||
rho_effective=rho_effective,
|
||||
d_network=d_network,
|
||||
pattern_confidence=pattern_confidence,
|
||||
)
|
||||
|
||||
assert llr_competitive == 0.0, (
|
||||
f"Expected 0.0 for d_network={d_network} > 3, got {llr_competitive}"
|
||||
)
|
||||
Reference in New Issue
Block a user