Shortest-path in a grid using prolog - prolog

Sorry by the first ask, I'm new at the hood... I did a cleaning on the code. The problem is:
I have a square grid with paths and obstacles. I want to find the shortest path from a point to another. This is part of an artificial intelligence. When the path is too large, I can not see the whole list of points on the bash, but in the game, the character who travels this path, it does not at shortest path. So, my question is, how I can change this code to solve the shortest path. Thank you so much!
mov(X1,Y1,X2,Y2):-
pos(X1,Y1), X2 is X1 , Y2 is Y1+1 ,pos(X2,Y2).
mov(X1,Y1,X2,Y2):-
pos(X1,Y1), X2 is X1 , Y2 is Y1-1 ,pos(X2,Y2).
mov(X1,Y1,X2,Y2):-
pos(X1,Y1), X2 is X1+1 , Y2 is Y1 , pos(X2,Y2).
mov(X1,Y1,X2,Y2):-
pos(X1,Y1), X2 is X1 -1 , Y2 is Y1 , pos(X2,Y2).
path(X1,Y1,X2,Y2,Path) :-
travel(pos(X1,Y1),pos(X2,Y2),[pos(X1,Y1)],Q),
reverse(Q,Path).
travel(pos(X1,Y1),pos(X2,Y2),P,[pos(X2,Y2)|P]) :-
mov(X1,Y1,X2,Y2).
travel(pos(X1,Y1),pos(X2,Y2),Visited,Path) :-
mov(X1,Y1,X,Y),
pos(X,Y) \== pos(X2,Y2),
\+member(pos(X,Y),Visited),
travel(pos(X,Y),pos(X2,Y2),[pos(X,Y)|Visited],Path).

First some Prolog advice.
member/2 is a built-in, you should not have to define it.
ISO negation is \+, not not/1.
For performance, memberchk/2 beats member/2.
I see a lot of foo(X,Y) :- X == Y, ... in your code. It's much better if you just say foo(X,X) and save yourself the trouble of making explicit tests like this, unless you're going to do a conditional expression to avoid a choice point or something.
Lots of cuts in this code. Cuts and bugs tend to be great friends because the cut can undermine reasonable-looking code by preventing it from being executed.
If I had to solve this problem, I would want to separate the shortest-path logic from the grid traversal logic. You'll never be able to debug this, and even if you do, what you'll have is a one of those unreadable blocks of code that cannot be modified. It's clear that you have an explosion of terms because you're embedding the traversal logic in the path finding logic. Break them out into two separate steps and you will probably find that you get smaller pieces you can meaningfully test and debug. This is a good way of life with programming, regardless of the language: what would you do if you needed to change the grid structure or make the pathfinding more intelligent or complex? Keeping pieces granular always helps for managing change.
As for S.O. etiquette, this isn't great: you should talk about what doesn't work and what you've tried and you want to supply a minimum, complete, verifiable example. I suspect in producing such a thing you'd probably solve the problem yourself.

Related

What does this program in Prolog do?

