home *** CD-ROM | disk | FTP | other *** search
Prolog Source | 1986-05-24 | 5.9 KB | 168 lines |
- /* spanning tree program*/
- /* by Neil J. Rubenking */
- /* in TURBO PROLOG */
- /* */
- /* INPUT: A connected undirected weighted graph, expressed as facts */
- /* in the predicate "wedges" (weighted edges). The example facts are */
- /* probably supposed to be air minutes between cities. */
- /* */
- /* OUTPUT: A list of edges forming a minimal spanning tree for the */
- /* graph. This will be the smallest TREE that connects all the nodes. */
- /* So, if you wanted to run an airline that connected all the cities on */
- /* the list, but with the minimum length of routes, and with no care */
- /* to avoiding plane changes, this program will find it for you. */
-
- /* The predicate "del_dupes" may be of particular interest in any */
- /* application that needs to change a LIST of objects into a SET -- */
- /* the SET will simply be a LIST of the object w/o any duplicates. */
- /* Clocksin and Mellish demonstrate SET operations that depend on the */
- /* assumption of no duplicates. */
-
-
- domains
- vertex = symbol
- vertices = vertex* /* list of vertices */
- weight = integer
- wlist = weight*
- database
- possible(vertex, vertex, weight)
- spanning(vertex, vertex, weight)
- predicates
- wedge(vertex, vertex, weight) /* the INPUT facts */
- run
- read_wedges(vertices)
- append(vertices, vertices, vertices)
- del_dupes(vertices, vertices)
- spanning_tree(vertices, vertices)
- possible_bridges(vertices, vertices)
- member(vertex, vertices)
- member(weight, wlist)
- least(weight, wlist)
- least_bridge(weight)
- less_than_the_rest(weight, wlist)
- forget
- appendOne(vertex, vertex, vertices, vertices)
- RemoveOne(vertex, vertex, vertices, vertices)
- efface(vertex, vertices, vertices)
- head_of(vertex, vertices, vertices)
- goal
- run.
- /***************************/
- clauses
- run:-
- read_wedges([H|L]),
- spanning_tree(L,[H]),!,
- spanning(X,Y,W),
- write("Vertices: ", X," ",Y,", weight: ",W),nl,fail.
-
- read_wedges(L) :- /* Make a list of all the vertices*/
- findall(X,wedge(X,_,_),XList), /* with no duplications, based on */
- findall(Y,wedge(_,Y,_),YList), /* the input database. */
- append(XList, YList, L1),
- del_dupes(L1,L).
-
- append([],L,L). /* the ususl append predicate */
- append([X|L1],L2,[X|L3]) if
- append(L1,L2,L3).
-
- del_dupes([],[]). /* Delete duplicates from a list. */
- del_dupes([X],[X]). /* There may well be a more efficient */
- del_dupes([X|T],L):- /* way to do this! */
- member(X,T),
- del_dupes(T,L),!.
- del_dupes([X|T],L):-
- not(member(X,T)),
- del_dupes(T,L1),
- head_of(X,L1,L),!.
-
- /* The algorithm for finding a minimal spanning tree is as follows: */
- /* 1. Divide the graph into two subgraphs, one (R) containing a */
- /* single node and the other (L) containing the rest. */
- /* 2. Repeat the following until the L graph is empty: */
- /* 2a) Find the "bridge" of least weight between any node of */
- /* R and any node of L. (It can be proven that this */
- /* bridge MUST be an edge in the minimal spanning tree). */
- /* 2b) Take the vertex in L that was joined by the bridge, */
- /* remove it from L and add it to R. */
- /* 3. The set of found bridges forms the desired spanning tree. */
-
- spanning_tree([],_). /* if the list is empty, we succeed and end */
- spanning_tree(L,R) :-
- not(possible_bridges(L,R)), /* list the possible "bridges" */
- least_bridge(W), /* find the smallest */
- possible(X,Y,W), /* What edge had that weight? */
- assertz(spanning(X,Y,W)), /* Put that edge in our tree */
- not(forget), /* Forget the "possibles" list. */
- removeOne(X,Y,L,L1), /* Remove the newly used vertex */
- appendOne(X,Y,R,R1), /* from L and add it to R */
- spanning_tree(L1,R1). /* AND now do it again. */
-
- possible_bridges(L,R):- /* List the possible "bridges" between */
- member(X,L), /* the two lists of vertices -- that is */
- member(Y,R), /* all edges that connect an element of */
- wedge(X,Y,W), /* one to an element of the other. */
- assertz(possible(X,Y,W)),
- fail.
- possible_bridges(L,R):- /* Note that since possible_bridges */
- member(X,L), /* forces backtracking with "fail", it */
- member(Y,R), /* may need to be called with "not". */
- wedge(Y,X,W),
- assertz(possible(X,Y,W)),
- fail.
-
- member(X,[X|_]). /* X is a member of a list headed by X. */
- member(X,[_|T]) :- member(X,T). /* X is a member of a list if it is a */
- /* member of the TAIL of that list. */
-
- least_bridge(W):- /* Find the shortest bridge. */
- findall(X,possible(_,_,X),Xlist),
- least(W,XList).
-
- least(X,L):- /* "naive" method for finding the least */
- member(X,L), /* element of a list -- look at each */
- less_than_the_rest(X,L)./* til one is less than all the rest. */
-
- less_than_the_rest(X,[H|T]):-
- X <= H, less_than_the_rest(X,T).
- less_than_the_rest(_,[]).
-
- forget:-
- retract(possible(_,_,_)), fail. /* empty the database of possibles*/
-
- head_of(X,L,[X|L]). /* stick a single element at the head of the list*/
-
- efface(A,[A|L],L):-!.
- efface(A,[B|L],[B|M]):- efface(A,L,M). /* Remove an element from the list.*/
- /* This predicate straight from C&M*/
-
- appendOne(X,Y,Z,Znew):- /* Given the two vertices X and Y, */
- member(X,Z), /* add whichever one is not already in */
- head_of(Y,Z,ZNew). /* list Z into that list. */
- appendOne(X,Y,Z,Znew):-
- member(Y,Z),
- head_of(X,Z,ZNew).
-
- removeOne(X,_,Z,Znew):- /* Given X and Y, remove whichever */
- member(X,Z), /* of the two is present. */
- efface(X,Z,Znew).
- removeOne(_,Y,Z,Znew):-
- member(Y,Z),
- efface(Y,Z,Znew).
-
- /* here is the database of weighted edges */
-
- wedge("BOS","NY",40).
- wedge("BOS","CHI",90).
- wedge("NY","CHI",80).
- wedge("NY","PHL",30).
- wedge("NY","DC",50).
- wedge("CHI","SF",100).
- wedge("CHI","LA",120).
- wedge("CHI","KC",40).
- wedge("CHI","PHL",80).
- wedge("PHL","KC",70).
- wedge("PHL","DC",35).
- wedge("DC","ATL",60).
- wedge("SF","LA",50).
- wedge("KC","ATL",80).
- q