FA-70361 / GIS polygon topology / Open access
Right-hand rule ring orientation enforcement: minimum ring size · case 01
Two-vertex closed "rings" pass validation.
ROOT CAUSE
The minimum ring size is 3 positions, admitting a closed segment [a, b, a].
VERIFIED REPAIR
At the minimum ring size step restore `len(ring) < 4 or`, leaving the rest of the model unchanged.
Unsuccessful approach: Using <= 4 rejects valid closed triangles.
Case contract
Input: a polygon as a list of rings (exterior first, then holes), each a list of [x, y] integer positions. Every ring must be closed (first == last) with at least 4 positions, else return None; an empty polygon is None. Exterior rings are made counter-clockwise and holes clockwise by twice-signed-area sign; a reversed ring keeps its start vertex. Zero-area rings are left untouched. Return the rewritten rings.
Why this case matters
GeoJSON writers and vector-tile encoders must emit exterior and hole rings with opposite orientation; renderers use it to decide which rings cut holes.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
rings = x
if not rings:
return None
out = []
for i, ring in enumerate(rings):
if len(ring) < 3 or ring[0] != ring[-1]:
return None
a2 = 0
for p, q in zip(ring, ring[1:]):
a2 += p[0] * q[1] - q[0] * p[1]
want_ccw = i == 0
if a2 != 0 and (a2 > 0) != want_ccw:
ring = [ring[0]] + ring[-2:0:-1] + [ring[0]]
out.append(ring)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [[[63, -23], [55, -40], [70, -48], [-53, -42], [-62, -56], [-88, -26], [56, 38], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [0, -10], [0, -4], [-4, -4], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #1', [[[53, -16], [50, -21], [-19, 64], [42, 44], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('control #2', [[[57, -46], [24, -78], [-55, 32], [-12, 64], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [0, -10], [0, -4], [-4, -4], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #3', [[[-15, -68], [-15, -80], [-18, -70], [-14, 65], [-8, 57], [53, 44], [50, 23], [-15, -68]]], [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]]), ('control #4', [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #5', [[[12, -61], [-50, 26], [-57, 29], [-56, 51], [-33, 50], [12, -61]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None)], [('control #3', [[[-15, -68], [-15, -80], [-18, -70], [-14, 65], [-8, 57], [53, 44], [50, 23], [-15, -68]]], [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]]), ('control #4', [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #5', [[[12, -61], [-50, 26], [-57, 29], [-56, 51], [-33, 50], [12, -61]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #6', [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]], [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]]), ('control #7', [[[46, -58], [-55, -48], [-69, -60], [-63, -6], [-75, -1], [64, 11], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[46, -58], [64, 11], [-75, -1], [-63, -6], [-69, -60], [-55, -48], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #8', [[[-19, -75], [-53, -81], [-65, -30], [91, 24], [-19, -75]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[-19, -75], [91, 24], [-65, -30], [-53, -81], [-19, -75]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('boundary #17', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]]), ('boundary #22', [[[0, 0], [9, 0], [9, 9], [0, 9], [0, 0]], [[1, 1], [1, 2], [1, 1]]], None)], [('control #6', [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]], [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]]), ('control #7', [[[46, -58], [-55, -48], [-69, -60], [-63, -6], [-75, -1], [64, 11], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[46, -58], [64, 11], [-75, -1], [-63, -6], [-69, -60], [-55, -48], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #8', [[[-19, -75], [-53, -81], [-65, -30], [91, 24], [-19, -75]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[-19, -75], [91, 24], [-65, -30], [-53, -81], [-19, -75]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #9', [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #10', [[[96, -2], [-10, -53], [-33, -60], [-57, -50], [-77, -40], [-90, -24], [-81, -5], [87, 6], [96, -2]]], [[[96, -2], [87, 6], [-81, -5], [-90, -24], [-77, -40], [-57, -50], [-33, -60], [-10, -53], [96, -2]]]), ('control #11', [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None), ('boundary #21', [[[0, 0], [4, 0], [4, 4], [0, 0]]], [[[0, 0], [4, 0], [4, 4], [0, 0]]])], [('control #9', [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #10', [[[96, -2], [-10, -53], [-33, -60], [-57, -50], [-77, -40], [-90, -24], [-81, -5], [87, 6], [96, -2]]], [[[96, -2], [87, 6], [-81, -5], [-90, -24], [-77, -40], [-57, -50], [-33, -60], [-10, -53], [96, -2]]]), ('control #11', [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #12', [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #13', [[[92, -1], [31, -67], [-68, -40], [-55, 70], [43, 69], [35, 70], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[92, -1], [35, 70], [43, 69], [-55, 70], [-68, -40], [31, -67], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('regression #14', [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #22', [[[0, 0], [9, 0], [9, 9], [0, 9], [0, 0]], [[1, 1], [1, 2], [1, 1]]], None)], [('control #12', [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #13', [[[92, -1], [31, -67], [-68, -40], [-55, 70], [43, 69], [35, 70], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[92, -1], [35, 70], [43, 69], [-55, 70], [-68, -40], [31, -67], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('regression #14', [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]]]), ('regression #15', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]], [[1, 6], [2, 6], [2, 8], [1, 8], [1, 6]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]], [[1, 6], [1, 8], [2, 8], [2, 6], [1, 6]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #17', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]]), ('boundary #18', [[[0, 0], [4, 0], [4, 4], [0, 4]]], None), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None)]]
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 | [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | Passed |
| control #1 | [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]] | [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]] | Passed |
| control #2 | [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | Passed |
| control #3 | [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]] | [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]] | Passed |
| control #4 | [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | Passed |
| control #5 | [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | Passed |
| boundary #16 | [[[0, 0], [5, 0], [10, 0], [0, 0]]] | [[[0, 0], [5, 0], [10, 0], [0, 0]]] | Passed |
| boundary #20 | [[[0, 0], [4, 0], [0, 0]]] | None | Failed |
SHA-256 / c4a58b07eb0cd56c43e14a6056592e71ecdc8985aa7acc5f025bd78bbd265ba3
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
rings = x
if not rings:
return None
out = []
for i, ring in enumerate(rings):
if len(ring) <= 4 or ring[0] != ring[-1]:
return None
a2 = 0
for p, q in zip(ring, ring[1:]):
a2 += p[0] * q[1] - q[0] * p[1]
want_ccw = i == 0
if a2 != 0 and (a2 > 0) != want_ccw:
ring = [ring[0]] + ring[-2:0:-1] + [ring[0]]
out.append(ring)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [[[63, -23], [55, -40], [70, -48], [-53, -42], [-62, -56], [-88, -26], [56, 38], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [0, -10], [0, -4], [-4, -4], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #1', [[[53, -16], [50, -21], [-19, 64], [42, 44], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('control #2', [[[57, -46], [24, -78], [-55, 32], [-12, 64], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [0, -10], [0, -4], [-4, -4], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #3', [[[-15, -68], [-15, -80], [-18, -70], [-14, 65], [-8, 57], [53, 44], [50, 23], [-15, -68]]], [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]]), ('control #4', [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #5', [[[12, -61], [-50, 26], [-57, 29], [-56, 51], [-33, 50], [12, -61]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None)], [('control #3', [[[-15, -68], [-15, -80], [-18, -70], [-14, 65], [-8, 57], [53, 44], [50, 23], [-15, -68]]], [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]]), ('control #4', [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #5', [[[12, -61], [-50, 26], [-57, 29], [-56, 51], [-33, 50], [12, -61]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #6', [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]], [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]]), ('control #7', [[[46, -58], [-55, -48], [-69, -60], [-63, -6], [-75, -1], [64, 11], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[46, -58], [64, 11], [-75, -1], [-63, -6], [-69, -60], [-55, -48], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #8', [[[-19, -75], [-53, -81], [-65, -30], [91, 24], [-19, -75]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[-19, -75], [91, 24], [-65, -30], [-53, -81], [-19, -75]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('boundary #17', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]]), ('boundary #22', [[[0, 0], [9, 0], [9, 9], [0, 9], [0, 0]], [[1, 1], [1, 2], [1, 1]]], None)], [('control #6', [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]], [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]]), ('control #7', [[[46, -58], [-55, -48], [-69, -60], [-63, -6], [-75, -1], [64, 11], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[46, -58], [64, 11], [-75, -1], [-63, -6], [-69, -60], [-55, -48], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #8', [[[-19, -75], [-53, -81], [-65, -30], [91, 24], [-19, -75]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[-19, -75], [91, 24], [-65, -30], [-53, -81], [-19, -75]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #9', [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #10', [[[96, -2], [-10, -53], [-33, -60], [-57, -50], [-77, -40], [-90, -24], [-81, -5], [87, 6], [96, -2]]], [[[96, -2], [87, 6], [-81, -5], [-90, -24], [-77, -40], [-57, -50], [-33, -60], [-10, -53], [96, -2]]]), ('control #11', [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None), ('boundary #21', [[[0, 0], [4, 0], [4, 4], [0, 0]]], [[[0, 0], [4, 0], [4, 4], [0, 0]]])], [('control #9', [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #10', [[[96, -2], [-10, -53], [-33, -60], [-57, -50], [-77, -40], [-90, -24], [-81, -5], [87, 6], [96, -2]]], [[[96, -2], [87, 6], [-81, -5], [-90, -24], [-77, -40], [-57, -50], [-33, -60], [-10, -53], [96, -2]]]), ('control #11', [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #12', [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #13', [[[92, -1], [31, -67], [-68, -40], [-55, 70], [43, 69], [35, 70], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[92, -1], [35, 70], [43, 69], [-55, 70], [-68, -40], [31, -67], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('regression #14', [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #22', [[[0, 0], [9, 0], [9, 9], [0, 9], [0, 0]], [[1, 1], [1, 2], [1, 1]]], None)], [('control #12', [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #13', [[[92, -1], [31, -67], [-68, -40], [-55, 70], [43, 69], [35, 70], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[92, -1], [35, 70], [43, 69], [-55, 70], [-68, -40], [31, -67], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('regression #14', [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]]]), ('regression #15', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]], [[1, 6], [2, 6], [2, 8], [1, 8], [1, 6]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]], [[1, 6], [1, 8], [2, 8], [2, 6], [1, 6]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #17', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]]), ('boundary #18', [[[0, 0], [4, 0], [4, 4], [0, 4]]], None), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None)]]
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 | [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | Passed |
| control #1 | [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]] | [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]] | Passed |
| control #2 | [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | Passed |
| control #3 | [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]] | [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]] | Passed |
| control #4 | [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | Passed |
| control #5 | [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | Passed |
| boundary #16 | None | [[[0, 0], [5, 0], [10, 0], [0, 0]]] | Failed |
| boundary #20 | None | None | Passed |
SHA-256 / ee02d9209bc6184bfb8949c08249044c9c6800bf9fc395ad930a51ce9dbee2a1
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
rings = x
if not rings:
return None
out = []
for i, ring in enumerate(rings):
if len(ring) < 4 or ring[0] != ring[-1]:
return None
a2 = 0
for p, q in zip(ring, ring[1:]):
a2 += p[0] * q[1] - q[0] * p[1]
want_ccw = i == 0
if a2 != 0 and (a2 > 0) != want_ccw:
ring = [ring[0]] + ring[-2:0:-1] + [ring[0]]
out.append(ring)
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [[[63, -23], [55, -40], [70, -48], [-53, -42], [-62, -56], [-88, -26], [56, 38], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [0, -10], [0, -4], [-4, -4], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #1', [[[53, -16], [50, -21], [-19, 64], [42, 44], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('control #2', [[[57, -46], [24, -78], [-55, 32], [-12, 64], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [0, -10], [0, -4], [-4, -4], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #3', [[[-15, -68], [-15, -80], [-18, -70], [-14, 65], [-8, 57], [53, 44], [50, 23], [-15, -68]]], [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]]), ('control #4', [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #5', [[[12, -61], [-50, 26], [-57, 29], [-56, 51], [-33, 50], [12, -61]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None)], [('control #3', [[[-15, -68], [-15, -80], [-18, -70], [-14, 65], [-8, 57], [53, 44], [50, 23], [-15, -68]]], [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]]), ('control #4', [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #5', [[[12, -61], [-50, 26], [-57, 29], [-56, 51], [-33, 50], [12, -61]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #6', [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]], [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]]), ('control #7', [[[46, -58], [-55, -48], [-69, -60], [-63, -6], [-75, -1], [64, 11], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[46, -58], [64, 11], [-75, -1], [-63, -6], [-69, -60], [-55, -48], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #8', [[[-19, -75], [-53, -81], [-65, -30], [91, 24], [-19, -75]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[-19, -75], [91, 24], [-65, -30], [-53, -81], [-19, -75]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('boundary #17', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]]), ('boundary #22', [[[0, 0], [9, 0], [9, 9], [0, 9], [0, 0]], [[1, 1], [1, 2], [1, 1]]], None)], [('control #6', [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]], [[[-58, 10], [-59, 11], [-61, -9], [58, -67], [92, -23], [-58, 10]]]), ('control #7', [[[46, -58], [-55, -48], [-69, -60], [-63, -6], [-75, -1], [64, 11], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[46, -58], [64, 11], [-75, -1], [-63, -6], [-69, -60], [-55, -48], [46, -58]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #8', [[[-19, -75], [-53, -81], [-65, -30], [91, 24], [-19, -75]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]]], [[[-19, -75], [91, 24], [-65, -30], [-53, -81], [-19, -75]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #9', [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #10', [[[96, -2], [-10, -53], [-33, -60], [-57, -50], [-77, -40], [-90, -24], [-81, -5], [87, 6], [96, -2]]], [[[96, -2], [87, 6], [-81, -5], [-90, -24], [-77, -40], [-57, -50], [-33, -60], [-10, -53], [96, -2]]]), ('control #11', [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None), ('boundary #21', [[[0, 0], [4, 0], [4, 4], [0, 0]]], [[[0, 0], [4, 0], [4, 4], [0, 0]]])], [('control #9', [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [6, -10], [6, -4], [2, -4], [2, -10]]], [[[76, 35], [-31, 78], [-27, 53], [15, -82], [55, -64], [59, -16], [53, -4], [76, 35]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #10', [[[96, -2], [-10, -53], [-33, -60], [-57, -50], [-77, -40], [-90, -24], [-81, -5], [87, 6], [96, -2]]], [[[96, -2], [87, 6], [-81, -5], [-90, -24], [-77, -40], [-57, -50], [-33, -60], [-10, -53], [96, -2]]]), ('control #11', [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-6, -10], [-6, -4], [-10, -4], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]], [[[-33, 44], [-59, 30], [-32, -51], [-3, -69], [1, -82], [39, -42], [72, -45], [72, -15], [-33, 44]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]]), ('control #12', [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #13', [[[92, -1], [31, -67], [-68, -40], [-55, 70], [43, 69], [35, 70], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[92, -1], [35, 70], [43, 69], [-55, 70], [-68, -40], [31, -67], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('regression #14', [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #22', [[[0, 0], [9, 0], [9, 9], [0, 9], [0, 0]], [[1, 1], [1, 2], [1, 1]]], None)], [('control #12', [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]], [[[89, 9], [-81, 16], [39, -38], [71, -54], [61, -56], [89, 9]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]]), ('control #13', [[[92, -1], [31, -67], [-68, -40], [-55, 70], [43, 69], [35, 70], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]], [[[92, -1], [35, 70], [43, 69], [-55, 70], [-68, -40], [31, -67], [92, -1]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]]), ('regression #14', [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], [[2, 2], [4, 2], [4, 4], [2, 4], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]]]), ('regression #15', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [7, 5], [7, 7], [5, 7], [5, 5]], [[1, 6], [2, 6], [2, 8], [1, 8], [1, 6]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[2, 2], [2, 4], [4, 4], [4, 2], [2, 2]], [[5, 5], [5, 7], [7, 7], [7, 5], [5, 5]], [[1, 6], [1, 8], [2, 8], [2, 6], [1, 6]]]), ('boundary #16', [[[0, 0], [5, 0], [10, 0], [0, 0]]], [[[0, 0], [5, 0], [10, 0], [0, 0]]]), ('boundary #17', [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]], [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], [[1, 1], [3, 3], [5, 5], [1, 1]]]), ('boundary #18', [[[0, 0], [4, 0], [4, 4], [0, 4]]], None), ('boundary #20', [[[0, 0], [4, 0], [0, 0]]], None)]]
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 | [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | [[[63, -23], [56, 38], [-88, -26], [-62, -56], [-53, -42], [70, -48], [55, -40], [63, -23]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | Passed |
| control #1 | [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]] | [[[53, -16], [42, 44], [-19, 64], [50, -21], [53, -16]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]]] | Passed |
| control #2 | [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | [[[57, -46], [-12, 64], [-55, 32], [24, -78], [57, -46]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]], [[-4, -10], [-4, -4], [0, -4], [0, -10], [-4, -10]], [[2, -10], [2, -4], [6, -4], [6, -10], [2, -10]]] | Passed |
| control #3 | [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]] | [[[-15, -68], [50, 23], [53, 44], [-8, 57], [-14, 65], [-18, -70], [-15, -80], [-15, -68]]] | Passed |
| control #4 | [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | [[[69, 12], [-70, 38], [-68, -6], [-66, -30], [11, -70], [34, -72], [36, -68], [63, -28], [69, 12]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | Passed |
| control #5 | [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | [[[12, -61], [-33, 50], [-56, 51], [-57, 29], [-50, 26], [12, -61]], [[-10, -10], [-10, -4], [-6, -4], [-6, -10], [-10, -10]]] | Passed |
| boundary #16 | [[[0, 0], [5, 0], [10, 0], [0, 0]]] | [[[0, 0], [5, 0], [10, 0], [0, 0]]] | Passed |
| boundary #20 | None | None | Passed |
SHA-256 / 966f06055c7fdedbf7fe56416343eab31b9f5350ebf22d3e7bb4f4754b3177f8
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:20.046570+00:00.
Case digest / 1d9f80699b46ef5d6e76bd4b5c5aab0165cec03c239dc32fb537ed0948066473