What is the purpose of this:
route(Town1,Town2,Distance):-
road(Town1,Town2,Distance).
Also, what does ! mean in this context? If someone knows exactly what it means, because all I hear is "cut" without any other explanation.
%TRAVELLING SALESMAN PROBLEM
DOMAINS
town = symbol
distance = integer
PREDICATES
nondeterm road(town,town,distance)
nondeterm route(town,town,distance)
CLAUSES
road("tampa","houston",200).
road("gordon","tampa",300).
road("houston","gordon",100).
road("houston","kansas_city",120).
road("gordon","kansas_city",130).
route(Town1,Town2,Distance):-
road(Town1,Town2,Distance).
route(Town1,Town2,Distance):-
road(Town1,X,Dist1),
route(X,Town2,Dist2),
Distance=Dist1+Dist2, !.
GOAL
route("tampa", "kansas_city", X),
write("Distance from Tampa to Kansas City is ",X),nl.
Prolog programs use recursion heavily, which is why you need a base case for the recursion to stop. Here:
route(Town1,Town2,Distance):-
road(Town1,Town2,Distance).
We're saying "If there's a direct road between Town1 and Town2, then we're done, no need to check for a route through any other town because this is a route, just give me the distance." In other words, we are saying "If there is a defined clause that matches the first two arguments, what must Distance be to fully match it?"
The ! is the cut/1 predicate. It stops backtracking. Here it is, described more thoroughly:
Sometimes it is desirable to selectively turn off backtracking. Prolog provides a predicate that performs this function. It is called the cut/1, represented by an exclamation point (!).
The cut/1 effectively tells Prolog to freeze all the decisions made so far in this predicate. That is, if required to backtrack, it will automatically fail without trying other alternatives.
In the case of your code:
route(Town1,Town2,Distance):-
road(Town1,X,Dist1),
route(X,Town2,Dist2),
Distance=Dist1+Dist2, !.
You are telling Prolog that, if you find a road between Town1 and Town X, and then from Town X there is a route to finish of the path between Town1 and Town2, then recurse; if there is a direct road between X and Town2, then the predicate at the top of your question holds. If not, it will recursively loop. Eventually, Dist2 will have a final value which will float back up to this predicate.
This is where ! comes in. Once you have a route that holds, it says "Stop, don't try and find another route, I only want 1 route. Don't backtrack for any other possible routes." Otherwise, you'd get multiple write("Distance from Tampa to Kansas City is ",X),nl. with different X values, which might not have made sense to the author of this program.
Also, as #DavidTonhofer says, the = should be replaced with is as the latter will force arithmetic evaluation. For example X = 2+4 compares X to the unevaluated expression 2+4, but with is you'll be comparing X to 6.

Why does it say my predicate block/3 is not called?

So I've been learning Prolog, and to test myself I wanted to solve a certain puzzle. I think I'm pretty close to solving it, but I seem to be doing something wrong. It seems my predicate block/3 is not called.
maybe it's a syntax error, or I'm doing something that doesn't work in Prolog. I can't see it.
block/3 is supposed to give all possible combinations of sets in block/2.
I'm not sure if it's entirely relevant but I'll include the goal of the puzzle:
There's four cubes, with different combination of four images on their faces. (Kim,Lab,Hail and Com)
The goal is to align the cubes in such a way that if you put them together, all the sides next to each other should be the same. So it's four of the same rows going around each cube, and then two sides that should also be matching.
I wrote the program to just solve the rows, and disregarding the orientation of the images and the two sides. Should that give more than one answer it shouldn't give too many to manually try.
anyway, somehow solve(X) completely ignores my predicate block/3. I've been staring at it for a long time and I can't find the issue.
member( block(1, _, Row), X )
is equivalent to
E = block(1, _, Row), member( E, X )
so it does not in fact call block/3 as a predicate, it just uses it as a compound term, symbolically.

Asserting all different possibilities

I have this code which asserts fact based on lists of other facts, however I have difficulty doing 2 things:
First, I want it to assert all the different possible facts.
Second, I want it to be able to use lists of variable lengths. The code I have only works if the lists are exactly 2 and 4 of length, which works for testing but will not work in practice.
assert_test([Fact], [Z,Z2], [Y, Y2, Y3, Y4]) :-
Z,
Z2,
Y,
Y2,
Y3,
Y4,
assertz(Fact).
I really have no clue as to what kind of solution I need for my problems, I would really appreciate any pointer that could help me in the right direction.
This question isn't very clear, but it seems like you want to (a) call a number of goals passed in as a list, then (b) assert all those goals. I will answer under the assumption that this is true, although this operation as written is almost certainly not useful.
To call some variable V, you can just put V as a goal in your rule body, as you did, or you can apply the call/1 predicate to it, i.e., write call(V). Thus, to call a list of goals, you can do maplist(call, Goals).
Similarly, to assert a list of goals, you can do maplist(assertz, Goals).
So overall, here is one way of doing what you might want:
test_assert(Goals) :-
maplist(call, Goals),
maplist(assertz, Goals).
This applies to a list Goals of any length.
If your Prolog doesn't have an implementation of maplist/2 or you don't want to use it, you might instead write a recursive solution, something like:
test_assert([]).
test_assert([Goal|Goals]) :-
call(Goal),
assertz(Goal),
test_assert(Goals).
(None of this is tested.) Note that this interleaves the call and assert operations, so they are performed in a different order than in the approach using maplist/2.

Hierarchical Agglomerative Clustering in Prolog

