MCPcopy Create free account
hub / github.com/Effect-TS/effect / isAcyclic

Function isAcyclic

packages/effect/src/Graph.ts:3510–3631  ·  view source on GitHub ↗
(
  graph: Graph<N, E, T> | MutableGraph<N, E, T>
)

Source from the content-addressed store, hash-verified

3508 * @since 3.18.0
3509 */
3510export const isAcyclic = <N, E, T extends Kind = "directed">(
3511 graph: Graph<N, E, T> | MutableGraph<N, E, T>
3512): boolean => {
3513 const impl = graphImpl(graph)
3514 // Use existing cycle flag if available
3515 if (Option.isSome(impl.acyclic)) {
3516 return impl.acyclic.value
3517 }
3518
3519 if (graph.type === "undirected") {
3520 const visited = new Set<NodeIndex>()
3521
3522 for (const startNode of impl.nodes.keys()) {
3523 if (visited.has(startNode)) {
3524 continue
3525 }
3526
3527 visited.add(startNode)
3528 const stack: Array<{ node: NodeIndex; incoming: EdgeIndex | null }> = [{ node: startNode, incoming: null }]
3529
3530 while (stack.length > 0) {
3531 const { node, incoming } = stack.pop()!
3532 const adjacencyList = impl.adjacency.get(node)
3533 if (adjacencyList === undefined) {
3534 continue
3535 }
3536
3537 for (const edgeIndex of adjacencyList) {
3538 if (edgeIndex === incoming) {
3539 continue
3540 }
3541 const edge = impl.edges.get(edgeIndex)
3542 if (edge === undefined) {
3543 continue
3544 }
3545 const neighbor = getTraversableNeighbor(graph, node, edge)
3546 if (!visited.has(neighbor)) {
3547 visited.add(neighbor)
3548 stack.push({ node: neighbor, incoming: edgeIndex })
3549 } else {
3550 impl.acyclic = Option.some(false)
3551 return false
3552 }
3553 }
3554 }
3555 }
3556
3557 impl.acyclic = Option.some(true)
3558 return true
3559 }
3560
3561 // Stack-safe DFS cycle detection using iterative approach
3562 const visited = new Set<NodeIndex>()
3563 const recursionStack = new Set<NodeIndex>()
3564
3565 // Stack entry: [node, neighbors, neighborIndex, isFirstVisit]
3566 type DfsStackEntry = [NodeIndex, Array<NodeIndex>, number, boolean]
3567

Callers 1

Graph.tsFile · 0.85

Calls 8

graphImplFunction · 0.85
getTraversableNeighborFunction · 0.85
getDirectedNeighborsFunction · 0.85
pushMethod · 0.80
someMethod · 0.80
addMethod · 0.65
getMethod · 0.65
hasMethod · 0.45

Tested by

no test coverage detected