Skip to content

Commit 6ae7c5b

Browse files
authored
Preserve probability digit bounds above Python's string limit (#763)
* fix(probability): avoid bounded integer string limits * fix(ci): format eval telemetry test signature Ruff format requires wrapping the long test function signature that blocked Lint & Format on this branch. Co-authored-by: morluto <morluto@users.noreply.github.com> --------- Co-authored-by: morluto <morluto@users.noreply.github.com>
1 parent bad5a78 commit 6ae7c5b

2 files changed

Lines changed: 58 additions & 6 deletions

File tree

src/jacobian/contracts/probability.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from pydantic import Field, StrictInt, model_validator
1010

11-
from jacobian.canonical import canonicalize_json
11+
from jacobian.canonical import canonicalize_json, format_canonical_integer
1212
from jacobian.contracts.exact import CanonicalInteger, CanonicalRational
1313
from jacobian.contracts.graph_isomorphism import SimpleUndirectedGraph
1414
from jacobian.contracts.results import ContractModel
@@ -36,8 +36,8 @@ def _require_bounded_fraction(
3636
label: str,
3737
) -> None:
3838
if (
39-
len(str(abs(value.numerator))) > max_digits
40-
or len(str(value.denominator)) > max_digits
39+
len(format_canonical_integer(abs(value.numerator))) > max_digits
40+
or len(format_canonical_integer(value.denominator)) > max_digits
4141
):
4242
raise ValueError(f"{label} exceeds the {max_digits}-digit bound")
4343

@@ -324,13 +324,25 @@ def require_bounded_fully_weighted_graph(self) -> Self:
324324
)
325325
probability_numerator_digits = sum(
326326
max(
327-
len(str(item.open_probability.as_fraction().numerator)),
328-
len(str((1 - item.open_probability.as_fraction()).numerator)),
327+
len(
328+
format_canonical_integer(
329+
item.open_probability.as_fraction().numerator
330+
)
331+
),
332+
len(
333+
format_canonical_integer(
334+
(1 - item.open_probability.as_fraction()).numerator
335+
)
336+
),
329337
)
330338
for item in self.edge_probabilities
331339
)
332340
probability_denominator_digits = sum(
333-
len(str(item.open_probability.as_fraction().denominator))
341+
len(
342+
format_canonical_integer(
343+
item.open_probability.as_fraction().denominator
344+
)
345+
)
334346
for item in self.edge_probabilities
335347
)
336348
maximum_state = {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from __future__ import annotations
2+
3+
import sys
4+
5+
import pytest
6+
from pydantic import ValidationError
7+
8+
from jacobian.contracts.probability import GraphReliabilityEdgeProbability
9+
10+
11+
@pytest.mark.parametrize(
12+
("num", "den"),
13+
(
14+
("1" * (sys.int_info.default_max_str_digits + 1), "1"),
15+
("1", "1" * (sys.int_info.default_max_str_digits + 1)),
16+
),
17+
ids=("numerator", "denominator"),
18+
)
19+
def test_large_probability_reports_the_contract_digit_bound(
20+
num: str,
21+
den: str,
22+
) -> None:
23+
previous_limit = sys.get_int_max_str_digits()
24+
sys.set_int_max_str_digits(sys.int_info.default_max_str_digits)
25+
try:
26+
with pytest.raises(
27+
ValidationError,
28+
match="graph reliability edge probability exceeds the 128-digit bound",
29+
):
30+
GraphReliabilityEdgeProbability.model_validate(
31+
{
32+
"edge": ["a", "b"],
33+
"open_probability": {
34+
"num": num,
35+
"den": den,
36+
},
37+
}
38+
)
39+
finally:
40+
sys.set_int_max_str_digits(previous_limit)

0 commit comments

Comments
 (0)