I'm trying to re-familiarize myself with Prolog and I thought this could be the type of problem with an elegant solution in Prolog.
I'm following along this example:
http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/hierarchical.html
I've tried a variety of data formats:
dist('BA','FI',662).
dist(0,'BA','FI',662).
dist(['BA'],['FI'],662).
but I haven't found any particular one most suitable.
Here's all the data in the first format:
%% Graph distances
dist('BA','FI',662).
dist('BA','MI',877).
dist('BA','NA',255).
dist('BA','RM',412).
dist('BA','TO',996).
dist('FI','MI',295).
dist('FI','NA',468).
dist('FI','RM',268).
dist('FI','TO',400).
dist('MI','NA',754).
dist('MI','RM',564).
dist('MI','TO',138).
dist('NA','RM',219).
dist('NA','TO',869).
dist('RM','TO',669).
Now, there seems to be some awesome structure to this problem to exploit, but I'm really struggling to get a grasp of it. I think I've got the first cluster here (thought it may not be the most elegant way of doing it ;)
minDist(A,B,D) :- dist(A,B,D), dist(X,Y,Z), A \= X, A \= Y, B \= X, B \= Y, D < Z.
min(A,B,B) :- B < A
min(A,B,A) :- A < B
dist([A,B],C, D) :- minDist(A,B,D), dist(A,C,Q), dist(B,C,W), min(Q,W,D)
The problem I have here is the concept of "replacing" the dist statements involving A and B with the cluster.
This just quickly become a brainteaser for me and I'm stuck. Any ideas on how to formulate this? Or is this perhaps just not the kind of problem elegantly solved with Prolog?
Your table is actually perfect! The problem is that you don't have an intermediate data structure. I'm guessing you'll find the following code pretty surprising. In Prolog, you can simply use whatever structures you want, and it will actually work. First let's get the preliminary we need for calculating distance without regard for argument order:
distance(X, Y, Dist) :- dist(X, Y, Dist) ; dist(Y, X, Dist).
This just swaps the order if it doesn't get a distance on the first try.
Another utility we'll need: the list of cities:
all_cities(['BA','FI','MI','NA','RM','TO']).
This is just helpful; we could compute it, but it would be tedious and weird looking.
OK, so the end of the linked article makes it clear that what is actually being created is a tree structure. The article doesn't show you the tree at all until you get to the end, so it isn't obvious that's what's going on in the merges. In Prolog, we can simply use the structure we want and there it is, and it will work. To demonstrate, let's enumerate the items in a tree with something like member/2 for lists:
% Our clustering forms a tree. So we need to be able to do some basic
% operations on the tree, like get all of the cities in the tree. This
% predicate shows how that is done, and shows what the structure of
% the cluster is going to look like.
cluster_member(X, leaf(X)).
cluster_member(X, cluster(Left, Right)) :-
cluster_member(X, Left) ; cluster_member(X, Right).
So you can see we're going to be making use of trees using leaf('FI') for instance, to represent a leaf-node, a cluster of N=1, and cluster(X,Y) to represent a cluster tree with two branches. The code above lets you enumerate all the cities within a cluster, which we'll need to compute the minimum distance between them.
% To calculate the minimum distance between two cluster positions we
% need to basically pair up each city from each side of the cluster
% and find the minimum.
cluster_distance(X, Y, Distance) :-
setof(D,
XCity^YCity^(
cluster_member(XCity, X),
cluster_member(YCity, Y),
distance(XCity, YCity, D)),
[Distance|_]).
This probably looks pretty weird. I'm cheating here. The setof/3 metapredicate finds solutions for a particular goal. The calling pattern is something like setof(Template, Goal, Result) where the Result will become a list of Template for each Goal success. This is just like bagof/3 except that setof/3 gives you unique results. How does it do that? By sorting! My third argument is [Distance|_], saying just give me the first item in the result list. Because the result is sorted, the first item in the list will be the smallest. It's a big cheat!
The XCity^YCity^ notation says to setof/3: I don't care what these variables actually are. It marks them as "existential variables." This means Prolog will not provide multiple solutions for each city combination; they will all be thrown together and sorted once.
This is all we need to perform the clustering!
From the article, the base case is when you have two clusters left: just combine them:
% OK, the base case for clustering is that we have two items left, so
% we cluster them together.
cluster([Left,Right], cluster(Left,Right)).
The inductive case takes the list of results and finds the two which are nearest and combines them. Hold on!
% The inductive case is: pair up each cluster and find the minimum distance.
cluster(CityClusters, FinalCityClusters) :-
CityClusters = [_,_,_|_], % ensure we have >2 clusters
setof(result(D, cluster(N1,N2), CC2),
CC1^(select(N1, CityClusters, CC1),
select(N2, CC1, CC2),
cluster_distance(N1, N2, D)),
[result(_, NewCluster, Remainder)|_]),
cluster([NewCluster|Remainder], FinalCityClusters).
Prolog's built-in sorting is to sort a structure on the first argument. We cheat again here by creating a new structure, result/3, which will contain the distance, the cluster with that distance, and the remaining items to be considered. select/3 is extremely handy. It works by pulling an item out of the list and then giving you back the list without that item. We use it twice here to select two items from the list (I don't have to worry about comparing a place to itself as a result!). CC1 is marked as a free variable. The result structures will be created for considering each possible cluster with the items we were given. Again, setof/3 will sort the list to make it unique, so the first item in the list will happen to be the one with the shortest distance. It's a lot of work for one setof/3 call, but I like to cheat!
The last line says, take the new cluster and append it to the remaining items, and forward it on recursively to ourself. The result of that invocation will eventually be the base case.
Now does it work? Let's make a quick-n-dirty main procedure to test it:
main :-
setof(leaf(X), (all_cities(Cities), member(X, Cities)), Basis),
cluster(Basis, Result),
write(Result), nl.
Line one is a cheesy way to construct the initial conditions (all cities in their own cluster of one). Line two calls our predicate to cluster things. Then we write it out. What do we get? (Output manually indented for readability.)
cluster(
cluster(
leaf(FI),
cluster(
leaf(BA),
cluster(
leaf(NA),
leaf(RM)))),
cluster(
leaf(MI),
leaf(TO)))
The order is slightly different, but the result is the same!
If you're perplexed by my use of setof/3 (I would be!) then consider rewriting those predicates using the aggregate library or with simple recursive procedures that aggregate and find the minimum by hand.

