"""Original small binary-grid 4/8 components with independent boolean closure oracle."""
from collections import deque
from itertools import product
import json

def components(mask,connectivity):
 if type(connectivity)!=int or connectivity not in [4,8]:raise ValueError('4 or 8 only')
 if not isinstance(mask,list) or not 1<=len(mask)<=6 or any(not isinstance(r,list) or not 1<=len(r)<=6 for r in mask) or len({len(r) for r in mask})!=1 or any(type(v)!=int or v not in [0,1] for r in mask for v in r):raise ValueError('rectangular binary int grid max6x6;bool rejected')
 h,w=len(mask),len(mask[0]);seen=set();groups=[];labels=[[0]*w for _ in mask]
 offsets=[(dr,dc) for dr,dc in product([-1,0,1],repeat=2) if (dr or dc) and (connectivity==8 or abs(dr)+abs(dc)==1)]
 assert all((-dr,-dc) in offsets for dr,dc in offsets)
 for r,c in product(range(h),range(w)):
  if mask[r][c] and (r,c) not in seen:
   q=deque([(r,c)]);seen.add((r,c));group=[]
   while q:
    a,b=q.popleft();group.append((a,b));labels[a][b]=len(groups)+1
    for dr,dc in offsets:
     p=(a+dr,b+dc)
     if 0<=p[0]<h and 0<=p[1]<w and mask[p[0]][p[1]] and p not in seen:seen.add(p);q.append(p)
   groups.append(sorted(group))
 return {'labels':labels,'partition':sorted(groups),'size_bbox':[{'size':len(g),'bbox_half_open':[min(p[0] for p in g),min(p[1] for p in g),max(p[0] for p in g)+1,max(p[1] for p in g)+1]} for g in groups]}
def closure(mask,k):
 pts=[(r,c) for r in range(len(mask)) for c in range(len(mask[0])) if mask[r][c]];n=len(pts)
 reach=[[max(abs(a[0]-b[0]),abs(a[1]-b[1]))<=1 if k==8 else abs(a[0]-b[0])+abs(a[1]-b[1])<=1 for b in pts] for a in pts]
 for m in range(n):
  for i in range(n):
   for j in range(n):reach[i][j]=reach[i][j] or (reach[i][m] and reach[m][j])
 return sorted({tuple(pts[j] for j in range(n) if reach[i][j]) for i in range(n)})
def demo():
 mask=[[1,0,1],[0,1,0],[1,0,1]];four=components(mask,4);eight=components(mask,8);assert len(four['partition'])==5 and len(eight['partition'])==1
 checks=0
 for bits in product([0,1],repeat=9):
  grid=[list(bits[i:i+3]) for i in [0,3,6]]
  for k in [4,8]:
   got=components(grid,k);assert [tuple(g) for g in got['partition']]==closure(grid,k);checks+=1
 for grid in [[[0,0],[0,0]],[[1,1],[1,1]],[[1]],[[1,0,0],[1,1,0]]]:
  for k in [4,8]:
   original=components(grid,k)['partition'];tr=components([list(r) for r in zip(*grid)],k)['partition'];assert sorted(sorted((b,a) for a,b in g) for g in original)==tr
 rejects=[]
 for label,grid,k in [('ragged',[[1],[1,0]],4),('nonbinary',[[2]],4),('bool',[[True]],4),('invalid_connectivity',[[1]],6),('bool_connectivity',[[1]],True),('empty',[],4),('budget',[[1]*7],4)]:
  try:components(grid,k)
  except ValueError:rejects.append(label)
  else:raise AssertionError(label)
 return {'mask':mask,'four_neighbor':four,'eight_neighbor':eight,'exhaustive_grid_connectivity_oracles':checks,'invalid_cases_rejected':rejects,'scope':'BFS versus independent boolean Floyd transitive closure; partitions, not numeric label identity. Only fixed symmetric4/8 neighborhoods, not custom structures/SciPy/model/object identification.'}
if __name__=='__main__':print(json.dumps(demo(),indent=2))
