formal models of computation part ii the logic model
DESCRIPTION
Formal Models of Computation Part II The Logic Model. Lecture 7 – Trees and graphs. Trees. Trees are important data structures Binary trees: each node has at most two daughters Binary trees can be recursively defined as An empty tree is a binary tree (represented as “nil”) - PowerPoint PPT PresentationTRANSCRIPT
CS4026Formal Models of
ComputationPart II
The Logic ModelLecture 7 – Trees and graphs
formal models of computation 2
Trees• Trees are important data structures• Binary trees: each node has at most two
daughters• Binary trees can be recursively defined as
– An empty tree is a binary tree (represented as “nil”)
– A binary tree is a node with two subtrees• In Prolog, we can represent binary trees as
bTree(Node,SubTreeL,SubTreeR) where SubTreeL and SubTreeR are
(recursively) binary trees. • Convention for the empty tree: nil
formal models of computation 3
a
b
d
c
nil
nil nil
fe
nilnilnilnil
Trees (Cont’d)• For instance, the binary tree
• Can be represented in Prolog asbTree(a, bTree(b, bTree(d,nil,nil), bTree(e,nil,nil)), bTree(c, bTree(f,nil,nil), nil)).
Remarks:• There is nothing special
about the bTree name! We could have used “foo” or “bar” ;
• Identations are for the benefit of humans, i.e., to improve visualisation!
formal models of computation 4
Trees (Cont’d)• Let’s write a program to visit the nodes of a
binary tree in pre-order– Visit (write) parent node, then– Visit subtree on the left (using the same policy),
then– Visit subtree on the right (ditto)
• In Prolog:preOrder(nil). % empty tree?preOrder(bTree(N,L,R)):- % not empty tree? write(N), % write node N nl, % skip a line preOrder(L), % recursion on left tree preOrder(R). % recursion on right tree
formal models of computation 5
Trees (Cont’d)• Let’s alter the previous program
– Enable it to collect in a list the nodes of the tree:– This portion defines the main flow of execution
• Add an argument to hold the list to be built:
• Decide on what to do with each case…
traverse(nil). % empty tree?traverse(bTree(N,L,R)):- % not empty tree? traverse(L), % recursion on left tree traverse(R). % recursion on right tree
traverse(nil,List0).traverse(bTree(N,L,R),List1):- traverse(L,List2), traverse(R,List3).
formal models of computation 6
Trees (Cont’d)• What happens on the base (empty tree)
case?– What value should a list of nodes have when the
tree is empty? Answer: the empty list!collect(nil,List0):- % if empty tree List0 = []. % list is emptycollect(bTree(N,L,R),List1):- collect(L,List2), collect(R,List3).
formal models of computation 7
Trees (Cont’d)• What happens on the recursive case?
– We must relate N and the resulting lists of L and R
– Node N must be the head of the final resulting list
– There are two resulting lists List2 and List3 – These two lists must be combined (append!)collect(nil,List0):- % if empty tree
List0 = []. % list is emptycollect(bTree(N,L,R),List1):- List1 = [N|List4], % N is the head collect(L,List2), % get nodes of L collect(R,List3), % get nodes of R append(List2,List3,List4). % append them!
formal models of computation 8
Trees (Cont’d)• More compact:collect(nil,[]). % if empty treecollect(bTree(N,L,R),[N|Ns]):- % otherwise collect(L,LNs), % get nodes of L collect(R,RNs), % get nodes of R append(LNs,RNs,Ns). % append them!
formal models of computation 9
Trees (Cont’d)• Change program to count nodes of tree• Initial program establishes the flow of
execution– As the tree is traversed, computations can take
place!
• To compute/show results, an argument must be inserted in every goal:
traverse(nil). traverse(bTree(N,L,R)):- traverse(L), traverse(R).
count(nil,Arg1). count(bTree(N,L,R),Arg2):- count(L,Arg3), count(R,Arg4).
formal models of computation 10
Trees (Cont’d)• The inserted arguments must be
– Defined or – Related to each other
count(nil,Arg1):- define(Arg1). count(bTree(N,L,R),Arg2):- relate1(Arg2,Arg3,Arg4), count(L,Arg3), count(R,Arg4), relate2(Arg2,Arg3,Arg4).
formal models of computation 11
Trees (Cont’d)• In this specific case, we have:
• More compact:
count(nil,SNs):- SNs = 0. count(bTree(N,L,R),SNs):- count(L,SLNs), count(R,SRNs), SNs is 1 + SLNs + SRNs.
count(nil,0). % empty tree? no. nodes is 0count(bTree(N,L,R),SNs):- % otherwise count(L,SLNs), % get no nodes of left tree count(R,SRNs), % get no nodes of right tree SNs is 1 + SLNs + SRNs. % add them up plus 1
formal models of computation 12
Graphs• Graphs are a generalisation of trees:
– Nodes can have many parents and many children
– Example:
– A mathematical definition:
a b
d
c
f
e
A graph G = (N,E ) is • A set of nodes N = {a1 ,…,
an}• A set of edges E N N
formal models of computation 13
Graphs (Cont’d)• A Prolog representation for graphs
– Based on the previous mathematical definition:
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d). edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e). a b
d
c
f
e
formal models of computation 14
Graphs (Cont’d)• Let’s write a program to check for paths• A path between O and D exists iff:
– There is an edge (O,D) (i.e., a direct path) OR– There is an edge (O,I) from the origin to an
intermediate node I and there is a path from I to D
• In Prolog:path(O,D):- % there is a path between O and D edge(O,D). % if there is an edge between thempath(O,D):- % otherwise, edge(O,I), % there is an intermediary node I path(I,D). % with a path between I and D
formal models of computation 15
Graphs (Cont’d)• Execution:nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
?- path(a,e).
path(O1,D1):- edge(O1,D1).{O1/a,D1/e}
Fail!!
path(O1,D1):- edge(O1,D1).{O1/a,D1/e}
unification
Backtracks…
formal models of computation 16
Graphs (Cont’d)• Execution:nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
?- path(a,e).
path(O1,D1):- edge(O1,I1), path(I1,D1).{O1/a,D1/e}
unification
path(O1,D1):- edge(O1,I1), path(I1,D1).{O1/a,D1/e,I1/b}
path(O1,D1):- edge(O1,I1), path(I1,D1).{O1/a,D1/e,I1/b}path(b,e)
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
formal models of computation 17
Graphs (Cont’d)• Execution:nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
path(O1,D1):- edge(O1,D1).{O1/b,D1/e}
Fail!!
path(O1,D1):- edge(O1,D1).{O1/b,D1/e}
unification
path(b,e)
Backtracks…
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
formal models of computation 18
path(b,e)
Graphs (Cont’d)• Execution:nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
path(O1,D1):- edge(O1,I1), path(I1,D1).{O1/b,D1/e}
unification
path(O1,D1):- edge(O1,I1), path(I1,D1).{O1/b,D1/e,I1/c}path(O1,D1):- edge(O1,I1), path(I1,D1).{O1/a,D1/e,I1/c}
path(c,e)
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
formal models of computation 19
Graphs (Cont’d)• Execution:nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
path(O1,D1):- edge(O1,D1).{O1/c,D1/e}
path(O1,D1):- edge(O1,D1).{O1/c,D1/e}
unification
path(c,e)
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D):- edge(O,D).path(O,D):- edge(O,I), path(I,D).
?- path(a,e).yes?-
path(c,e)
formal models of computation 20
Graphs (Cont’d)• Predicate path can be used in 4 different
ways:– path(a,e): is there a path between a and e?– path(a,D): where can we get from a?– path(O,e): where can we start a journey to e?– path(O,D): all possible tours
• Problems: the previous program may loop!– If there are cycles in the path, then program
may loop forever…– We can improve the previous program to keep
track of where we’ve been and avoid loops.– Store in a list the nodes that have been visited
formal models of computation 21
Graphs (Cont’d)• Reuse previous program and add
functionality:path(O,D,Path):- % as before edge(O,D). % Path has no use herepath(O,D,Path):- % same as before edge(O,I), % get intermediate node \+ member(I,Path), % that is not already in Path path(I,D,[I|Path]). % update path and carry on
“not provable”
formal models of computation 22
Graphs (Cont’d)• Same graph with one node added: edge(b,a)
?- path(a,e,[a]).Initial value of Path
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
Loop: a-b-a!!
formal models of computation 23
Graphs (Cont’d)• Execution:
?- path(a,e,[a]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(O1,D1,_):- edge(O1,D1).{O1/a,D1/e}
Fail!!
Backtracks…
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(O1,D1,_):- edge(O1,D1).{O1/a,D1/e}
unification
formal models of computation 24
Graphs (Cont’d)• Execution:
?- path(a,e,[a]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(O1,D1,Path1):- edge(O1,I1), \+ member(I1,Path1), path(I1,D1,[I1|Path1]).{O1/a,D1/e,Path1/[a],I1/b}path(O1,D1,Path1):- edge(O1,I1), \+ member(I1,Path1), path(I1,D1,[I1|Path1]).{O1/a,D1/e,Path1/[a],I1/b}path(O1,D1,Path1):- edge(O1,I1), \+ member(I1,Path1), path(I1,D1,[I1|Path1]).{O1/a,D1/e,Path1/[a],I1/b}
path(b,e,[b,a])
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(O1,D1,Path1):- edge(O1,I1), \+ member(I1,Path1), path(I1,D1,[I1|Path1]).{O1/a,D1/e,Path1/[a]}
unification
formal models of computation 25
Graphs (Cont’d)• Execution:
path(b,e,[b,a]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/b,D2/e,Path2/[b,a]}
unification
path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/b,D2/e,Path2/[b,a],I2/a}path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/a,D2/e,Path2/[b,a],I2/a}
It fails because node a has already been visited – it is in the Path followed so far. Prolog backtracks to the previous goal and tries another edge!
path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/a,D2/e,Path2/[b,a],I2/a}
Fail!!
formal models of computation 26
Graphs (Cont’d)• Execution:
path(b,e,[b,a]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/b,D2/e,Path2/[b,a]}
unification
path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/b,D2/e,Path2/[b,a],I2/c}path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/a,D2/e,Path2/[b,a],I2/c}path(O2,D2,Path2):- edge(O2,I2), \+ member(I2,Path2), path(I2,D2,[I2|Path2]).{O2/a,D2/e,Path2/[b,a],I2/c}
path(c,e,[c,b,a])
formal models of computation 27
Graphs (Cont’d)• Execution:nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).
path(c,e,[c,b,a])
path(O3,D3,Path3):- edge(O3,I3), \+ member(I3,Path3), path(I3,D3,[I3|Path3]).{O3/c,D3/e,Path3/[c,b,a]}Computation goes on until it finally reaches destination. The path is added with each node visited thus avoiding coming back to a visited node.
nodes([a,b,c,d,e,f]).edge(a,b). edge(a,d).edge(a,f). edge(b,a). edge(b,c).edge(b,f). edge(c,e).edge(f,d). edge(f,e).
path(O,D,_):- edge(O,D).path(O,D,Path):- edge(O,I), \+ member(I,Path), path(I,D,[I|Path]).