MCPcopy Index your code
hub / github.com/Effect-TS/effect / isAcyclic

Function isAcyclic

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

Source from the content-addressed store, hash-verified

1887 * @category algorithms
1888 */
1889export const isAcyclic = <N, E, T extends Kind = "directed">(
1890 graph: Graph<N, E, T> | MutableGraph<N, E, T>
1891): boolean => {
1892 // Use existing cycle flag if available
1893 if (Option.isSome(graph.isAcyclic)) {
1894 return graph.isAcyclic.value
1895 }
1896
1897 if (graph.type === "undirected") {
1898 const visited = new Set<NodeIndex>()
1899
1900 for (const startNode of graph.nodes.keys()) {
1901 if (visited.has(startNode)) {
1902 continue
1903 }
1904
1905 visited.add(startNode)
1906 const stack: Array<{ node: NodeIndex; parent: NodeIndex | null }> = [{ node: startNode, parent: null }]
1907
1908 while (stack.length > 0) {
1909 const { node, parent } = stack.pop()!
1910 const nodeNeighbors = getUndirectedNeighbors(graph as any, node)
1911
1912 for (const neighbor of nodeNeighbors) {
1913 if (!visited.has(neighbor)) {
1914 visited.add(neighbor)
1915 stack.push({ node: neighbor, parent: node })
1916 } else if (neighbor !== parent) {
1917 graph.isAcyclic = Option.some(false)
1918 return false
1919 }
1920 }
1921 }
1922 }
1923
1924 graph.isAcyclic = Option.some(true)
1925 return true
1926 }
1927
1928 // Stack-safe DFS cycle detection using iterative approach
1929 const visited = new Set<NodeIndex>()
1930 const recursionStack = new Set<NodeIndex>()
1931
1932 // Stack entry: [node, neighbors, neighborIndex, isFirstVisit]
1933 type DfsStackEntry = [NodeIndex, Array<NodeIndex>, number, boolean]
1934
1935 // Get all nodes to handle disconnected components
1936 for (const startNode of graph.nodes.keys()) {
1937 if (visited.has(startNode)) {
1938 continue // Already processed this component
1939 }
1940
1941 // Iterative DFS with explicit stack
1942 const stack: Array<DfsStackEntry> = [[startNode, [], 0, true]]
1943
1944 while (stack.length > 0) {
1945 const [node, neighbors, neighborIndex, isFirstVisit] = stack[stack.length - 1]
1946

Callers 1

topoFunction · 0.85

Calls 4

getUndirectedNeighborsFunction · 0.85
neighborsDirectedFunction · 0.85
keysMethod · 0.80
addMethod · 0.65

Tested by

no test coverage detected