Add task277 solver (266/266 PASS) - smallest CC recoloring
Browse files
medal-solvers/task277_solver_266.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Task 277 Solver — Smallest connected component recoloring (266/266 PASS).
|
| 2 |
+
|
| 3 |
+
Rule:
|
| 4 |
+
1. Input is 10x10 with separate shapes made of color 8 on background 0
|
| 5 |
+
2. Find 8-connected components of color 8
|
| 6 |
+
3. The component with the SMALLEST area (pixel count) gets recolored to 2
|
| 7 |
+
4. All other components get recolored to 1
|
| 8 |
+
|
| 9 |
+
ONNX viability:
|
| 10 |
+
- Requires connected-component detection (8-connected)
|
| 11 |
+
- On 10x10 grid, MaxPool-based CC detection needs ~20-30 iterations × ~5 nodes = 100-150 nodes
|
| 12 |
+
- Base: 56 nodes, profiled score 13.30
|
| 13 |
+
- Even with CC: ~150 nodes * 400 bytes = 60K memory + params → score ~14.1
|
| 14 |
+
- **POTENTIALLY VIABLE** — score 14.1 vs base 13.30 → gain +0.8
|
| 15 |
+
- But CC detection in ONNX is fragile and complex to build correctly
|
| 16 |
+
|
| 17 |
+
CC approach for ONNX:
|
| 18 |
+
1. Initialize label grid = nonzero_mask * (row*10 + col + 1) [unique labels]
|
| 19 |
+
2. Repeat 20 times: MaxPool(3x3) the label grid, masked by nonzero_mask
|
| 20 |
+
3. After convergence, each CC has the same max label
|
| 21 |
+
4. Count pixels per label → find minimum count label → mask it as color 2
|
| 22 |
+
5. Remaining → color 1
|
| 23 |
+
|
| 24 |
+
Challenge: Step 4 requires comparing per-label counts, which is hard without dynamic shapes.
|
| 25 |
+
Alternative: could potentially use the fact that shapes are always rectangular frames or solid blocks.
|
| 26 |
+
|
| 27 |
+
Status: Rule cracked (266/266), ONNX build pending — needs careful CC implementation.
|
| 28 |
+
"""
|
| 29 |
+
import numpy as np
|
| 30 |
+
import json
|
| 31 |
+
from scipy import ndimage
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def solve_277(inp_grid):
|
| 35 |
+
"""Smallest CC gets color 2, all others get color 1. 266/266 PASS."""
|
| 36 |
+
inp = np.array(inp_grid)
|
| 37 |
+
out = np.zeros_like(inp)
|
| 38 |
+
|
| 39 |
+
# Find 8-connected components of color 8
|
| 40 |
+
mask = (inp == 8).astype(int)
|
| 41 |
+
labeled, n = ndimage.label(mask, structure=np.ones((3, 3)))
|
| 42 |
+
|
| 43 |
+
if n == 0:
|
| 44 |
+
return out
|
| 45 |
+
|
| 46 |
+
# Find smallest component by area
|
| 47 |
+
areas = []
|
| 48 |
+
for i in range(1, n + 1):
|
| 49 |
+
areas.append(((labeled == i).sum(), i))
|
| 50 |
+
|
| 51 |
+
min_area = min(a for a, _ in areas)
|
| 52 |
+
|
| 53 |
+
for area, idx in areas:
|
| 54 |
+
component = (labeled == idx)
|
| 55 |
+
if area == min_area:
|
| 56 |
+
out[component] = 2
|
| 57 |
+
else:
|
| 58 |
+
out[component] = 1
|
| 59 |
+
|
| 60 |
+
return out
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
if __name__ == '__main__':
|
| 64 |
+
from pathlib import Path
|
| 65 |
+
task_data = Path('/app/task-data')
|
| 66 |
+
if not task_data.exists():
|
| 67 |
+
task_data = Path(__file__).parent.parent / 'task-data'
|
| 68 |
+
with open(task_data / 'task277.json') as f:
|
| 69 |
+
data = json.load(f)
|
| 70 |
+
all_ex = data['train'] + data['test'] + data.get('arc-gen', [])
|
| 71 |
+
right = sum(1 for ex in all_ex if np.array_equal(solve_277(ex['input']), np.array(ex['output'])))
|
| 72 |
+
print(f'task277: {right}/{len(all_ex)} PASS')
|