What is the general idea of using breadth-first over the default depth-first search scheme in Prolog?
Not taking infinite branches?
Is there any general way to use breadth-first in Prolog? I've been googling around and I didn't find too much useful info for a novice.
The advantage of breadth-first is that you will find all solutions. With depth-first you can become stuck in an infinite branch.
The disadvantage is that breadth-first uses a lot of memory, therefore it is not used generally for execution.
If you want to use it you'll need to implement it explicitly with some kind of queue.
Edit: If you want to have the advantages of breadth-first search without using much memory you can use iterative deepening. This is depth-first search with a depth-bound, which you increase successively. This causes some duplicate computation, but if your search space doesn't have long linear stretches without branching then this duplication is small.
There is something I got to know as "agenda search". While traversing the tree (of data, relations, rules, ...) you maintain an "agenda" (a list) of what to do next. When you enter a node you put its children on the agenda, and then continue with the first element of the agenda, which you pop. This way, if you put new items at the end of the agenda, you get breadth-first. If you put them in front of the agenda, you get depth-first.
It's easy to implement with Prolog.
EDIT: I might just as well give an implementation hint here. This is a very basic implementation of the agenda search algorithm.
agenda_search([N|T],Mode):-
doWithNode(N), % do whatever you do the searching for
getNodeChildren(N,C),
(Mode=bf -> % bf or df (depth-first)
append(T,C,A);
append(C,T,A)),
agenda_search(A,Mode).
It relies on external predicates doWithNode
that stands for the action you want to perform with each node (e.g. compare node data to a search term, serialize node content, asf.). And getNodeChildren
that will bind the list of children of the given node to C
(I.e. this predicate actually knows the tree structure and how to find child nodes). Of course the doWithNode
predicate might need additional parameters to do its job, which would also show up in the argument list of agenda_search
.
You can invoke it like this:
agenda_search([RootNode], bf) % for breadth-first search
and
agenda_search([RootNode], df) % for depth-first search
I've also found a bit of explanation of the agenda search on this web page. The nice thing with agenda search is that you can easily switch between the two variants df and bf and play with the results. The algorithm is quite well-behaved memory-wise, as the agenda, the nodes still to explore, only captures a (more or less) small fraction of nodes in the tree at any one time (the so called fringe).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With