Detect cycle in undirected graph in Ocaml - graph

Does someone has idea how to detect if there is a cycle in undirected graph in OCaml?
Here's the type I'm using for graph:
type 'a graph = { nodes : 'a list; edges : ('a * 'a * int) list }
And for example, I would like to check if this graph contains cycles:
let graph = { nodes = ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'j';];
edges = [('c', 'j', 9); ('d', 'e', 8); ('a', 'b', 8); ('b', 'c', 7); ('f', 'g', 6); ('b', 'h', 4); ('a', 'd', 4); ('g', 'h', 2); ('b', 'f', 2); ('e', 'g', 1)]}

In both directed and undirected graphs, the presence of a cycle is detected using depth first search. Roughly, you traverse a graph and if a walk contains repetitive nodes, then there is a cycle.
Commonly, an additional data structure is employed for labeling already visited nodes. For example, we can employ a set data structure (using vanilla OCaml),
module Nodes = Set.Make(struct
type t = int
let compare = compare
end)
let dfs {edges} f x =
let rec loop visited x = function
| [] -> x
| (src,dst,data) :: rest ->
let x = f src data in
let visited = Nodes.add src visited in
if Nodes.mem dst visited
then loop visited x rest
else ... in
loop Nodes.empty x edges
You can also use an imperative hash table instead of a pure functional set. There is also an algorithm, called Iterative Deepening DFS, that can traverse cyclic graphs without labeling all visited nodes, which is useful when your graph is huge (and won't fit into the memory).
Unless you're doing this for an exercise, I would suggest you using some existing Graph library in OCaml, e.g., OCamlgraph (docs) or Graphlib (docs).

It is also possible to avoid visiting the same edge twice by removing it from the list of available edges; assuming order does not matter in among edges, you can remove an edge as follows:
let edges_remove_edge edges edge =
let (src, dst, _) = edge in
let rec iter edges res = match edges with
| [] -> res
| ((s, d, _) as e)::edges ->
if (s = src && d = dst) then
res # edges
else
iter edges (e::res)
in iter edges []
Removing an edge from a graph is then done by building a new graph that shares data with the previous graph, but with a modified list of edges:
let graph_remove_edge graph edge =
{ nodes = graph.nodes;
edges = edges_remove_edge graph.edges edge }
You can then transform the graph along the recursive calls of your graph traversal; the example does nothing interesting here, it is just to demonstrate the structure:
let choose_edge graph = match graph.edges with
| [] -> None
| e::_ -> Some e;;
let rec visit graph = match (choose_edge graph) with
| None -> graph
| Some e -> visit (graph_remove_edge graph e);;
# visit graph;;
- : char graph =
{nodes = ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'j']; edges = []}
Or, you keep track of the current graph with a ref:
let visit2 graph =
let g = ref graph in
let rec v () = match (choose_edge !g) with
| None -> ()
| Some e -> begin g := graph_remove_edge !g e; v () end
in v(); !g

I managed to detect cycle by using union-find data structure.
A structure to represent a subset for union-find:
let create n =
{parent = Array.init n (fun i -> i);
rank = Array.init n (fun i -> 0)}
A utility function to find set of an element. It uses path compression technique:
let rec find uf i =
let pi = uf.parent.(i) in
if pi == i then
i
else begin
let ci = find uf pi in
uf.parent.(i) <- ci;
ci
end
A function that does union of two sets of x and y. It uses union by rank:
let union ({ parent = p; rank = r } as uf) x y =
let cx = find uf x in
let cy = find uf y in
if cx == cy then raise (Failure "Cycle detected") else begin
if r.(cx) > r.(cy) then
p.(cy) <- cx
else if r.(cx) < r.(cy) then
p.(cx) <- cy
else begin
r.(cx) <- r.(cx) + 1;
p.(cy) <- cx
end
end
I created function for checking if there is a cycle.
let thereIsCycle c1 c2 g subset =
let isCycle = try Some (union subset (findIndex c1 g.nodes) (findIndex c2 g.nodes)) with _ -> None in
match isCycle with
| Some isCycle -> false
| None -> true
let rec findIndex x lst =
match lst with
| [] -> raise (Failure "Not Found")
| h :: t -> if x = h then 0 else 1 + findIndex x t