Dijkstra in Prolog

I have been given an assignment to write an Dijkstra Shortest Path in Prolog.
First of all I don't want source or complete implementation, as I'm trying to understand code (part of evaluation would be explaining the code). I have seen a few implementations here and there, but I don't really know, how does it work.
So far I have this:
edge(1,2,12). %edge(From,To,Cost)
...
edge(1,4,13).
vertex(1,100000,nil,false).%vertex(Id, Weight, Over, Closed).
...
vertex(5,100000,nil,false).
neigh(V1, V2):-edge(V1,V2,_).
open_neigh(V1,V2):-edge(V1,V2,_),vertex(V2,_,_,P),not(P).
nearest_neighbor(From,Who,Cost):-findall(Node,neigh(From, Node),NeighL),
nearest_in_list(From,Who,NeighL,Cost).
n_hood(From,NeighList):-findall(Node, neigh(From,Node), NeighList).
open_n_hood(From,NeighList):-findall(Node, open_neigh(From,Node), NeighList).
nearest_in_list(_,Who,[Who],_).
nearest_in_list(From,Who,[H,K|T],Cost) :-
edge(From,H,C1),
edge(From,K,C2),
C1 =< C2,
Cost is C1,
nearest_in_list(From,Who,[H|T],Cost).
nearest_in_list(From,Who,[H,K|T],Cost) :-
edge(From,H,C1),
edge(From,K,C2),
C1 > C2,
Cost is C2,
nearest_in_list(From,Who,[K|T],Cost).
The thing is, I have no idea how to update the info about vertices. I have tried assert/1 and retract/1 but it doesn't work. I get error that I cannot modify static procedure vertex/4.
I'm currently using SWI Prolog, but the program should work on Amzi! Prolog too, so I would like to keep it as close to basic Prolog as possible.
Thanks.
If you really need to update values I would suggest you use flag/3. However, as suggested in the comments, Prolog programs usually don't have "global variables" that you update through your algorithm steps.
Instead, I would suggest that you find a proper way to calculate Dijkstra costs. Note that the initial arguments in a Dijkstra algorithm are always the "not visited" nodes, a list ([a,b,c,d|...]). At every step, you update this list by "visiting" one of these nodes and updating its costs. I see a clear recursive call here!

Resources