|
207 | 207 | {"id":"br-r37-c1-tm1tq","title":"Unhashable parity: resistance_distance (too strict), betweenness_centrality_subset, astar_path_length wording","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-04-27T11:06:57.445670354Z","created_by":"ubuntu","updated_at":"2026-04-27T11:11:13.783065861Z","closed_at":"2026-04-27T11:11:13.780303689Z","source_repo":".","compaction_level":0,"original_size":0} |
208 | 208 | {"id":"br-r37-c1-tqimg","title":"20+ fnx functions missing @not_implemented_for('multigraph') guard","description":"An audit of nx functions decorated with @not_implemented_for('multigraph') against fnx revealed 20+ functions that silently accept MultiGraph/MultiDiGraph input where nx raises NetworkXNotImplemented:\n\n bethe_hessian_matrix, cn_soundarajan_hopcroft, communicability,\n communicability_betweenness_centrality, directed_modularity_matrix,\n eigenvector_centrality, find_asteroidal_triple, girth,\n hyper_wiener_index, intersection_array, is_at_free,\n is_perfect_graph, katz_centrality, max_weight_matching,\n maximal_matching, min_weight_matching, mycielskian,\n ra_index_soundarajan_hopcroft, random_reference, stoer_wagner,\n tree_broadcast_center, tree_broadcast_time, within_inter_cluster.\n\nDrop-in code that does pytest.raises(NetworkXNotImplemented) on these functions for multigraph inputs won't trigger on fnx. Most fnx wrappers either return a value (from a Rust path that ignores parallel edges), raise a wrong exception type (e.g. NetworkXAlgorithmError 'No community information available for Node 1' on link-prediction functions), or fail with PowerIterationFailedConvergence (on eigenvector_centrality MultiDiGraph).\n\nFix: add if G.is_multigraph(): raise NetworkXNotImplemented('not implemented for multigraph type') at the top of each fnx wrapper.\n\nThis is a focused mechanical change: one guard per function, no algorithmic changes.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-04-27T07:55:34.775823916Z","created_by":"ubuntu","updated_at":"2026-04-27T08:06:42.216472526Z","closed_at":"2026-04-27T08:06:42.212949361Z","source_repo":".","compaction_level":0,"original_size":0} |
209 | 209 | {"id":"br-r37-c1-turq0","title":"parity: node_connectivity/edge_connectivity silently return 0 on empty graph, nx raises NetworkXPointlessConcept","description":"fnx.node_connectivity(fnx.empty_graph(0)) returns 0; nx.node_connectivity(nx.empty_graph(0)) raises NetworkXPointlessConcept('Connectivity is undefined for the null graph.'). Same drift in edge_connectivity. Drop-in code that catches NetworkXPointlessConcept to gate empty-graph paths fails to trigger on fnx — silent value masks the contract violation. Fix: add the raise at the top of each wrapper, matching nx's documented behaviour. Single-node case (returns 0 on both) is unchanged.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-04-26T07:17:28.519121260Z","created_by":"ubuntu","updated_at":"2026-04-26T07:19:20.086837509Z","closed_at":"2026-04-26T07:19:20.084994560Z","close_reason":"Fixed in commit c633959. node_connectivity/edge_connectivity raise NetworkXPointlessConcept on null graph matching nx. 8 parity tests freeze the contract.","source_repo":".","compaction_level":0,"original_size":0} |
210 | | -{"id":"br-r37-c1-tvf43","title":"[reality-check] add nx.clique.find_cliques","description":"fnx 8.76ms vs nx 1.23ms (7x slower) on BA200. Bron-Kerbosch with pivot. Port nx.algorithms.clique.find_cliques to a Rust generator (returns Vec<Vec<&str>>) and stream from PyO3.\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.","notes":"Partial shipped locally: find_cliques(nodes=None) now uses the nx-order local Bron-Kerbosch path instead of NetworkX fallback or the Rust canonical-order binding; focused parity/no-fallback tests pass with PYTHONPATH=python. BA200 median after patch: fnx 2.073 ms vs nx 1.260 ms, exact clique order true. Remaining blocker for closure: parity-or-faster target is unmet; a PyO3 CPython-set-order port passed parity but measured ~7.431 ms, while the fast Rust path breaks observable clique iteration order.","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2026-05-03T03:03:17.914009371Z","created_by":"ubuntu","updated_at":"2026-05-03T22:11:54.957785823Z","source_repo":".","compaction_level":0,"original_size":0} |
| 210 | +{"id":"br-r37-c1-tvf43","title":"[reality-check] add nx.clique.find_cliques","description":"fnx 8.76ms vs nx 1.23ms (7x slower) on BA200. Bron-Kerbosch with pivot. Port nx.algorithms.clique.find_cliques to a Rust generator (returns Vec<Vec<&str>>) and stream from PyO3.\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.","notes":"Partial shipped locally: find_cliques(nodes=None) now uses the nx-order local Bron-Kerbosch path instead of NetworkX fallback or the Rust canonical-order binding; focused parity/no-fallback tests pass with PYTHONPATH=python. BA200 median after patch: fnx 2.073 ms vs nx 1.260 ms, exact clique order true. Remaining blocker for closure: parity-or-faster target is unmet; a PyO3 CPython-set-order port passed parity but measured ~7.431 ms, while the fast Rust path breaks observable clique iteration order.","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2026-05-03T03:03:17.914009371Z","created_by":"ubuntu","updated_at":"2026-05-04T19:07:47.348148646Z","source_repo":".","compaction_level":0,"original_size":0,"comments":[{"id":106,"issue_id":"br-r37-c1-tvf43","author":"ubuntu","text":"Partial progress shipped in 34c50ba1: switched adjacency-build to G.neighbors() (fast Rust round-trip) from G[u] (slow AtlasView iteration with per-edge PyO3 attr fetch). Set-comprehension form preserves nx's exact iter order — verified list(G[u]) == list(G.neighbors(u)) on every node, full clique-order parity holds across all 262 clique-family tests. Bench: BA50 1.02x (parity), BA200 1.19x (was 1.50x), BA500 1.14x (was 1.61x), BA1000 1.07x (was 1.60x). Major gap closure but not full >= 1.0x. Remaining gap (7-19%) is now in the Bron-Kerbosch loop itself — pivot-selection lambda and set & operations dominate now that adj-build is cheap. Next step would be order-preserving Rust port but exceeds 60-min budget for this cycle.","created_at":"2026-05-04T19:07:47Z"}]} |
211 | 211 | {"id":"br-r37-c1-u7ry8","title":"second_order_centrality silently returns dict on empty/disconnected; nx raises NetworkXException","description":"fnx.second_order_centrality silently returns a value dict on empty graphs and on disconnected graphs. nx raises NetworkXException with specific wording:\n\n >>> fnx.second_order_centrality(fnx.Graph()) # {}\n >>> nx.second_order_centrality(nx.Graph()) # NetworkXException: Empty graph.\n\n >>> g = fnx.Graph(); g.add_nodes_from([1,2,3])\n >>> fnx.second_order_centrality(g) # {1: nan, 2: nan, 3: nan}\n >>> nx.second_order_centrality(nx.Graph(g)) # NetworkXException: Non connected graph.\n\n >>> fnx.second_order_centrality(fnx.Graph([(1,2),(3,4)])) # {1:0.0, 2:0.0, 3:0.0, 4:0.0}\n >>> nx.second_order_centrality(nx.Graph([(1,2),(3,4)])) # NetworkXException: Non connected graph.\n\nThe single-node case (one isolated node) is correctly handled — both fnx and nx return {n: 0.0}. Only multi-node disconnected and the empty case drift.\n\nFix: add explicit empty/disconnected guards at the top of fnx.second_order_centrality with nx's exact wording. Drop-in code that does pytest.raises(NetworkXException, match='Non connected graph') would not trigger on fnx silently returning a value.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-04-27T05:57:36.133302831Z","created_by":"ubuntu","updated_at":"2026-04-27T06:03:15.496115939Z","closed_at":"2026-04-27T06:03:15.493224402Z","source_repo":".","compaction_level":0,"original_size":0} |
212 | 212 | {"id":"br-r37-c1-ua4i8","title":"[parity-gap] katz_centrality silently returns un-converged values; nx raises PowerIterationFailedConvergence","description":"fnx.katz_centrality runs power iteration up to KATZ_DEFAULT_MAX_ITERATIONS (1000) and falls through the loop if convergence isn't reached, returning the un-converged values normalized. nx.katz_centrality raises PowerIterationFailedConvergence(max_iter) in that case.\n\nRepro on BA200, default alpha=0.1, max_iter=1000:\n fnx.katz_centrality(G) → succeeds with normalized but un-converged values\n nx.katz_centrality(G_nx) → raises PowerIterationFailedConvergence\n\nBug location: crates/fnx-algorithms/src/lib.rs:2442-2473 — power iteration loop has no convergence-failure exit. After KATZ_DEFAULT_MAX_ITERATIONS, the loop ends and the function continues to normalization + return.\n\nFix: add a convergence flag; if loop ends without delta < tolerance, return Result::Err so the PyO3 binding can raise PowerIterationFailedConvergence matching nx's contract.\n\nAudit-found 2026-05-03 during review-mode pass.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-05-03T22:58:17.797122317Z","created_by":"ubuntu","updated_at":"2026-05-03T23:03:25.059594620Z","closed_at":"2026-05-03T23:03:25.059364835Z","close_reason":"Shipped in 8da6d1ac. fnx.katz_centrality now raises PowerIterationFailedConvergence on non-convergence matching nx (was silently returning un-converged vector). 20 katz tests pass; 3 cargo unit tests pass; bit-exact parity vs nx on convergent fixtures.","source_repo":".","compaction_level":0,"original_size":0} |
213 | 213 | {"id":"br-r37-c1-ugod2","title":"parity: 4 branching/arborescence functions over-restrict undirected (or use wrong error wording)","description":"Four functions diverge from nx on undirected input: (1) maximum_branching raises NotImplemented; nx.maximum_branching(undirected) returns a maximum-spanning Graph result. (2) minimum_branching raises NotImplemented; nx returns an empty Graph (lowest sum is no edges). (3) maximum_spanning_arborescence and (4) minimum_spanning_arborescence raise with custom message '<name> is only implemented for directed graphs.' instead of nx's standard 'not implemented for undirected type'. Drop-in code that uses these on undirected breaks or fails to match nx's exact NotImplemented message. Fix: delegate branching variants to nx for undirected; align arborescence messages.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-04-26T09:57:01.883605639Z","created_by":"ubuntu","updated_at":"2026-04-26T09:59:23.989928755Z","closed_at":"2026-04-26T09:59:23.987956927Z","close_reason":"Fixed in commit f0d25ef. min/maximum_branching now accept undirected (delegate to nx); min/maximum_spanning_arborescence raise nx's standard NotImplemented message. 10 parity tests freeze the contract.","source_repo":".","compaction_level":0,"original_size":0} |
|
0 commit comments