Related

Functional Pattern to check Connect 4 board for winner

I want to learn some functional style programming, so I want to write a littel Connect 4 engine.
Given a board I want to determine if a player has won in that board state, so I need a function
let winner (board : Board) : Player option = ???
'Usually' one could simply loop through the rows, the columns, and the diagonals, and as soon as we find a winner we return whoever we found and 'break out'. I'm not sure if something like that is even possible in F#.
In my current implementation I am using a helper function which takes a list of board cells and checks if there are four consecutive cells belonging to PlayerA or PlayerB. It returns a Player option type.
Then in my main 'winner' function I check if there is a winner in the rows, if yes, return that Player, if None, check the columns, etc.
So basically I am doing a lot of matching and stuff, and it seems to me like this should be easier to do with some kind of bind, but I wouldn't know how.
So how would one approach this problem in functional style?
EDIT: Some Code Snippets
These are my basic types
type Player =
| PlayerA
| PlayerB
type Cell =
| Empty
| Occupied of Player
type Board = Cell [] list
// Cell [] [] would probably be better, but some things were easier when I could use pattern matching x :: xs for lists
Here are some helper functions. This already seems like too much.
let rec getFours (l: 'a list):'a list list =
if List.length l < 4 then
[[]]
elif List.length l = 4 then
[l]
else
match l with
| [] -> [[]]
| x::xs -> [[x;l.[1];l.[2];l.[3]]] # getFours xs
let quadToPlayer quad=
if List.forall (fun x -> x = Occupied PlayerA) quad then
Some PlayerA
elif List.forall (fun x -> x = Occupied PlayerB) quad then
Some PlayerB
else
None
let rowWinnerHelper (row : Cell []) : Player option=
if Array.length row <4 then
None
else
let possibleWinners = getFours (List.ofArray row) |> List.map quadToPlayer
if List.exists (fun x -> x = Some PlayerA) possibleWinners then
Some PlayerA
elif List.exists (fun x -> x = Some PlayerB) possibleWinners then
Some PlayerB
else
None
let rowWinner (board:Board) : Player option =
let rowWinners = List.map rowWinnerHelper board
if List.exists (fun x -> x = Some PlayerA) rowWinners then
Some PlayerA
elif List.exists (fun x -> x = Some PlayerB) rowWinners then
Some PlayerB
else
None
What I don't like for example is that I am computing possible winners for all rows and all quadruples in each row etc. Instead of just stopping once I found the first winning Player.
Your could improve your getFours by computing if it's a win immediately rather than building lists.
let rec getFours player (l: 'a list): bool =
if List.length l < 4 then
false
elif List.length l = 4 then
quadToPlayer player l
else
match l with
| [] -> false
| x::xs -> (quadToPlayer player [x; l.[1];l.[2];l.[3]]) || (getFours xs)
let quadToPlayer player quad =
List.forall (fun x -> x = Occupied player) quad
Alternatively, if you have a fixed board size you can then precompute winning patterns and you can bitmask against them. This will increase significantly the performance.
Encode each players moves into a bit array (each) maybe using long type depending on the size of your board. The example below is for tic-tac-toe.
let white,black = board
let winningPatterns =
[
0b111000000; // horizontal
0b000111000;
0b000000111;
0b100100100; // vertical
0b010010010;
0b001001001;
0b100010001; // diagonal
0b001010100 ]
let whiteWin = winningPatterns
|> Seq.map( fun p -> white &&& p = p )
|> Seq.reduce (||)
let blackWin = winningPatterns
|> Seq.map( fun p -> black &&& p = p )
|> Seq.reduce (||)
There is an Elm implementation of Connect 4 here.
Following ideas from there, I learned that fold does the trick, as it can just keep track how many consecutive pieces by one player we have seen.
let arrayWinner (row:Cell []) (player:Player) =
Array.fold (fun count p->
if count = 4 then
4
elif p = Occupied player then
count + 1
else
0
) 0 row
|> (=) 4
This can then be used in an 'exists'-check
let arrayOfArrayWinner (board:Cell [] []) (player:Player) =
Array.exists (fun arr -> arrayWinner arr player) board
This bit of code accomplishes basically the same as the code snippet in the question.

How to collapse a recursive tree in OCaml

I have a tree type:
type tree = Vertex of int * tree list;;
My recursive equality definition is that two trees are equal if their ints are equal and all of their children are equal.
How do I build the function
topo: tree -> tree list
that creates a list of all of the trees in depth first search order with each tree appearing once and only once (according to the equality definition)? I want to do this in a computationally efficient way. Maybe use lazy or a hashmap?
Here is my attempt, the code blows up when the length is too large:
type tree = Vertex of int * (tree list)
let rec base = function
| 0 -> Vertex (0, [])
| i -> Vertex (i, [base (i - 1)])
let rec range = function
| 0 -> [0]
| i -> i :: range (i - 1)
let agg i = Vertex (-1, List.map base (range i))
let rec equals (a: tree) (b: tree) : bool =
let rec deep_match a_dep b_dep = match a_dep, b_dep with
| [], [] -> true
| [], _
| _, [] -> false
| x::xs, y::ys -> equals x y && deep_match xs ys
in
let Vertex (ai, al) = a in
let Vertex (bi, bl) = b in
ai = bi && deep_match al bl
let rec in_list (a: tree) (l: tree list) : bool = match l with
| [] -> false
| hd::tl -> equals a hd || in_list a tl
let rec topological (pool: tree list) (t: tree) : tree list =
if in_list t pool then pool else
t::match t with
| Vertex(_, []) -> pool
| Vertex(_, deps) -> List.fold_left topological pool deps
let big_agg = agg 100_000
let topo_ordered = topological [] big_agg;;
Printf.printf "len %i\n" (List.length topo_ordered)
To make it efficient you need to implement ordering and hash-consing. With total ordering, you can store your trees in a balanced tree or even a hashtable, thus turning your in_list into O(logN) or even O(1). Adding hash-consing will enable O(1) comparison of your trees (at the cost of less efficient tree construction).
Instead of having both, depending on your design constraints, you can have only one. For the didactic purposes, let's implement hash-consing for your particular representation
To implement hash-consing you need to make your constructor private and hide data constructors behind an abstraction wall (to prevent users from breaking you hash-consing properties):
module Tree : sig
type t = private Vertex of int * t list
val create : int -> t list -> t
val equal : t -> t -> bool
end = struct
type t = Vertex of int * t list
let repository = Hashtbl.create 64
let create n children =
let node = Vertex (n,children) in
try Hashtbl.find repository node
with Not_found -> Hashtbl.add repository node node; node
let equal x y = x == y
end
Since we guaranteed that structurally equal trees are physically equal during the tree creation (i.e., if there exists an equal tree in our repository then we return it), we are now able to substitute structural equality with physical equality, i.e., with pointer comparison.
We got a fast comparison with the price - we now leaking memory, since we need to store all ever created trees and the create function is now O(N). We can alleviate the first problem by using ephemerons, but the latter problem will persist, of course.
Another issue, is that we're not able to put our trees into ordered structure, like a map or a set. We can of course use regular polymorphic compare, but since it will be O(N), inserting to such structure will become quadratic. Not an option for us. Therefore we need to add total ordering on our trees. We can theoretically do this without changing the representation (using ephemerons), but it is easier just to add an order parameter to our tree representation, e.g.,
module Tree : sig
type order (* = private int *) (* add this for debuggin *)
type t = private Vertex of order * int * t list
val create : int -> t list -> t
val equal : t -> t -> bool
val compare : t -> t -> int
end = struct
type order = int
type t = Vertex of order * int * t list
type tree = t
module Repository = Hashtbl.Make(struct
type t = tree
let max_hash = 16
let rec equal (Vertex (_,p1,x)) (Vertex (_,p2,y)) =
match compare p1 p2 with
| 0 -> equal_trees x y
| n -> false
and equal_trees xs ys = match xs, ys with
| [],[] -> true
| [],_ | _,[] -> false
| x :: xs, y::ys -> equal x y && equal_trees xs ys
let rec hash (Vertex (_,p,xs)) =
hash_trees (Hashtbl.hash p) max_hash xs
and hash_trees hash depth = function
| x :: xs when depth > 0 ->
hash_trees (Hashtbl.hash x) (depth-1) xs
| _ -> hash
end)
let repository = Repository.create 64
let create n children =
try Repository.find repository (Vertex (0,n,children))
with Not_found ->
let order = Repository.length repository + 1 in
let node = Vertex (order,n,children) in
Repository.add repository node node; node
let equal x y = x == y
let order (Vertex (order,_,_)) = order
let compare x y = compare (order x) (order y)
end
We had to manually implement the structural variants of equal and hash for our trees because we need to ignore the order in comparison, when we store a new tree in the repository. It looks like a bit of work, but in the real-life you can do this using derivers.
Anyways, now we got a comparable version of a tree with a comparison function which is O(1), so we can put our trees in sets and maps, and implement your topo efficiently.
A nice feature of both implementations is a tight representation of a tree, since sharing is guaranteed by the create function. E.g.,
# let t1 = Tree.create 42 [];;
val t1 : Tree.t = Tree.Vertex (1, 42, [])
# let t3 = Tree.create 42 [t1; t1];;
val t3 : Tree.t =
Tree.Vertex (2, 42, [Tree.Vertex (1, 42, []); Tree.Vertex (1, 42, [])])
# let t5 = Tree.create 42 [t1; t3; t1];;
val t5 : Tree.t =
Tree.Vertex (3, 42,
[Tree.Vertex (1, 42, []);
Tree.Vertex (2, 42, [Tree.Vertex (1, 42, []); Tree.Vertex (1, 42, [])]);
Tree.Vertex (1, 42, [])])
#
In this example, t1 in t5 and t3 will be the same pointer.
For optimal performance, one possibility would be to use hashconsing. However, in your current example, both the generation and the unicity test are quadratic in n. Fixing both points seems to already improve performance a lot.
First, we can avoid the quadratic tree generation by adding a lot of sharing:
let range max =
let rec range elt l n =
if n > max then elt::l
else
let next = Vertex(n,[elt]) in
range next (elt::l) (n+1) in
range (Vertex(0,[])) [] 1
let agg i = Vertex (-1, range i)
With this change, it is become reasonable to generate a tree with 1010 elements (but only 105 unique elements).
Then, the unicity test can be done with a set (or a hashtable):
module S = Set.Make(struct type t = tree let compare = compare end)
let rec topological (set, pool) t =
if S.mem t set then (set, pool) else
let set = S.add t set in
let set, pool =
match t with
| Vertex(_, []) -> set, pool
| Vertex(_, deps) -> List.fold_left topological (set,pool) deps in
set, t::pool

create a register

I have to create a type tree which would be used to store words, like every node of the tree would hold a letter and the list of the next characters (so words with the same root would share the same "part/branch of the tree). the tree is basically a n-ary one, used as a dictionnary.
All using Caml language
Well, I don't know if it's a homework or not but I'll still answer :
First, we need to define a signature type for letters.
module type LS = sig
type t
val compare : t -> t -> int
end
Then, we need to define our structure :
module Make (L : LS) = struct
module M = Map.Make(L)
type elt = L.t list
type t = { word : bool; branches : t M.t }
let empty = { word = false; branches = M.empty }
let is_empty t = not t.word && M.is_empty t.branches
let rec mem x t =
match x with
| [] -> t.word
| c :: cl -> try mem cl (M.find c t.branches)
with Not_found -> false
let rec add x t =
match x with
| [] -> if t.word then t else { t with word = true }
| c :: cl ->
let b = try M.find c t.branches with Not_found -> empty in
{ t with branches = M.add c (add cl b) t.branches }
end
Now, step by step :
module Make (L : LS) = struct is a functor that will return a new module if we give it a module of type LS as an argument
module M = Map.Make(L)
type elt = L.t list
type t = { word : bool; branches : t M.t }
This is the complex point, once you have it, everything begins clear. We need to represent a node (as you can see in the Wikipedia page of tries). My representation is this : a node is
a truth value stating that this node represent a word (which means that all the letters from the root to this node form a word)
the branches that goes from it. To represent this branches, I need a dictionary and luckily there's a Map functor in OCaml. So, my field branches is a field associating to some letters a trie (which is why I wrote that branches : t M.t). An element is then a list of letters and you'll find out why I chose this type rather than a string.
let empty = { word = false; branches = M.empty } the empty trie is the record with no branches (so, just the root), and this root is not a word (so word = false) (same idea for is_empty)
let rec mem x t =
match x with
| [] -> t.word
| c :: cl -> try mem cl (M.find c t.branches)
with Not_found -> false
Here it becomes interesting. My word being a list of letters, if I want to know if a word is in my trie, I need to make a recursive functions going through this list.
If I reached the point where my list is empty it means that I reached a node where the path from the root to it is composed by all the letters of my word. I just need to know, then, if the value word at this node is true or false.
If I still have at least one letter I need to find the branch corresponding to this letter.
If I find this branch (which will be a trie), I just need to make a recursive call to find the rest of the word (cl) in it
If I don't find it I know that my word doesn't exist in my trie so I can return false.
let rec add x t =
match x with
| [] -> if t.word then t else { t with word = true }
| c :: cl ->
let b = try M.find c t.branches with Not_found -> empty in
{ t with branches = M.add c (add cl b) t.branches }
Same idea. If I want to add a word :
If my list is empty it means that I added all the letters and I've reached the node corresponding to my word. In that case, if word is already true it means that this word was already added, I don't do anything. If word is false I just return the same branch (trie) but with word equal to true.
If my list contains at least a letter c, I find in the current node the branch corresponding to it (try M.find c t.branches with Not_found -> empty) and I there's no such branch, I just return an empty one and then I recursively add the rest of my letters to this branch and add this new branch to the branches of my current node associated to the letter c (if this branch already existed, it will be replaced since I use a dictionary)
Here, we start with the empty trie and we add the word to, top and tea.
In case we don't want to use functors, we can do it this way :
type elt = char list
type t = { word : bool; branches : (char * t) list }
let empty = { word = false; branches = [] }
let is_empty t = not t.word && t.branches = []
let find c l =
let rec aux = function
| [] -> raise Not_found
| (c', t) :: tl when c' = c -> t
| _ :: tl -> aux tl
in aux l
let rec mem x t =
match x with
| [] -> t.word
| c :: cl -> try mem cl (find c t.branches)
with Not_found -> false
let rec add x t =
match x with
| [] -> if t.word then t else { t with word = true }
| c :: cl ->
let b = try find c t.branches with Not_found -> empty in
{ t with branches = (c, (add cl b)) :: t.branches }

Grabbing a list of nodes in a tree?

How would you go about grabbing a list of nodes from a tree structure that meet a certain criteria using ocaml? Since everything's created anew, there's no saved data structure. Any type of function that tries to return a list could only return one element when it hits a node, not a list.
Here's a tree type:
type tree = Leaf of int | Node of int * tree * tree
Here's a function that returns all the even values from the nodes of a tree:
let evens t =
let rec go sofar = function
| Leaf k -> if k mod 2 = 0 then k :: sofar else sofar
| Node (k, lt, rt) ->
let sofar' = if k mod 2 = 0 then k :: sofar else sofar in
let sofar'' = go sofar' lt in
go sofar'' rt
in
go [] t

Graph with sets as vertices

I have a tiny grammar represented as a variant type term with strings that are tokens/part of tokens (type term).
Given expressions from the grammar, I am collecting all strings from expressions and pack them into sets (function vars). Finally, I want to create some graph with these sets as vertices (lines 48-49).
For some reason, the graph created in the such sophisticated way does not recognise sets containing same variables and creates multiple vertices with the same content. I don't really understand why this is happening.
Here is minimal working example with this behaviour:
(* demo.ml *)
type term =
| Var of string
| List of term list * string option
| Tuple of term list
module SSet = Set.Make(
struct
let compare = String.compare
type t = string
end)
let rec vars = function
| Var v -> SSet.singleton v
| List (x, tail) ->
let tl = match tail with
| None -> SSet.empty
| Some var -> SSet.singleton var in
SSet.union tl (List.fold_left SSet.union SSet.empty (List.map vars x))
| Tuple x -> List.fold_left SSet.union SSet.empty (List.map vars x)
module Node = struct
type t = SSet.t
let compare = SSet.compare
let equal = SSet.equal
let hash = Hashtbl.hash
end
module G = Graph.Imperative.Digraph.ConcreteBidirectional(Node)
(* dot output for the graph for illustration purposes *)
module Dot = Graph.Graphviz.Dot(struct
include G
let edge_attributes _ = []
let default_edge_attributes _ = []
let get_subgraph _ = None
let vertex_attributes _ = []
let vertex_name v = Printf.sprintf "{%s}" (String.concat ", " (SSet.elements v))
let default_vertex_attributes _ = []
let graph_attributes _ = []
end)
let _ =
(* creation of two terms *)
let a, b = List ([Var "a"], Some "b"), Tuple [Var "a"; Var "b"] in
(* get strings from terms packed into sets *)
let avars, bvars = vars a, vars b in
let g = G.create () in
G.add_edge g avars bvars;
Printf.printf "The content is the same: [%s] [%s]\n"
(String.concat ", " (SSet.elements avars))
(String.concat ", " (SSet.elements bvars));
Printf.printf "compare/equal output: %d %b\n"
(SSet.compare avars bvars)
(SSet.equal avars bvars);
Printf.printf "Hash values are different: %d %d\n"
(Hashtbl.hash avars) (Hashtbl.hash bvars);
Dot.fprint_graph Format.str_formatter g;
Printf.printf "Graph representation:\n%s" (Format.flush_str_formatter ())
In order to compile, type ocamlc -c -I +ocamlgraph demo.ml; ocamlc -I +ocamlgraph graph.cma demo.cmo. When the program is executed you get this output:
The content is the same: [a, b] [a, b]
compare/equal output: 0 true
Hash values are different: 814436103 1017954833
Graph representation:
digraph G {
{a, b};
{a, b};
{a, b} -> {a, b};
{a, b} -> {a, b};
}
To sum up, I am curious why there are non-equal hash values for sets and two identical vertices are created in the graph, despite the fact these sets are equal by all other means.
I suspect the general answer is that OCaml's built-in hashing is based on rather physical properties of a value, while set equality is a more abstract notion. If you represent sets as ordered binary trees, there are many trees that represent the same set (as is well known). These will be equal as sets but might very well hash to different values.
If you want hashing to work for sets, you might have to supply your own function.
As Jeffrey pointed out, it seems that the problem is in the definition of the hash function that is part of Node module.
Changing it to let hash x = Hashtbl.hash (SSet.elements x) fixed the issue.

Resources