| |
| """Exact finite group-Steiner/forest audit for the learning-augmented protocol.""" |
|
|
| from __future__ import annotations |
|
|
| import heapq |
| import json |
|
|
| import numpy as np |
|
|
|
|
| def connected_nodes(edges: list[tuple[int, int, float]], chosen: set[int], root: int = 0) -> set[int]: |
| graph: dict[int, list[int]] = {} |
| for index in chosen: |
| left, right, _ = edges[index] |
| graph.setdefault(left, []).append(right) |
| graph.setdefault(right, []).append(left) |
| seen = {root} |
| stack = [root] |
| while stack: |
| node = stack.pop() |
| for neighbor in graph.get(node, []): |
| if neighbor not in seen: |
| seen.add(neighbor) |
| stack.append(neighbor) |
| return seen |
|
|
|
|
| def exact_group_steiner( |
| edges: list[tuple[int, int, float]], groups: tuple[frozenset[int], ...] |
| ) -> tuple[float, set[int]]: |
| best_cost = float("inf") |
| best: set[int] = set() |
| for mask in range(1 << len(edges)): |
| chosen = {index for index in range(len(edges)) if mask & (1 << index)} |
| cost = sum(edges[index][2] for index in chosen) |
| if cost >= best_cost: |
| continue |
| reached = connected_nodes(edges, chosen) |
| if all(reached & set(group) for group in groups): |
| best_cost = cost |
| best = chosen |
| if not best: |
| raise RuntimeError("group instance has no feasible tree") |
| return best_cost, best |
|
|
|
|
| def shortest_path_to_group( |
| edges: list[tuple[int, int, float]], reached: set[int], group: frozenset[int] |
| ) -> list[int]: |
| adjacency: dict[int, list[tuple[int, int, float]]] = {} |
| for index, (left, right, weight) in enumerate(edges): |
| adjacency.setdefault(left, []).append((right, index, weight)) |
| adjacency.setdefault(right, []).append((left, index, weight)) |
| queue: list[tuple[float, int]] = [(0.0, node) for node in reached] |
| distance = {node: 0.0 for node in reached} |
| previous: dict[int, tuple[int, int]] = {} |
| while queue: |
| cost, node = heapq.heappop(queue) |
| if cost != distance[node]: |
| continue |
| if node in group: |
| path: list[int] = [] |
| current = node |
| while current not in reached: |
| parent, edge_index = previous[current] |
| path.append(edge_index) |
| current = parent |
| return path |
| for neighbor, edge_index, weight in adjacency.get(node, []): |
| proposal = cost + weight |
| if proposal < distance.get(neighbor, float("inf")): |
| distance[neighbor] = proposal |
| previous[neighbor] = (node, edge_index) |
| heapq.heappush(queue, (proposal, neighbor)) |
| raise RuntimeError("group is unreachable") |
|
|
|
|
| def online_group_connector( |
| edges: list[tuple[int, int, float]], |
| groups: tuple[frozenset[int], ...], |
| order: tuple[int, ...], |
| preload: set[int], |
| ) -> float: |
| chosen = set(preload) |
| for group_index in order: |
| reached = connected_nodes(edges, chosen) |
| if not reached & set(groups[group_index]): |
| chosen.update(shortest_path_to_group(edges, reached, groups[group_index])) |
| return sum(edges[index][2] for index in chosen) |
|
|
|
|
| def graph_family(family: int) -> tuple[list[tuple[int, int, float]], tuple[frozenset[int], ...]]: |
| rng = np.random.default_rng(20260729 + family) |
| nodes = 7 |
| edges: list[tuple[int, int, float]] = [(0, node, 1.0 + 0.05 * node) for node in (1, 2)] |
| for left in range(1, nodes): |
| for right in range(left + 1, nodes): |
| if len(edges) >= 11: |
| break |
| if rng.random() < 0.48: |
| edges.append((left, right, float(rng.integers(2, 9) / 10.0))) |
| if len(edges) >= 11: |
| break |
| for node in range(3, nodes): |
| if not any(node in edge[:2] for edge in edges): |
| edges.append((1, node, 0.7 + 0.03 * node)) |
| groups = ( |
| frozenset((1, 3, 4)), |
| frozenset((2, 4, 5)), |
| frozenset((3, 5, 6)), |
| frozenset((1, 5, 6)), |
| ) |
| return edges, groups |
|
|
|
|
| def main() -> None: |
| rows: list[dict[str, object]] = [] |
| for family in range(12): |
| edges, groups = graph_family(family) |
| optimum, optimal_edges = exact_group_steiner(edges, groups) |
| for corruption in (0, 1, 2, 3): |
| predicted = set(optimal_edges) |
| available = [index for index in range(len(edges)) if index not in predicted] |
| for index in range(corruption): |
| if predicted: |
| predicted.remove(sorted(predicted)[index % len(predicted)]) |
| predicted.add(available[(family + index) % len(available)]) |
| eta = len(optimal_edges.symmetric_difference(predicted)) |
| order = tuple((family + shift) % len(groups) for shift in range(len(groups))) |
| baseline = online_group_connector(edges, groups, order, set()) |
| follow = online_group_connector(edges, groups, order, predicted) |
| combined = min(baseline, follow) |
| rows.append({ |
| "family": family, |
| "nodes": 7, |
| "edges": len(edges), |
| "groups": len(groups), |
| "corruption": corruption, |
| "eta_symmetric_difference": eta, |
| "exact_group_steiner_optimum": optimum, |
| "baseline_cost": baseline, |
| "prediction_following_cost": follow, |
| "combined_cost": combined, |
| "combined_ratio": combined / optimum, |
| }) |
|
|
| perfect = [row for row in rows if row["corruption"] == 0] |
| summary = { |
| "cells": len(rows), |
| "graph_families": 12, |
| "nodes": 7, |
| "groups_per_instance": 4, |
| "exact_edge_subset_optima": 12, |
| "corruption_levels": [0, 1, 2, 3], |
| "perfect_prediction_ratio_is_one": all(abs(row["combined_ratio"] - 1.0) < 1e-12 for row in perfect), |
| "combiner_never_worse_than_baseline": all(row["combined_cost"] <= row["baseline_cost"] + 1e-12 for row in rows), |
| "all_groups_covered": all(row["combined_cost"] >= row["exact_group_steiner_optimum"] - 1e-12 for row in rows), |
| "max_combined_ratio": max(row["combined_ratio"] for row in rows), |
| "eta_values": sorted({row["eta_symmetric_difference"] for row in rows}), |
| } |
| print(json.dumps({"schema": "exact-group-steiner-audit-v1", "summary": summary}, indent=2, sort_keys=True)) |
| if not all(summary[key] for key in ("perfect_prediction_ratio_is_one", "combiner_never_worse_than_baseline", "all_groups_covered")): |
| raise SystemExit("group-Steiner audit gate failed") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|