|
228 | 228 | {"id":"br-r37-c1-wcdm3","title":"parity: Graph add_*/remove_* methods reject nx-canonical kwarg names (u_of_edge, node_for_adding, ebunch_to_add, n, nodes, ebunch)","description":"All four Graph classes use fnx-internal positional arg names that differ from nx's documented kwarg names. Drop-in callers using the documented kwarg form hit TypeError: G.add_edge(u_of_edge=0, v_of_edge=1), G.add_node(node_for_adding=0), G.add_weighted_edges_from(ebunch_to_add=...), G.remove_node(n=0), G.remove_nodes_from(nodes=...), G.remove_edges_from(ebunch=...). MultiGraph/MultiDiGraph add_edge takes u_for_edge/v_for_edge per nx. Fix: thin Python wrappers that accept the nx-canonical names and forward to the rust impl. Add parity tests asserting both kwarg-form calls work and inspect.signature names match nx.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-04-26T05:18:44.567118639Z","created_by":"ubuntu","updated_at":"2026-04-26T05:27:45.419544506Z","closed_at":"2026-04-26T05:27:45.417701899Z","close_reason":"Fixed in commit f748b59. All Graph class wrappers now use nx's documented kwarg names (u_of_edge/v_of_edge for simple add_edge, u_for_edge/v_for_edge for multi add_edge, node_for_adding, ebunch_to_add, n, nodes, ebunch). Drop-in callers using the documented kwarg form now work on fnx exactly like nx. Also added _wraps_without_signature_poisoning helper so to_directed/to_undirected error messages match nx's wording (Graph.to_undirected vs <locals>.to_undirected). 32 parity tests freeze the contract.","source_repo":".","compaction_level":0,"original_size":0} |
229 | 229 | {"id":"br-r37-c1-wh0x0","title":"[reality-check] add nx.clustering.clustering","description":"fnx 16.3ms vs nx 2.77ms (5.9x slower) on BA200. Bundles 4 algorithms: clustering, transitivity, average_clustering, generalized_degree (all share the same triangle-iteration core). Port a single fnx_algorithms::clustering_coefficient_all that returns per-node clustering + global transitivity + global average + generalized degree counts in one BFS-style scan.\n\nAudited 2026-05-03 (artifact: artifacts/reality-check-2026-05-03.md). Bench fixture: barabasi_albert_graph(200, 5, seed=42).\nReference: see V_SLOW table in artifacts/reality-check-2026-05-03.md.\n\nThis bead represents a pure perf gap — the function exists in fnx and matches nx semantically, but routes through a pure-Python or naive wrapper. The fix is a Rust port mirroring the upstream nx algorithm; benchmark target is parity-or-faster than nx (>= 1.0x speedup) on the same fixture.","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-05-03T03:04:43.529996945Z","created_by":"ubuntu","updated_at":"2026-05-03T18:54:19.774393306Z","closed_at":"2026-05-03T18:54:19.772401255Z","close_reason":"Shipped in 96b05f5c. Wrapper now uses Rust _raw_clustering/_raw_average_clustering/_raw_transitivity for undirected, no-weight, all-nodes case. BA1000: clustering 0.17x → 5.9x. BA5000: 0.14x → 4.3x. Bit-exact parity. 315 tests pass.","source_repo":".","compaction_level":0,"original_size":0} |
230 | 230 | {"id":"br-r37-c1-wjv9o","title":"parity: tree.branchings + tree.mst edge iterators (5 fns)","description":"Five tree-related utilities from networkx.algorithms.tree not surfaced. Branchings: branching_weight(G, attr=weight, default=1), minimal_branching(G, *, attr=weight, default=1, preserve_attrs=False, partition=None). MST edge iterators: boruvka_mst_edges, kruskal_mst_edges, prim_mst_edges (all signature G, minimum, weight=weight, keys=True, data=True, ignore_nan=False, partition optional). These give users access to the underlying MST/branching algorithm primitives. Add Python wrappers in __init__.py exporting at top-level + __all__.","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-04-25T22:24:47.743148985Z","created_by":"ubuntu","updated_at":"2026-04-25T22:39:41.161615863Z","closed_at":"2026-04-25T22:39:41.159730985Z","close_reason":"Shipped in 7cca063: branching_weight + minimal_branching + boruvka/kruskal/prim mst_edges iterators. All 5 verified on weighted K5 (MSTs match nx exactly) and 3-node DiGraph (branching weight + edge count match).","source_repo":".","compaction_level":0,"original_size":0} |
| 231 | +{"id":"br-r37-c1-wojl3","title":"[parity-gap] diameter/radius delegate directed graphs to nx, _raw_* mishandles antiparallel directions","description":"Audit source: python/franken_networkx/__init__.py::diameter (line 5233) and ::radius (line 5266). Same defensive 'or G.is_directed(): _call_networkx_for_parity' guard as br-r37-c1-89n9d (center/periphery), but with an additional twist — the underlying Rust _raw_diameter / _raw_radius produce WRONG values on directed graphs because they call gr.undirected() before computing.\n\nRepro:\n >>> from franken_networkx._fnx import diameter as raw_diam\n >>> import franken_networkx as fnx\n >>> G = fnx.DiGraph([(i,(i+1)%5) for i in range(5)])\n >>> raw_diam(G)\n 2 # WRONG — should be 4 (length of the directed path around the cycle)\n >>> import networkx as nx\n >>> nx.diameter(nx.DiGraph([(i,(i+1)%5) for i in range(5)]))\n 4\n\nSame shape as harmonic_diameter's documented 'directed-collapse defect' (same family as eccentricity, is_eulerian, is_tree, core_number — all fixed previously). The Python wrapper currently masks this by routing directed graphs to nx, paying the fnx_to_nx graph-conversion cost on every directed-graph diameter/radius call.\n\nFix plan:\n 1. For undirected (the original fast Rust path stays): _raw_diameter / _raw_radius.\n 2. For directed: reuse fnx.eccentricity (already directed-aware, fast Rust path), then take max for diameter / min for radius.\n 3. Other-args delegation (e=, usebounds, weight=) stays unchanged.\n\nThis avoids the fnx_to_nx graph-conversion overhead on every directed-graph call AND keeps the undirected fast path. Verified bit-exact against nx 3.6.1 on directed cycle5, directed K5, directed cycle3+chord — diameter and radius all match.\n\nP1 because directed-graph callers of fnx.diameter / fnx.radius pay the round-trip cost on every call; affects every directed-graph user.","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-05-04T22:31:18.493727169Z","created_by":"ubuntu","updated_at":"2026-05-04T22:31:47.853331697Z","closed_at":"2026-05-04T22:31:47.853126048Z","close_reason":"Shipped. fnx.diameter and fnx.radius now natively handle directed graphs via fnx.eccentricity (max/min) instead of round-tripping to nx. Verified against nx on directed cycle5, K5, cycle3+chord — bit-exact match. 497 diameter/radius tests pass. The Rust _raw_diameter/_raw_radius directed-collapse defect is now bypassed at the Python wrapper level; same family as harmonic_diameter's documented defect, fixable in Rust later.","source_repo":".","compaction_level":0,"original_size":0} |
231 | 232 | {"id":"br-r37-c1-wpydo","title":"parity: community leiden_communities + leiden_partitions missing","description":"networkx.algorithms.community.leiden_communities(G, ...) and leiden_partitions(G, ...) (Leiden community detection algorithm) not exposed by franken_networkx. Add Python wrappers delegating to nx.algorithms.community via _call_networkx_community_for_parity. Export both at top-level and include in __all__ under community detection section.","status":"closed","priority":2,"issue_type":"task","created_at":"2026-04-25T12:06:41.073069778Z","created_by":"ubuntu","updated_at":"2026-04-25T13:05:29.824008425Z","closed_at":"2026-04-25T13:05:29.822140820Z","close_reason":"Shipped in 4eb0d6d: leiden_communities/partitions wrappers; mirrors nx NotImplementedError parity","source_repo":".","compaction_level":0,"original_size":0} |
232 | 233 | {"id":"br-r37-c1-wtjho","title":"parity: bellman_ford negative-cycle error message says 'Negative cost cycle detected.' instead of nx's 'Negative cycle detected.'","description":"fnx's bellman_ford_predecessor_and_distance raises NetworkXUnbounded with message 'Negative cost cycle detected.' nx uses 'Negative cycle detected.' (no 'cost'). Drop-in code that matches on the exact error message text fails on fnx. Other bellman_ford paths in fnx (lines 12321/12324/12360) already use the correct nx message; just one site is wrong. Fix: change the message at line 27949 to match nx exactly.","status":"closed","priority":3,"issue_type":"bug","created_at":"2026-04-26T09:10:44.499350842Z","created_by":"ubuntu","updated_at":"2026-04-26T09:12:59.207406388Z","closed_at":"2026-04-26T09:12:59.205363470Z","close_reason":"Fixed in commit acd6a87. All four bellman_ford entry points now raise with nx's exact 'Negative cycle detected.' message. 7 parity tests freeze the contract.","source_repo":".","compaction_level":0,"original_size":0} |
233 | 234 | {"id":"br-r37-c1-wu9dv","title":"parity: _FilteredDegreeView class name and repr diverge from nx's DegreeView","description":"fnx.bipartite.degrees(G, top) returns a tuple of (_FilteredDegreeView, _FilteredDegreeView). nx returns (DegreeView({1: 2, 3: 2}), DegreeView({0: 1, 2: 2, 4: 1})). Two issues: (1) class name '_FilteredDegreeView' differs from nx's 'DegreeView'. (2) repr shows just node-keys list ('_FilteredDegreeView([1, 3])') instead of nx's full dict repr ('DegreeView({1: 2, 3: 2})'). Drop-in code that prints these or compares reprs breaks. Fix: rename class to 'DegreeView' (or set __qualname__) and update __repr__ to match nx's dict format.","status":"closed","priority":3,"issue_type":"bug","created_at":"2026-04-26T12:14:35.680457671Z","created_by":"ubuntu","updated_at":"2026-04-26T12:17:16.042991811Z","closed_at":"2026-04-26T12:17:16.041024306Z","close_reason":"Fixed in commit d524522. _FilteredDegreeView now has class name 'DegreeView' and repr matching nx's DegreeView({...}) format. 7 parity tests freeze the contract.","source_repo":".","compaction_level":0,"original_size":0} |
|
0 commit comments