""" Coverage analysis: for each pair (n, target-class restriction), check whether every iso-class in the restriction is reachable as a level resolution of some triangulation on n vertices. """ import networkx as nx import time from level_cycles import all_level_resolutions from triangulation_gen import enumerate_all_triangulations def iso_class(G, reps): for i, r in enumerate(reps): if nx.is_isomorphic(G, r): return i return -1 def resolution_classes(G, reps): return {iso_class(Gp, reps) for Gp, _, _, _ in all_level_resolutions(G)} def min_degree(G): return min(d for _, d in G.degree()) def coverage_report(n, target_filter=None, source_filter=None): """ target_filter / source_filter: callables G -> bool, or None for "any". """ print(f"\n{'='*60}\nn = {n}\n{'='*60}") t0 = time.time() reps = enumerate_all_triangulations(n) print(f"Total iso-classes: {len(reps)}") if source_filter is None: sources = list(range(len(reps))) print(f"Sources: all {len(sources)}") else: sources = [i for i, G in enumerate(reps) if source_filter(G)] print(f"Sources (filtered): {len(sources)}") if target_filter is None: targets = set(range(len(reps))) else: targets = {i for i, G in enumerate(reps) if target_filter(G)} print(f"Targets: {len(targets)} iso-classes") for i in sorted(targets): deg = sorted((d for _, d in reps[i].degree()), reverse=True) print(f" T{i}: degree {deg}") reached, sources_per_target = set(), {i: [] for i in targets} for src_i in sources: prod = resolution_classes(reps[src_i], reps) & targets for p in prod: sources_per_target[p].append(src_i) reached |= prod print("\nCoverage:") for i in sorted(targets): sources_list = sources_per_target[i] status = "REACHED" if sources_list else "UNREACHABLE" s = ", ".join(f"T{j}" for j in sources_list[:6]) if len(sources_list) > 6: s += f", ... ({len(sources_list)} total)" elif not sources_list: s = "(none)" print(f" T{i}: {status} via {s}") uncov = targets - reached print(f"\nUncovered: {sorted(uncov)}") print(f"Time: {time.time()-t0:.1f}s") if __name__ == "__main__": # General coverage (any source, any target) for n in [6, 7]: coverage_report(n) # md3 sources -> md4 targets print("\n\n" + "#"*60) print("md3 sources -> md4 targets") print("#"*60) for n in [6, 7, 8]: coverage_report(n, target_filter=lambda G: min_degree(G) >= 4)