FA-71496 / Seismic magnitude estimation / Open access
Aki maximum-likelihood b-value: binning correction · case 01
b-values are systematically too high for binned catalogues.
ROOT CAUSE
The half-bin (Utsu) correction is omitted.
VERIFIED REPAIR
Subtract dM/2 from Mc.
Unsuccessful approach: Adding half a bin shifts the correction the wrong way.
Case contract
Magnitudes, completeness and bin width in tenths. Use events with M >= Mc; fewer than 2 returns None. b = log10(e) / (mean(M) - (Mc - dM/2)); non-positive denominator returns None. Return [b rounded 0.001, n, sigma = b/sqrt(n) rounded 0.001].
Why this case matters
Gutenberg-Richter b-values feed hazard rates and foreshock studies.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(mags_x10, mc_x10, dm_x10):
sel = [m for m in mags_x10 if m >= mc_x10]
n = len(sel)
if n < 2:
return None
mean = sum(sel) / n / 10.0
denom = mean - (mc_x10) / 10.0
if denom <= 0:
return None
b = math.log10(math.e) / denom
return [round(b, 3), n, round(b / math.sqrt(n), 3)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['catalogue 0', [[10, 41, 21, 20, 12], 20, 1], [0.554, 3, 0.32]], ['catalogue 1', [[18, 21, 15, 10, 25, 41, 34, 20, 20, 34, 30], 15, 1], [0.384, 10, 0.122]], ['catalogue 2', [[25, 25, 22], 15, 1], [0.457, 3, 0.264]], ['catalogue 3', [[15, 15, 25, 12, 22, 34, 20, 25], 15, 1], [0.558, 7, 0.211]], ['catalogue 4', [[25, 41, 25, 15, 25, 25, 30], 15, 1], [0.36, 7, 0.136]], ['catalogue 5', [[30, 12], 20, 1], None], ['catalogue 6', [[22, 25, 10], 15, 1], [0.483, 2, 0.341]], ['catalogue 7', [[34], 20, 1], None]], [['catalogue 3', [[15, 15, 25, 12, 22, 34, 20, 25], 15, 1], [0.558, 7, 0.211]], ['catalogue 7', [[34], 20, 1], None], ['catalogue 8', [[25, 25, 18, 15, 34], 15, 1], [0.488, 5, 0.218]], ['catalogue 9', [[34, 15, 20, 12, 15], 20, 1], [0.579, 2, 0.409]], ['catalogue 10', [[22, 21, 25, 30, 20, 15, 22], 15, 1], [0.568, 7, 0.215]], ['catalogue 11', [[30, 21, 25], 20, 1], [0.745, 3, 0.43]], ['catalogue 12', [[25, 15, 18, 25, 22, 15, 20, 12], 20, 1], [1.241, 4, 0.62]], ['catalogue 13', [[34, 20, 12, 18, 20, 15, 25, 25, 41], 20, 1], [0.543, 6, 0.222]]], [['catalogue 8', [[25, 25, 18, 15, 34], 15, 1], [0.488, 5, 0.218]], ['catalogue 13', [[34, 20, 12, 18, 20, 15, 25, 25, 41], 20, 1], [0.543, 6, 0.222]], ['catalogue 14', [[15], 15, 1], None], ['catalogue 15', [[20, 12, 25, 25, 22, 25, 20, 21, 30, 10, 41, 25], 15, 1], [0.398, 10, 0.126]], ['catalogue 16', [[10, 15, 20, 22], 20, 1], [2.895, 2, 2.047]], ['catalogue 17', [[22, 10, 20, 18, 25, 10, 15], 20, 1], [1.533, 3, 0.885]], ['catalogue 18', [[22, 34, 20, 18], 15, 1], [0.483, 4, 0.241]], ['catalogue 19', [[20, 41, 25, 30], 15, 1], [0.3, 4, 0.15]]], [['catalogue 11', [[30, 21, 25], 20, 1], [0.745, 3, 0.43]], ['catalogue 19', [[20, 41, 25, 30], 15, 1], [0.3, 4, 0.15]], ['catalogue 21', [[20], 15, 1], None], ['catalogue 22', [[15, 25, 15, 21, 22, 41, 18, 20, 10, 10], 15, 1], [0.57, 8, 0.201]], ['catalogue 23', [[21, 34, 18], 20, 1], [0.543, 2, 0.384]], ['catalogue 24', [[20], 20, 1], None], ['catalogue 25', [[25, 34, 34, 20, 12], 20, 1], [0.496, 4, 0.248]], ['catalogue 26', [[25, 18, 25, 10, 10, 41, 20, 12, 34, 25], 15, 1], [0.351, 7, 0.133]]], [['catalogue 15', [[20, 12, 25, 25, 22, 25, 20, 21, 30, 10, 41, 25], 15, 1], [0.398, 10, 0.126]], ['catalogue 26', [[25, 18, 25, 10, 10, 41, 20, 12, 34, 25], 15, 1], [0.351, 7, 0.133]], ['catalogue 28', [[22, 18, 21, 25, 20, 15], 15, 1], [0.766, 6, 0.313]], ['catalogue 29', [[12, 25, 15, 20, 22, 41], 15, 1], [0.43, 5, 0.192]], ['catalogue 30', [[22], 20, 1], None], ['catalogue 31', [[10, 18, 22, 41, 30, 18, 41, 20, 25, 10, 22, 34], 15, 1], [0.345, 10, 0.109]], ['catalogue 32', [[20, 20, 25], 15, 1], [0.606, 3, 0.35]], ['catalogue 33', [[34, 18, 15, 12, 25, 34, 21, 30, 15, 41], 15, 1], [0.381, 9, 0.127]]]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| catalogue 0 | [0.592, 3, 0.342] | [0.554, 3, 0.32] | Failed |
| catalogue 1 | [0.402, 10, 0.127] | [0.384, 10, 0.122] | Failed |
| catalogue 2 | [0.483, 3, 0.279] | [0.457, 3, 0.264] | Failed |
| catalogue 3 | [0.596, 7, 0.225] | [0.558, 7, 0.211] | Failed |
| catalogue 4 | [0.375, 7, 0.142] | [0.36, 7, 0.136] | Failed |
| catalogue 5 | None | None | Passed |
| catalogue 6 | [0.511, 2, 0.361] | [0.483, 2, 0.341] | Failed |
| catalogue 7 | None | None | Passed |
SHA-256 / 8fc1688715dfc2d5f1ee71bb5e91d7f92e10e4357ae8770dfa97568fb6429135
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(mags_x10, mc_x10, dm_x10):
sel = [m for m in mags_x10 if m >= mc_x10]
n = len(sel)
if n < 2:
return None
mean = sum(sel) / n / 10.0
denom = mean - (mc_x10 + dm_x10 / 2.0) / 10.0
if denom <= 0:
return None
b = math.log10(math.e) / denom
return [round(b, 3), n, round(b / math.sqrt(n), 3)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['catalogue 0', [[10, 41, 21, 20, 12], 20, 1], [0.554, 3, 0.32]], ['catalogue 1', [[18, 21, 15, 10, 25, 41, 34, 20, 20, 34, 30], 15, 1], [0.384, 10, 0.122]], ['catalogue 2', [[25, 25, 22], 15, 1], [0.457, 3, 0.264]], ['catalogue 3', [[15, 15, 25, 12, 22, 34, 20, 25], 15, 1], [0.558, 7, 0.211]], ['catalogue 4', [[25, 41, 25, 15, 25, 25, 30], 15, 1], [0.36, 7, 0.136]], ['catalogue 5', [[30, 12], 20, 1], None], ['catalogue 6', [[22, 25, 10], 15, 1], [0.483, 2, 0.341]], ['catalogue 7', [[34], 20, 1], None]], [['catalogue 3', [[15, 15, 25, 12, 22, 34, 20, 25], 15, 1], [0.558, 7, 0.211]], ['catalogue 7', [[34], 20, 1], None], ['catalogue 8', [[25, 25, 18, 15, 34], 15, 1], [0.488, 5, 0.218]], ['catalogue 9', [[34, 15, 20, 12, 15], 20, 1], [0.579, 2, 0.409]], ['catalogue 10', [[22, 21, 25, 30, 20, 15, 22], 15, 1], [0.568, 7, 0.215]], ['catalogue 11', [[30, 21, 25], 20, 1], [0.745, 3, 0.43]], ['catalogue 12', [[25, 15, 18, 25, 22, 15, 20, 12], 20, 1], [1.241, 4, 0.62]], ['catalogue 13', [[34, 20, 12, 18, 20, 15, 25, 25, 41], 20, 1], [0.543, 6, 0.222]]], [['catalogue 8', [[25, 25, 18, 15, 34], 15, 1], [0.488, 5, 0.218]], ['catalogue 13', [[34, 20, 12, 18, 20, 15, 25, 25, 41], 20, 1], [0.543, 6, 0.222]], ['catalogue 14', [[15], 15, 1], None], ['catalogue 15', [[20, 12, 25, 25, 22, 25, 20, 21, 30, 10, 41, 25], 15, 1], [0.398, 10, 0.126]], ['catalogue 16', [[10, 15, 20, 22], 20, 1], [2.895, 2, 2.047]], ['catalogue 17', [[22, 10, 20, 18, 25, 10, 15], 20, 1], [1.533, 3, 0.885]], ['catalogue 18', [[22, 34, 20, 18], 15, 1], [0.483, 4, 0.241]], ['catalogue 19', [[20, 41, 25, 30], 15, 1], [0.3, 4, 0.15]]], [['catalogue 11', [[30, 21, 25], 20, 1], [0.745, 3, 0.43]], ['catalogue 19', [[20, 41, 25, 30], 15, 1], [0.3, 4, 0.15]], ['catalogue 21', [[20], 15, 1], None], ['catalogue 22', [[15, 25, 15, 21, 22, 41, 18, 20, 10, 10], 15, 1], [0.57, 8, 0.201]], ['catalogue 23', [[21, 34, 18], 20, 1], [0.543, 2, 0.384]], ['catalogue 24', [[20], 20, 1], None], ['catalogue 25', [[25, 34, 34, 20, 12], 20, 1], [0.496, 4, 0.248]], ['catalogue 26', [[25, 18, 25, 10, 10, 41, 20, 12, 34, 25], 15, 1], [0.351, 7, 0.133]]], [['catalogue 15', [[20, 12, 25, 25, 22, 25, 20, 21, 30, 10, 41, 25], 15, 1], [0.398, 10, 0.126]], ['catalogue 26', [[25, 18, 25, 10, 10, 41, 20, 12, 34, 25], 15, 1], [0.351, 7, 0.133]], ['catalogue 28', [[22, 18, 21, 25, 20, 15], 15, 1], [0.766, 6, 0.313]], ['catalogue 29', [[12, 25, 15, 20, 22, 41], 15, 1], [0.43, 5, 0.192]], ['catalogue 30', [[22], 20, 1], None], ['catalogue 31', [[10, 18, 22, 41, 30, 18, 41, 20, 25, 10, 22, 34], 15, 1], [0.345, 10, 0.109]], ['catalogue 32', [[20, 20, 25], 15, 1], [0.606, 3, 0.35]], ['catalogue 33', [[34, 18, 15, 12, 25, 34, 21, 30, 15, 41], 15, 1], [0.381, 9, 0.127]]]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| catalogue 0 | [0.636, 3, 0.367] | [0.554, 3, 0.32] | Failed |
| catalogue 1 | [0.422, 10, 0.133] | [0.384, 10, 0.122] | Failed |
| catalogue 2 | [0.511, 3, 0.295] | [0.457, 3, 0.264] | Failed |
| catalogue 3 | [0.64, 7, 0.242] | [0.558, 7, 0.211] | Failed |
| catalogue 4 | [0.392, 7, 0.148] | [0.36, 7, 0.136] | Failed |
| catalogue 5 | None | None | Passed |
| catalogue 6 | [0.543, 2, 0.384] | [0.483, 2, 0.341] | Failed |
| catalogue 7 | None | None | Passed |
SHA-256 / f4e1ff4c7984059dc9bcbc4272881ed27c080b8fc63fec5f332a8db1973335e9
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(mags_x10, mc_x10, dm_x10):
sel = [m for m in mags_x10 if m >= mc_x10]
n = len(sel)
if n < 2:
return None
mean = sum(sel) / n / 10.0
denom = mean - (mc_x10 - dm_x10 / 2.0) / 10.0
if denom <= 0:
return None
b = math.log10(math.e) / denom
return [round(b, 3), n, round(b / math.sqrt(n), 3)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['catalogue 0', [[10, 41, 21, 20, 12], 20, 1], [0.554, 3, 0.32]], ['catalogue 1', [[18, 21, 15, 10, 25, 41, 34, 20, 20, 34, 30], 15, 1], [0.384, 10, 0.122]], ['catalogue 2', [[25, 25, 22], 15, 1], [0.457, 3, 0.264]], ['catalogue 3', [[15, 15, 25, 12, 22, 34, 20, 25], 15, 1], [0.558, 7, 0.211]], ['catalogue 4', [[25, 41, 25, 15, 25, 25, 30], 15, 1], [0.36, 7, 0.136]], ['catalogue 5', [[30, 12], 20, 1], None], ['catalogue 6', [[22, 25, 10], 15, 1], [0.483, 2, 0.341]], ['catalogue 7', [[34], 20, 1], None]], [['catalogue 3', [[15, 15, 25, 12, 22, 34, 20, 25], 15, 1], [0.558, 7, 0.211]], ['catalogue 7', [[34], 20, 1], None], ['catalogue 8', [[25, 25, 18, 15, 34], 15, 1], [0.488, 5, 0.218]], ['catalogue 9', [[34, 15, 20, 12, 15], 20, 1], [0.579, 2, 0.409]], ['catalogue 10', [[22, 21, 25, 30, 20, 15, 22], 15, 1], [0.568, 7, 0.215]], ['catalogue 11', [[30, 21, 25], 20, 1], [0.745, 3, 0.43]], ['catalogue 12', [[25, 15, 18, 25, 22, 15, 20, 12], 20, 1], [1.241, 4, 0.62]], ['catalogue 13', [[34, 20, 12, 18, 20, 15, 25, 25, 41], 20, 1], [0.543, 6, 0.222]]], [['catalogue 8', [[25, 25, 18, 15, 34], 15, 1], [0.488, 5, 0.218]], ['catalogue 13', [[34, 20, 12, 18, 20, 15, 25, 25, 41], 20, 1], [0.543, 6, 0.222]], ['catalogue 14', [[15], 15, 1], None], ['catalogue 15', [[20, 12, 25, 25, 22, 25, 20, 21, 30, 10, 41, 25], 15, 1], [0.398, 10, 0.126]], ['catalogue 16', [[10, 15, 20, 22], 20, 1], [2.895, 2, 2.047]], ['catalogue 17', [[22, 10, 20, 18, 25, 10, 15], 20, 1], [1.533, 3, 0.885]], ['catalogue 18', [[22, 34, 20, 18], 15, 1], [0.483, 4, 0.241]], ['catalogue 19', [[20, 41, 25, 30], 15, 1], [0.3, 4, 0.15]]], [['catalogue 11', [[30, 21, 25], 20, 1], [0.745, 3, 0.43]], ['catalogue 19', [[20, 41, 25, 30], 15, 1], [0.3, 4, 0.15]], ['catalogue 21', [[20], 15, 1], None], ['catalogue 22', [[15, 25, 15, 21, 22, 41, 18, 20, 10, 10], 15, 1], [0.57, 8, 0.201]], ['catalogue 23', [[21, 34, 18], 20, 1], [0.543, 2, 0.384]], ['catalogue 24', [[20], 20, 1], None], ['catalogue 25', [[25, 34, 34, 20, 12], 20, 1], [0.496, 4, 0.248]], ['catalogue 26', [[25, 18, 25, 10, 10, 41, 20, 12, 34, 25], 15, 1], [0.351, 7, 0.133]]], [['catalogue 15', [[20, 12, 25, 25, 22, 25, 20, 21, 30, 10, 41, 25], 15, 1], [0.398, 10, 0.126]], ['catalogue 26', [[25, 18, 25, 10, 10, 41, 20, 12, 34, 25], 15, 1], [0.351, 7, 0.133]], ['catalogue 28', [[22, 18, 21, 25, 20, 15], 15, 1], [0.766, 6, 0.313]], ['catalogue 29', [[12, 25, 15, 20, 22, 41], 15, 1], [0.43, 5, 0.192]], ['catalogue 30', [[22], 20, 1], None], ['catalogue 31', [[10, 18, 22, 41, 30, 18, 41, 20, 25, 10, 22, 34], 15, 1], [0.345, 10, 0.109]], ['catalogue 32', [[20, 20, 25], 15, 1], [0.606, 3, 0.35]], ['catalogue 33', [[34, 18, 15, 12, 25, 34, 21, 30, 15, 41], 15, 1], [0.381, 9, 0.127]]]]
for label, args, expected in fixtures[N - 1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| catalogue 0 | [0.554, 3, 0.32] | [0.554, 3, 0.32] | Passed |
| catalogue 1 | [0.384, 10, 0.122] | [0.384, 10, 0.122] | Passed |
| catalogue 2 | [0.457, 3, 0.264] | [0.457, 3, 0.264] | Passed |
| catalogue 3 | [0.558, 7, 0.211] | [0.558, 7, 0.211] | Passed |
| catalogue 4 | [0.36, 7, 0.136] | [0.36, 7, 0.136] | Passed |
| catalogue 5 | None | None | Passed |
| catalogue 6 | [0.483, 2, 0.341] | [0.483, 2, 0.341] | Passed |
| catalogue 7 | None | None | Passed |
SHA-256 / 53c3d2526b108a3e4f9a6b27d90d960deb90d18c53d9fa296b21490b8fa1fa18
Verification & scope
Stipulated deterministic teaching model of a seismological magnitude procedure; constants and tables are fixed by the contract and no claim of agency or standards conformance is made. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:48:30.165689+00:00.
Case digest / 643b413679fc055d856cc3a1bf20d45654b2bb6c4e2b62625eb768c6634c4dc8