FA-70266 / Map projection transforms / Open access
Affine geotransform inverse to pixel indices: negative index flooring · case 01
Points just outside the left or top edge are sampled from the first column or row.
ROOT CAUSE
int() truncates toward zero, so fractional indices in (-1, 0) become 0 and pass the bounds test.
VERIFIED REPAIR
At the negative index flooring step restore `c, r = math.floor(col), math.floor(row)`, leaving the rest of the model unchanged.
Unsuccessful approach: Rounding moves every point in the right half of a pixel into the next pixel.
Case contract
Input [gx, gy, gt, width, height] with a six-term affine gt: X = gt0 + col*gt1 + row*gt2, Y = gt3 + col*gt4 + row*gt5, where (gt0, gt3) is the outer corner of pixel (0, 0). Invert with the 2x2 determinant, take floor of the fractional column and row, and return [col, row] if inside [0, width) x [0, height), otherwise None (also None for a singular transform).
Why this case matters
Point sampling of rasters and click-to-pixel lookups rely on this inverse; half-pixel or sign mistakes read the neighbouring cell.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
gx, gy, gt, width, height = x
det = gt[1] * gt[5] - gt[2] * gt[4]
if det == 0:
return None
dx = gx - gt[0]
dy = gy - gt[3]
col = (gt[5] * dx - gt[2] * dy) / det
row = (-gt[4] * dx + gt[1] * dy) / det
c, r = int(col), int(row)
if c < 0 or r < 0 or c >= width or r >= height:
return None
return [c, r]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [501757.3953, 4199818.2948, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [58, 6]), ('control #1', [-171.8788, 83.4562, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [32, 26]), ('control #2', [1046.5787, 4959.4742, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [17, 23]), ('control #3', [515.0875, 607.7306, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [32, 35]), ('control #4', [76.2652, 18.2363, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [76, 18]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14])], [('control #2', [1046.5787, 4959.4742, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [17, 23]), ('control #4', [76.2652, 18.2363, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [76, 18]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #7', [1081.9041, 4971.5191, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [35, 21]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('boundary #24', [499999.0, 4199985.0, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None)], [('control #3', [515.0875, 607.7306, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [32, 35]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #8', [1154.1901, 783.547, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [94, 30]), ('control #9', [38.71, 51.2013, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [38, 51]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #11', [-179.8182, 72.2686, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [0, 70]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None)], [('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #11', [-179.8182, 72.2686, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [0, 70]), ('control #12', [1181.1787, 4910.1448, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [75, 60]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None), ('control #15', [500583.8568, 4199766.5953, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [19, 7]), ('boundary #24', [499999.0, 4199985.0, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None)], [('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #7', [1081.9041, 4971.5191, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [35, 21]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None), ('control #15', [500583.8568, 4199766.5953, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [19, 7]), ('control #16', [-155.0962, 71.5551, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [99, 73]), ('control #17', [1052.7736, 4892.5715, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [12, 56]), ('control #18', [1072.1342, 274.3213, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], None), ('control #19', [85.7339, 56.5251, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [85, 56])]]
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 |
|---|---|---|---|
| control #0 | [58, 6] | [58, 6] | Passed |
| control #1 | [32, 26] | [32, 26] | Passed |
| control #2 | [17, 23] | [17, 23] | Passed |
| control #3 | [32, 35] | [32, 35] | Passed |
| control #4 | [76, 18] | [76, 18] | Passed |
| control #5 | [20, 0] | None | Failed |
| control #6 | [97, 63] | [97, 63] | Passed |
| control #10 | [26, 14] | [26, 14] | Passed |
SHA-256 / 2eb2ecd38f0671d282f194b40b1b65b7da3a11bdb149d15a349b91cba2dc3490
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
gx, gy, gt, width, height = x
det = gt[1] * gt[5] - gt[2] * gt[4]
if det == 0:
return None
dx = gx - gt[0]
dy = gy - gt[3]
col = (gt[5] * dx - gt[2] * dy) / det
row = (-gt[4] * dx + gt[1] * dy) / det
c, r = round(col), round(row)
if c < 0 or r < 0 or c >= width or r >= height:
return None
return [c, r]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [501757.3953, 4199818.2948, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [58, 6]), ('control #1', [-171.8788, 83.4562, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [32, 26]), ('control #2', [1046.5787, 4959.4742, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [17, 23]), ('control #3', [515.0875, 607.7306, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [32, 35]), ('control #4', [76.2652, 18.2363, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [76, 18]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14])], [('control #2', [1046.5787, 4959.4742, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [17, 23]), ('control #4', [76.2652, 18.2363, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [76, 18]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #7', [1081.9041, 4971.5191, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [35, 21]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('boundary #24', [499999.0, 4199985.0, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None)], [('control #3', [515.0875, 607.7306, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [32, 35]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #8', [1154.1901, 783.547, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [94, 30]), ('control #9', [38.71, 51.2013, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [38, 51]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #11', [-179.8182, 72.2686, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [0, 70]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None)], [('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #11', [-179.8182, 72.2686, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [0, 70]), ('control #12', [1181.1787, 4910.1448, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [75, 60]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None), ('control #15', [500583.8568, 4199766.5953, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [19, 7]), ('boundary #24', [499999.0, 4199985.0, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None)], [('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #7', [1081.9041, 4971.5191, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [35, 21]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None), ('control #15', [500583.8568, 4199766.5953, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [19, 7]), ('control #16', [-155.0962, 71.5551, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [99, 73]), ('control #17', [1052.7736, 4892.5715, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [12, 56]), ('control #18', [1072.1342, 274.3213, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], None), ('control #19', [85.7339, 56.5251, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [85, 56])]]
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 |
|---|---|---|---|
| control #0 | [59, 6] | [58, 6] | Failed |
| control #1 | [32, 26] | [32, 26] | Passed |
| control #2 | [17, 24] | [17, 23] | Failed |
| control #3 | [32, 36] | [32, 35] | Failed |
| control #4 | [76, 18] | [76, 18] | Passed |
| control #5 | None | None | Passed |
| control #6 | [98, 63] | [97, 63] | Failed |
| control #10 | [26, 14] | [26, 14] | Passed |
SHA-256 / 2d0feb829d53e159a85249d69670c10f3ece0a6dbc18342e1a9a0023805d2768
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
gx, gy, gt, width, height = x
det = gt[1] * gt[5] - gt[2] * gt[4]
if det == 0:
return None
dx = gx - gt[0]
dy = gy - gt[3]
col = (gt[5] * dx - gt[2] * dy) / det
row = (-gt[4] * dx + gt[1] * dy) / det
c, r = math.floor(col), math.floor(row)
if c < 0 or r < 0 or c >= width or r >= height:
return None
return [c, r]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [501757.3953, 4199818.2948, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [58, 6]), ('control #1', [-171.8788, 83.4562, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [32, 26]), ('control #2', [1046.5787, 4959.4742, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [17, 23]), ('control #3', [515.0875, 607.7306, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [32, 35]), ('control #4', [76.2652, 18.2363, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [76, 18]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14])], [('control #2', [1046.5787, 4959.4742, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [17, 23]), ('control #4', [76.2652, 18.2363, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [76, 18]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #7', [1081.9041, 4971.5191, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [35, 21]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('boundary #24', [499999.0, 4199985.0, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None)], [('control #3', [515.0875, 607.7306, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [32, 35]), ('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #8', [1154.1901, 783.547, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [94, 30]), ('control #9', [38.71, 51.2013, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [38, 51]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #11', [-179.8182, 72.2686, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [0, 70]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None)], [('control #6', [-155.5787, 74.1746, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [97, 63]), ('control #10', [500787.7801, 4199579.3798, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [26, 14]), ('control #11', [-179.8182, 72.2686, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [0, 70]), ('control #12', [1181.1787, 4910.1448, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [75, 60]), ('control #13', [651.582, 912.3698, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], [37, 6]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None), ('control #15', [500583.8568, 4199766.5953, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [19, 7]), ('boundary #24', [499999.0, 4199985.0, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None)], [('control #5', [500628.6941, 4200027.3496, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], None), ('control #7', [1081.9041, 4971.5191, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [35, 21]), ('control #14', [43.3467, 82.4576, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], None), ('control #15', [500583.8568, 4199766.5953, [500000.0, 30.0, 0.0, 4200000.0, 0.0, -30.0], 100, 80], [19, 7]), ('control #16', [-155.0962, 71.5551, [-180.0, 0.25, 0.0, 90.0, 0.0, -0.25], 100, 80], [99, 73]), ('control #17', [1052.7736, 4892.5715, [1000.0, 2.0, 0.5, 5000.0, 0.4, -2.0], 100, 80], [12, 56]), ('control #18', [1072.1342, 274.3213, [300.0, 10.0, -3.0, 900.0, 2.0, -10.0], 100, 80], None), ('control #19', [85.7339, 56.5251, [0.0, 1.0, 0.0, 0.0, 0.0, 1.0], 100, 80], [85, 56])]]
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 |
|---|---|---|---|
| control #0 | [58, 6] | [58, 6] | Passed |
| control #1 | [32, 26] | [32, 26] | Passed |
| control #2 | [17, 23] | [17, 23] | Passed |
| control #3 | [32, 35] | [32, 35] | Passed |
| control #4 | [76, 18] | [76, 18] | Passed |
| control #5 | None | None | Passed |
| control #6 | [97, 63] | [97, 63] | Passed |
| control #10 | [26, 14] | [26, 14] | Passed |
SHA-256 / e53e37a32545334d47a803514422aedc5e0fca0aba46a2645fd7d6dee77c8ad6
Verification & scope
Stipulated deterministic toy contract on a bounded input domain; results are rounded as stated and no conformance with any published standard or library is claimed. 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:19.093615+00:00.
Case digest / d86b51bb8aac191a67d82a18ef99f6e017633087a992ef010d0b0680bc211567