|
|
|
|
@ -23,41 +23,6 @@ instance : EmptyCollection (Graph α β) := ⟨default⟩
|
|
|
|
|
def Graph.insertNode (g : Graph α β) (a : α) (b : β) :=
|
|
|
|
|
{g with nodes := g.nodes.insert a b}
|
|
|
|
|
|
|
|
|
|
/-- Check if graph contains loops -/
|
|
|
|
|
partial def Graph.hasLoops (g : Graph α β) (visited0 : HashSet α := {}): Bool := Id.run do
|
|
|
|
|
let mut visited : HashSet α := visited0
|
|
|
|
|
let all : Array α := g.nodes.toArray.map (·.1)
|
|
|
|
|
|
|
|
|
|
-- find some node that we haven't visited
|
|
|
|
|
let some x := all.find? fun x => ¬ visited.contains x
|
|
|
|
|
| return false -- We have visted all nodes and found no loops
|
|
|
|
|
visited := visited.insert x
|
|
|
|
|
|
|
|
|
|
match visitSuccessors x x visited with -- visit all recursive successors of x
|
|
|
|
|
| some visited' => visited := visited'
|
|
|
|
|
| none => return true -- none means a loop has been found
|
|
|
|
|
|
|
|
|
|
g.hasLoops visited -- continue looking for unvisited nodes
|
|
|
|
|
|
|
|
|
|
where
|
|
|
|
|
visitSuccessors (x : α) (x0 : α) (visited0 : HashSet α) : Option (HashSet α) := Id.run do
|
|
|
|
|
let mut visited : HashSet α := visited0
|
|
|
|
|
|
|
|
|
|
let directSuccessors := (g.edges.filter (·.1 == x)).map (·.2)
|
|
|
|
|
for y in directSuccessors do
|
|
|
|
|
if y == x0 then
|
|
|
|
|
return none -- loop found
|
|
|
|
|
if visited.contains y then
|
|
|
|
|
continue -- no loop possible here because the visited nodes do not lead to x0
|
|
|
|
|
visited := visited.insert y
|
|
|
|
|
match visitSuccessors y x0 visited with
|
|
|
|
|
| some visited' => visited := visited'
|
|
|
|
|
| none => return none
|
|
|
|
|
|
|
|
|
|
return some visited
|
|
|
|
|
|
|
|
|
|
-- #eval Graph.hasLoops ⟨HashMap.ofList [(2,2), (1,1)], #[(2,1)]⟩
|
|
|
|
|
|
|
|
|
|
partial def Graph.predecessors (g : Graph α β) (x : α) (acc : HashSet α := {}) : HashSet α := Id.run do
|
|
|
|
|
let mut res := acc
|
|
|
|
|
let directPredecessors := (g.edges.filter (·.2 == x)).map (·.1)
|
|
|
|
|
|