Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Jan 7, 2026

📄 19,842% (198.42x) speedup for find_last_node in src/algorithms/graph.py

⏱️ Runtime : 66.7 milliseconds 334 microseconds (best of 250 runs)

📝 Explanation and details

The optimized code achieves a ~200x speedup by eliminating redundant nested iterations through a fundamental algorithmic improvement.

What changed:
The original implementation uses a nested loop structure where for each node, it checks against all edges to verify the node isn't a source (all(e["source"] != n["id"] for e in edges)). This creates O(N×M) time complexity where N is the number of nodes and M is the number of edges.

The optimized version pre-computes a set of all source node IDs (sources = {e["source"] for e in edges}), then performs simple O(1) membership checks (n["id"] not in sources). This reduces complexity to O(N+M).

Why it's faster:

  1. Set lookups are O(1): Python sets use hash tables, making membership checks nearly instantaneous regardless of set size
  2. Single edge traversal: Edges are only iterated once to build the set, not repeatedly for each node
  3. Eliminates nested iteration: The original's nested generator expressions created quadratic behavior that became catastrophic with larger graphs

Performance characteristics from tests:

  • Small graphs (2-5 nodes): 30-100% faster - modest gains due to set construction overhead
  • Linear chains (500-1000 nodes): 15,000-32,000% faster - dramatic improvement as the quadratic bottleneck is eliminated
  • Dense graphs: 5,800% faster on 100-node dense graph - particularly benefits from avoiding repeated edge scans
  • Empty edges: Slight overhead (9% slower) due to set construction, but negligible in absolute terms (microseconds)

The optimization is universally beneficial for any workflow calling this function with non-trivial graph sizes, particularly in scenarios involving graph traversal, flow analysis, or dependency resolution where graphs commonly have hundreds or thousands of nodes.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 58 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
from __future__ import annotations

# imports
import pytest  # used for our unit tests
from src.algorithms.graph import find_last_node

# unit tests

# 1. Basic Test Cases


def test_single_node_no_edges():
    # Only one node, no edges: should return the node itself
    nodes = [{"id": 1, "label": "A"}]
    edges = []
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.21μs -> 917ns (31.7% faster)


