| import numpy as np |
| from .solver_core import tile_transform, fill_enclosed, Transform |
|
|
|
|
| |
| |
| |
|
|
| def tile_to_target_shifted(shift=(1, 1), tile_factor=3): |
| """Tile the input tile_factor×tile_factor times, then roll by shift.""" |
| def fn(phi): |
| h_in, w_in = phi.shape |
| out_shape = (h_in * tile_factor, w_in * tile_factor) |
| tiled = tile_transform(phi, out_shape) |
| tiled = np.roll(tiled, shift=shift, axis=(0, 1)) |
| return tiled |
| return Transform(fn, f"ShiftedTile_s{shift}_f{tile_factor}") |
|
|
|
|
| def FillEnclosedHarmonic(boundary_mask=None): |
| def fn(phi): |
| bm = (phi != 0) if boundary_mask is None else boundary_mask |
| return fill_enclosed(phi, bm) |
| return Transform(fn, "FillEnclosedHarmonic") |
|
|
|
|
| def Rotate(k=1): |
| def fn(phi): |
| return np.rot90(phi, k) |
| return Transform(fn, f"Rotate_{90 * k}") |
|
|
|
|
| def Reflect(axis='h'): |
| def fn(phi): |
| if axis == 'h': |
| return np.flipud(phi) |
| return np.fliplr(phi) |
| return Transform(fn, f"Reflect_{axis}") |
|
|
|
|
| def ColorMap(mapping): |
| def fn(phi): |
| out = phi.copy() |
| for k, v in mapping.items(): |
| out[phi == k] = v |
| return out |
| return Transform(fn, f"ColorMap_{mapping}") |
|
|
|
|
| |
| |
| |
|
|
| def KroneckerSelfSimilar(): |
| """output = kron((input != 0).astype(int), input) |
| |
| This is the exact transform for ARC task 007bbfb7 and the general |
| family of "use the input's own nonzero pattern as a meta‑layout |
| for placing copies of itself". Works for any 2‑color grid. |
| """ |
| def fn(phi): |
| mask = (phi != 0).astype(phi.dtype) |
| return np.kron(mask, phi) |
| return Transform(fn, "KroneckerSelfSimilar") |
|
|
|
|
| def KroneckerSelfSimilarInv(): |
| """output = kron(input, (input != 0).astype(int)) |
| |
| Mirror variant — identical result for symmetric inputs, differs |
| for asymmetric ones. |
| """ |
| def fn(phi): |
| mask = (phi != 0).astype(phi.dtype) |
| return np.kron(phi, mask) |
| return Transform(fn, "KroneckerSelfSimilarInv") |
|
|
|
|
| |
| |
| |
|
|
| def MirrorTileH(): |
| """Horizontal mirror tile: [abc] → [abc|cba]""" |
| def fn(phi): |
| return np.hstack([phi, np.fliplr(phi)]) |
| return Transform(fn, "MirrorTileH") |
|
|
|
|
| def MirrorTileV(): |
| """Vertical mirror tile: stack input then its vertical reflection.""" |
| def fn(phi): |
| return np.vstack([phi, np.flipud(phi)]) |
| return Transform(fn, "MirrorTileV") |
|
|
|
|
| def MirrorTile4Way(): |
| """Full kaleidoscope: 2×2 mirror tile (D4 reflections).""" |
| def fn(phi): |
| top = np.hstack([phi, np.fliplr(phi)]) |
| return np.vstack([top, np.flipud(top)]) |
| return Transform(fn, "MirrorTile4Way") |
|
|
|
|
| |
| |
| |
|
|
| def Upscale(k=2): |
| """Pixel‑repeat upscale: each pixel becomes a k×k block.""" |
| def fn(phi): |
| return np.kron(phi, np.ones((k, k), dtype=phi.dtype)) |
| return Transform(fn, f"Upscale_{k}x") |
|
|
|
|
| def Downscale(k=2): |
| """Downsample by taking every k‑th pixel (inverse of Upscale).""" |
| def fn(phi): |
| return phi[::k, ::k].copy() |
| return Transform(fn, f"Downscale_{k}x") |
|
|
|
|
| |
| |
| |
|
|
| def StackH(n=2): |
| """Tile horizontally n times: [A] → [A|A|...|A].""" |
| def fn(phi): |
| return np.tile(phi, (1, n)) |
| return Transform(fn, f"StackH_{n}") |
|
|
|
|
| def StackV(n=2): |
| """Tile vertically n times.""" |
| def fn(phi): |
| return np.tile(phi, (n, 1)) |
| return Transform(fn, f"StackV_{n}") |
|
|
|
|
| |
| |
| |
|
|
| def RetainColor(color): |
| """Keep only pixels of the given color; zero the rest.""" |
| def fn(phi): |
| out = np.zeros_like(phi) |
| out[phi == color] = color |
| return out |
| return Transform(fn, f"RetainColor_{color}") |
|
|
|
|
| def RemoveColor(color): |
| """Zero out all pixels of the given color.""" |
| def fn(phi): |
| out = phi.copy() |
| out[phi == color] = 0 |
| return out |
| return Transform(fn, f"RemoveColor_{color}") |
|
|
|
|
| def InvertColors(): |
| """Swap black (0) with the most common non‑zero color.""" |
| def fn(phi): |
| nonzero = phi[phi != 0] |
| if nonzero.size == 0: |
| return phi.copy() |
| from collections import Counter |
| top_color = Counter(nonzero.flatten().astype(int).tolist()).most_common(1)[0][0] |
| out = phi.copy() |
| mask_zero = (phi == 0) |
| mask_top = (phi == top_color) |
| out[mask_zero] = top_color |
| out[mask_top] = 0 |
| return out |
| return Transform(fn, "InvertColors") |
|
|
|
|
| |
| |
| |
|
|
| def GravityDown(): |
| """Non‑zero pixels fall to the bottom within each column.""" |
| def fn(phi): |
| out = np.zeros_like(phi) |
| h, w = phi.shape |
| for c in range(w): |
| col = phi[:, c] |
| nonzero = col[col != 0] |
| if nonzero.size > 0: |
| out[h - nonzero.size:, c] = nonzero |
| return out |
| return Transform(fn, "GravityDown") |
|
|
|
|
| def GravityUp(): |
| """Non‑zero pixels rise to the top within each column.""" |
| def fn(phi): |
| out = np.zeros_like(phi) |
| h, w = phi.shape |
| for c in range(w): |
| col = phi[:, c] |
| nonzero = col[col != 0] |
| if nonzero.size > 0: |
| out[:nonzero.size, c] = nonzero |
| return out |
| return Transform(fn, "GravityUp") |
|
|
|
|
| |
| |
| |
|
|
| def OverlayTransparent(background): |
| """Overlay: background pixels are replaced by foreground where foreground != 0.""" |
| bg = np.array(background, dtype=float) |
| def fn(phi): |
| out = bg.copy() |
| mask = (phi != 0) |
| if phi.shape != out.shape: |
| p = tile_transform(phi, out.shape) |
| m = (p != 0) |
| out[m] = p[m] |
| else: |
| out[mask] = phi[mask] |
| return out |
| return Transform(fn, "OverlayTransparent") |
|
|
|
|
| |
| |
| |
|
|
| def CropToContent(): |
| """Crop grid to bounding box of non‑zero content.""" |
| def fn(phi): |
| rows = np.any(phi != 0, axis=1) |
| cols = np.any(phi != 0, axis=0) |
| if not rows.any(): |
| return phi.copy() |
| rmin, rmax = np.where(rows)[0][[0, -1]] |
| cmin, cmax = np.where(cols)[0][[0, -1]] |
| return phi[rmin:rmax + 1, cmin:cmax + 1].copy() |
| return Transform(fn, "CropToContent") |
|
|
|
|
| def Transpose(): |
| """Matrix transpose.""" |
| def fn(phi): |
| return phi.T.copy() |
| return Transform(fn, "Transpose") |
|
|