def test_two_nodes_one_edge():
    # Two nodes, one edge from 1->2: last node is node 2 (no outgoing edges)
    nodes = [{"id": 1}, {"id": 2}]
    edges = [{"source": 1, "target": 2}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.79μs -> 1.17μs (53.6% faster)


def test_three_nodes_linear_chain():
    # Three nodes, edges: 1->2, 2->3: last node is 3
    nodes = [{"id": 1}, {"id": 2}, {"id": 3}]
    edges = [{"source": 1, "target": 2}, {"source": 2, "target": 3}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 2.17μs -> 1.25μs (73.3% faster)


def test_multiple_nodes_multiple_edges():
    # Four nodes, edges: 1->2, 1->3, 2->4, 3->4: last node is 4
    nodes = [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}]
    edges = [
        {"source": 1, "target": 2},
        {"source": 1, "target": 3},
        {"source": 2, "target": 4},
        {"source": 3, "target": 4},
    ]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 2.75μs -> 1.38μs (100% faster)


# 2. Edge Test Cases


def test_empty_nodes_and_edges():
    # No nodes or edges: should return None
    nodes = []
    edges = []
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 791ns -> 875ns (9.60% slower)


def test_nodes_with_no_edges():
    # Multiple nodes, no edges: should return the first node (since all are "last")
    nodes = [{"id": 10}, {"id": 20}, {"id": 30}]
    edges = []
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.25μs -> 1.00μs (25.0% faster)


def test_all_nodes_have_outgoing_edges():
    # All nodes have outgoing edges: no last node, should return None
    nodes = [{"id": 1}, {"id": 2}]
    edges = [{"source": 1, "target": 2}, {"source": 2, "target": 1}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.88μs -> 1.21μs (55.2% faster)


def test_node_ids_are_strings():
    # Node ids are strings, not ints
    nodes = [{"id": "a"}, {"id": "b"}]
    edges = [{"source": "a", "target": "b"}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.88μs -> 1.17μs (60.8% faster)


def test_disconnected_nodes():
    # Some nodes are disconnected (no edges at all)
    nodes = [{"id": 1}, {"id": 2}, {"id": 3}]
    edges = [{"source": 1, "target": 2}]
    # Node 3 is not connected, so it's a "last" node
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.79μs -> 1.17μs (53.5% faster)
    # Accept either node 2 (no outgoing edge) or node 3 (no edges at all)


def test_multiple_last_nodes_returns_first():
    # Multiple nodes with no outgoing edges: should return the first one
    nodes = [{"id": 1}, {"id": 2}, {"id": 3}]
    edges = [{"source": 1, "target": 2}]
    # Nodes 2 and 3 have no outgoing edges
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.79μs -> 1.17μs (53.7% faster)


def test_edge_with_nonexistent_source():
    # Edge references a source node not in nodes list
    nodes = [{"id": 1}]
    edges = [{"source": 2, "target": 1}]
    # Node 1 has no outgoing edges, so it should be returned
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.46μs -> 1.08μs (34.5% faster)


def test_edge_with_nonexistent_target():
    # Edge references a target node not in nodes list
    nodes = [{"id": 1}]
    edges = [{"source": 1, "target": 2}]
    # Node 1 has outgoing edge, so no last node
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.42μs -> 1.08μs (30.7% faster)


def test_nodes_with_extra_fields():
    # Nodes have extra fields, function should ignore them
    nodes = [{"id": 1, "foo": "bar"}, {"id": 2, "baz": 42}]
    edges = [{"source": 1, "target": 2}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.75μs -> 1.12μs (55.6% faster)


def test_edges_with_extra_fields():
    # Edges have extra fields, function should ignore them
    nodes = [{"id": 1}, {"id": 2}]
    edges = [{"source": 1, "target": 2, "weight": 3}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.79μs -> 1.08μs (65.4% faster)


def test_duplicate_node_ids():
    # Duplicate node ids: should return the first "last" node it finds
    nodes = [{"id": 1}, {"id": 1}]
    edges = []
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.25μs -> 1.00μs (25.0% faster)


def test_edge_case_large_id_values():
    # Node ids are very large numbers
    nodes = [{"id": 9999999999999}, {"id": 8888888888888}]
    edges = [{"source": 9999999999999, "target": 8888888888888}]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.96μs -> 1.17μs (67.8% faster)


# 3. Large Scale Test Cases


def test_large_linear_chain():
    # Large linear chain of nodes: 1->2->3->...->1000
    N = 1000
    nodes = [{"id": i} for i in range(1, N + 1)]
    edges = [{"source": i, "target": i + 1} for i in range(1, N)]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 18.2ms -> 55.8μs (32532% faster)


def test_large_star_graph():
    # One central node with edges to all others
    N = 1000
    nodes = [{"id": 0}] + [{"id": i} for i in range(1, N)]
    edges = [{"source": 0, "target": i} for i in range(1, N)]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 38.2μs -> 20.0μs (90.4% faster)


def test_large_graph_all_last_nodes():
    # All nodes have no outgoing edges (no edges at all)
    N = 1000
    nodes = [{"id": i} for i in range(N)]
    edges = []
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 1.29μs -> 1.04μs (24.1% faster)


def test_large_graph_no_last_node():
    # All nodes have outgoing edges (cycle)
    N = 1000
    nodes = [{"id": i} for i in range(N)]
    edges = [{"source": i, "target": (i + 1) % N} for i in range(N)]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 18.2ms -> 54.9μs (32968% faster)


def test_large_graph_some_disconnected_last_nodes():
    # Half nodes are isolated, half are in a chain
    N = 1000
    nodes = [{"id": i} for i in range(N)]
    edges = [{"source": i, "target": i + 1} for i in range(0, N // 2 - 1)]
    codeflash_output = find_last_node(nodes, edges)
    result = codeflash_output  # 4.47ms -> 27.8μs (16021% faster)
    # Could be any isolated node or the end of the chain
    possible_last_nodes = [{"id": i} for i in range(N // 2, N)] + [{"id": N // 2 - 1}]


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import pytest  # used for our unit tests
from src.algorithms.graph import find_last_node

# unit tests


class TestFindLastNodeBasic:
    """Test basic functionality with simple, common scenarios."""

    def test_single_node_no_edges(self):
        """Single node with no edges should return that node."""
        nodes = [{"id": "A"}]
        edges = []
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.25μs -> 1.00μs (25.0% faster)

    def test_two_nodes_one_edge(self):
        """Two nodes connected by one edge: A→B, B is the last node."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = [{"source": "A", "target": "B"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.96μs -> 1.17μs (67.8% faster)

    def test_linear_chain_three_nodes(self):
        """Linear chain A→B→C, C should be the last node."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}]
        edges = [{"source": "A", "target": "B"}, {"source": "B", "target": "C"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.33μs -> 1.25μs (86.6% faster)

    def test_tree_structure(self):
        """Tree structure with one root and multiple leaves, returns first leaf."""
        nodes = [{"id": "root"}, {"id": "leaf1"}, {"id": "leaf2"}]
        edges = [
            {"source": "root", "target": "leaf1"},
            {"source": "root", "target": "leaf2"},
        ]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.00μs -> 1.21μs (65.4% faster)

    def test_disconnected_nodes(self):
        """Two disconnected nodes, both are last nodes, returns first."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = []
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.21μs -> 1.00μs (20.9% faster)


class TestFindLastNodeEdgeCases:
    """Test edge cases and unusual scenarios."""

    def test_empty_nodes_list(self):
        """Empty nodes list should return None."""
        nodes = []
        edges = []
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 792ns -> 875ns (9.49% slower)

    def test_empty_edges_with_nodes(self):
        """No edges means all nodes are last nodes, returns first."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}]
        edges = []
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.17μs -> 958ns (21.7% faster)

    def test_all_nodes_are_sources(self):
        """Cycle where all nodes are sources should return None."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = [{"source": "A", "target": "B"}, {"source": "B", "target": "A"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.96μs -> 1.17μs (67.8% faster)

    def test_self_loop(self):
        """Node with self-loop is a source, should return None if only node."""
        nodes = [{"id": "A"}]
        edges = [{"source": "A", "target": "A"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.33μs -> 1.12μs (18.6% faster)

    def test_self_loop_with_other_node(self):
        """Node with self-loop and another node without edges."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = [{"source": "A", "target": "A"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.75μs -> 1.12μs (55.6% faster)

    def test_multiple_last_nodes_returns_first(self):
        """Multiple last nodes should return the first one in the list."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}]
        edges = [{"source": "A", "target": "B"}]
        # C is not a source, comes before any other non-source
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.83μs -> 1.12μs (63.0% faster)

    def test_complete_cycle(self):
        """Complete cycle A→B→C→A should return None."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}]
        edges = [
            {"source": "A", "target": "B"},
            {"source": "B", "target": "C"},
            {"source": "C", "target": "A"},
        ]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.33μs -> 1.25μs (86.7% faster)


class TestFindLastNodeDataFormats:
    """Test various data formats and types."""

    def test_integer_node_ids(self):
        """Node IDs as integers should work correctly."""
        nodes = [{"id": 1}, {"id": 2}, {"id": 3}]
        edges = [{"source": 1, "target": 2}, {"source": 2, "target": 3}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.25μs -> 1.25μs (80.0% faster)

    def test_mixed_type_node_ids(self):
        """Mixed type node IDs (strings and integers)."""
        nodes = [{"id": "A"}, {"id": 1}, {"id": "B"}]
        edges = [{"source": "A", "target": 1}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.83μs -> 1.12μs (62.9% faster)

    def test_nodes_with_extra_properties(self):
        """Nodes with additional properties beyond 'id'."""
        nodes = [
            {"id": "A", "name": "Node A", "value": 10},
            {"id": "B", "name": "Node B", "value": 20},
        ]
        edges = [{"source": "A", "target": "B"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.83μs -> 1.12μs (62.9% faster)

    def test_edges_with_extra_properties(self):
        """Edges with additional properties beyond 'source'."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = [{"source": "A", "target": "B", "weight": 5, "label": "edge1"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.79μs -> 1.12μs (59.2% faster)

    def test_edges_referencing_nonexistent_nodes(self):
        """Edges referencing nodes not in the nodes list."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = [{"source": "X", "target": "Y"}, {"source": "A", "target": "Z"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.12μs -> 1.17μs (82.1% faster)

    def test_node_id_is_zero(self):
        """Node ID of 0 (falsy value) should work correctly."""
        nodes = [{"id": 0}, {"id": 1}]
        edges = [{"source": 0, "target": 1}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.92μs -> 1.21μs (58.6% faster)

    def test_node_id_is_empty_string(self):
        """Node ID as empty string should work."""
        nodes = [{"id": ""}, {"id": "A"}]
        edges = [{"source": "", "target": "A"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.83μs -> 1.12μs (63.0% faster)

    def test_node_id_is_none(self):
        """Node ID as None should work."""
        nodes = [{"id": None}, {"id": "A"}]
        edges = [{"source": None, "target": "A"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.96μs -> 1.17μs (67.8% faster)


class TestFindLastNodeComplexGraphs:
    """Test more complex graph structures."""

    def test_diamond_structure(self):
        """Diamond structure: A→B,C and B,C→D. D is last."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}, {"id": "D"}]
        edges = [
            {"source": "A", "target": "B"},
            {"source": "A", "target": "C"},
            {"source": "B", "target": "D"},
            {"source": "C", "target": "D"},
        ]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.79μs -> 1.38μs (103% faster)

    def test_multiple_disconnected_chains(self):
        """Multiple disconnected chains, returns first last node."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}, {"id": "D"}]
        edges = [{"source": "A", "target": "B"}, {"source": "C", "target": "D"}]
        # B and D are last nodes, B comes first
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.96μs -> 1.17μs (67.9% faster)

    def test_star_topology(self):
        """Star topology: center node connects to multiple leaf nodes."""
        nodes = [{"id": "center"}, {"id": "leaf1"}, {"id": "leaf2"}, {"id": "leaf3"}]
        edges = [
            {"source": "center", "target": "leaf1"},
            {"source": "center", "target": "leaf2"},
            {"source": "center", "target": "leaf3"},
        ]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.04μs -> 1.25μs (63.4% faster)

    def test_partial_cycle_with_tail(self):
        """Partial cycle with a tail: A→B→C→B, D→E. E is last."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "C"}, {"id": "D"}, {"id": "E"}]
        edges = [
            {"source": "A", "target": "B"},
            {"source": "B", "target": "C"},
            {"source": "C", "target": "B"},
            {"source": "D", "target": "E"},
        ]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 3.00μs -> 1.33μs (125% faster)


class TestFindLastNodeLargeScale:
    """Test performance and scalability with large datasets."""

    def test_long_linear_chain(self):
        """Long linear chain of 500 nodes."""
        num_nodes = 500
        nodes = [{"id": i} for i in range(num_nodes)]
        edges = [{"source": i, "target": i + 1} for i in range(num_nodes - 1)]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 4.46ms -> 28.2μs (15712% faster)

    def test_large_number_of_nodes_single_last(self):
        """1000 nodes with one clear last node."""
        num_nodes = 1000
        nodes = [{"id": i} for i in range(num_nodes)]
        # All nodes except last point to the last node
        edges = [{"source": i, "target": num_nodes - 1} for i in range(num_nodes - 1)]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 18.1ms -> 54.7μs (33022% faster)

    def test_large_sparse_graph(self):
        """Large graph with sparse connectivity (500 nodes, 100 edges)."""
        num_nodes = 500
        nodes = [{"id": i} for i in range(num_nodes)]
        # Create 100 edges connecting random pairs
        edges = [{"source": i * 5, "target": i * 5 + 1} for i in range(100)]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 6.12μs -> 4.62μs (32.4% faster)

    def test_large_dense_graph(self):
        """Dense graph where most nodes are sources (100 nodes, many edges)."""
        num_nodes = 100
        nodes = [{"id": i} for i in range(num_nodes)]
        # Create edges from each node to the next 5 nodes (circular)
        edges = []
        for i in range(num_nodes - 1):
            for j in range(1, 6):
                target = (i + j) % num_nodes
                edges.append({"source": i, "target": target})
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 881μs -> 15.0μs (5791% faster)

    def test_many_disconnected_single_nodes(self):
        """Many disconnected single nodes (all are last nodes)."""
        num_nodes = 800
        nodes = [{"id": f"node_{i}"} for i in range(num_nodes)]
        edges = []
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.38μs -> 1.08μs (27.0% faster)

    def test_large_tree_structure(self):
        """Large tree with one root and many leaves."""
        # Binary tree with depth 9 (511 nodes)
        nodes = [{"id": i} for i in range(511)]
        edges = []
        for i in range(255):  # Internal nodes
            left_child = 2 * i + 1
            right_child = 2 * i + 2
            edges.append({"source": i, "target": left_child})
            edges.append({"source": i, "target": right_child})
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.29ms -> 18.8μs (12116% faster)


class TestFindLastNodeBoundaryConditions:
    """Test boundary conditions and potential error cases."""

    def test_duplicate_node_ids(self):
        """Duplicate node IDs in the list."""
        nodes = [{"id": "A"}, {"id": "B"}, {"id": "A"}]
        edges = [{"source": "A", "target": "B"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.92μs -> 1.08μs (77.0% faster)

    def test_duplicate_edges(self):
        """Duplicate edges in the list."""
        nodes = [{"id": "A"}, {"id": "B"}]
        edges = [
            {"source": "A", "target": "B"},
            {"source": "A", "target": "B"},
            {"source": "A", "target": "B"},
        ]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 2.08μs -> 1.21μs (72.4% faster)

    def test_node_order_matters(self):
        """Verify that node order affects which last node is returned."""
        # First ordering
        nodes1 = [{"id": "A"}, {"id": "B"}, {"id": "C"}]
        edges1 = [{"source": "A", "target": "X"}]
        codeflash_output = find_last_node(nodes1, edges1)
        result1 = codeflash_output  # 1.83μs -> 1.04μs (75.9% faster)

        # Different ordering
        nodes2 = [{"id": "C"}, {"id": "B"}, {"id": "A"}]
        edges2 = [{"source": "A", "target": "X"}]
        codeflash_output = find_last_node(nodes2, edges2)
        result2 = codeflash_output  # 667ns -> 500ns (33.4% faster)

    def test_very_long_node_id(self):
        """Node ID with very long string."""
        long_id = "A" * 1000
        nodes = [{"id": long_id}, {"id": "B"}]
        edges = [{"source": long_id, "target": "B"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.88μs -> 1.08μs (73.1% faster)

    def test_special_characters_in_node_id(self):
        """Node IDs with special characters."""
        nodes = [{"id": "node-1"}, {"id": "node_2"}, {"id": "node.3"}, {"id": "node@4"}]
        edges = [{"source": "node-1", "target": "node_2"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.96μs -> 1.12μs (74.0% faster)

    def test_unicode_node_ids(self):
        """Node IDs with unicode characters."""
        nodes = [{"id": "节点A"}, {"id": "नोड_B"}, {"id": "узел_C"}]
        edges = [{"source": "节点A", "target": "नोड_B"}]
        codeflash_output = find_last_node(nodes, edges)
        result = codeflash_output  # 1.96μs -> 1.12μs (74.0% faster)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-find_last_node-mk3jbk03 and push.

Codeflash Static Badge

The optimized code achieves a **~200x speedup** by eliminating redundant nested iterations through a fundamental algorithmic improvement.

**What changed:**
The original implementation uses a nested loop structure where for each node, it checks against *all* edges to verify the node isn't a source (`all(e["source"] != n["id"] for e in edges)`). This creates O(N×M) time complexity where N is the number of nodes and M is the number of edges.

The optimized version pre-computes a set of all source node IDs (`sources = {e["source"] for e in edges}`), then performs simple O(1) membership checks (`n["id"] not in sources`). This reduces complexity to O(N+M).

**Why it's faster:**
1. **Set lookups are O(1)**: Python sets use hash tables, making membership checks nearly instantaneous regardless of set size
2. **Single edge traversal**: Edges are only iterated once to build the set, not repeatedly for each node
3. **Eliminates nested iteration**: The original's nested generator expressions created quadratic behavior that became catastrophic with larger graphs

**Performance characteristics from tests:**
- **Small graphs (2-5 nodes)**: 30-100% faster - modest gains due to set construction overhead
- **Linear chains (500-1000 nodes)**: 15,000-32,000% faster - dramatic improvement as the quadratic bottleneck is eliminated
- **Dense graphs**: 5,800% faster on 100-node dense graph - particularly benefits from avoiding repeated edge scans
- **Empty edges**: Slight overhead (9% slower) due to set construction, but negligible in absolute terms (microseconds)

The optimization is universally beneficial for any workflow calling this function with non-trivial graph sizes, particularly in scenarios involving graph traversal, flow analysis, or dependency resolution where graphs commonly have hundreds or thousands of nodes.
@codeflash-ai codeflash-ai bot requested a review from KRRT7 January 7, 2026 04:45
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Jan 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant