Out of local stack - prolog

So i have these facts:
border(germany, france).
border(france, spain).
border(spain, portugal).
And a few other borders that can get me from portugal to russia (theres too many facts to post here, but it is in fact possible to go from portugal to russia).
And i made this predicate that tells you the number of countries you crossed when you go from P1 to P2:
crossedCountries(P1,P2,0):- (border(P1,P2);border(P2,P1)).
crossedCountries(P1,P2,Num):-
(border(P1,Z);border(Z,P1)),
(crossedCountries(Z,P2,Num1);crossedCountries(P2,Z,Num1)),!,
Num is Num1 + 1.
All goes well when i have to cross, 3, or 4, or 5 countries, but if it is too far, it just gives me the error
ERROR: Out of local stack
Can someone give me a direction?

This problem is a classic graph traversal problem where you want to know the the different unique paths from one specific node to another (or in this case, just the count of countries in between).
The loop problem occurs because you can end up visiting the same country ("node") more than once when determining a route. So if there's a route from A to B to C to D, you might end up doing A to B to A to B to C to B to C to B to A ... and never get to D.
A solution that doesn't account for this might look like:
border(germany, france).
border(france, spain).
border(spain, portugal).
border(germany, austria).
border(austria, slovakia).
border(slovakia, poland).
border(poland, germany).
bordering(Country1, Country2) :-
border(Country1, Country2).
bordering(Country1, Country2) :-
border(Country2, Country1).
crossedCountries(C1, C2, 0):-
bordering(C1, C2).
crossedCountries(C1, C2, Num):-
bordering(C1, Z),
crossedCountries(Z, C2, Num1),
Num is Num1 + 1.
And you get a result like this:
| ?- crossedCountries(germany, spain, N).
N = 1 ? ;
N = 3 ? ;
N = 5 ? ;
...
This is because valid paths are germany-france-spain, germany-france-germany-france-spain, etc.
The common remedy is to keep track of visited countries ("nodes"). This can be done by adding an argument to track them. Also, to make the results clearer, I've added a Path argument to see the actual solution route through the countries (you can omit this argument if needed):
crossedCountries(P1, P2, [P1|Path], Num) :-
crossedCountries(P1, P2, [P1], Path, Num).
crossedCountries(P1, P2, Visited, [P2], 0) :-
neighbors(P1, P2),
\+ member(P2, Visited).
crossedCountries(P1, P2, Visited, [Z|Path], Num) :-
neighbors(P1, Z),
\+ member(Z, Visited),
crossedCountries(Z, P2, [Z|Visited], Path, Num1),
Num is Num1 + 1.
Now the query results in this:
| ?- crossedCountries(germany, spain, Path, N).
N = 1
Path = [germany,france,spain] ? ;
no
| ?- crossedCountries(germany, poland, Path, N).
N = 0
Path = [germany,poland] ? a
N = 2
Path = [germany,austria,slovakia,poland]
no
| ?-
Etc.

The first what i noticed is the forth line of code fragment#2:
(crossedCountries(Z,P2,Num1);crossedCountries(P2,Z,Num1)),!,
The symmetry is already handled earlier and i see it's just the cause of at least looping, but most likely stack overflow error.
border(germany, france).
border(france, spain).
border(spain, portugal).
crossedCountries(P1,P2,0):-
border(P1,P2);
border(P2,P1).
crossedCountries(P1,P2,Num):-
(
border(P1,Z);
border(Z,P1)
),
crossedCountries(Z,P2,Num1),
Num is Num1 + 1.

Related

finding a cycle path in prolog

atom_elements(h1,hydrogen,[c1]).
atom_elements(n1,nitrogen,[o1, o2, c2]).
atom_elements(o1,oxygen,[n1]).
atom_elements(o2,oxygen,[n1]).
atom_elements(n2,nitrogen,[o3, o4, c4]).
atom_elements(o3,oxygen,[n2]).
atom_elements(o4,oxygen,[n2]).
atom_elements(h5,hydrogen,[c5]).
atom_elements(n3,nitrogen,[o5, o6, c6]).
atom_elements(o5,oxygen,[n3]).
atom_elements(o6,oxygen,[n3]).
atom_elements(h7,hydrogen,[c7]).
atom_elements(h8,hydrogen,[c7]).
atom_elements(h9,hydrogen,[c7]).
atom_elements(c1,carbon,[c2,c6,h1]).
atom_elements(c2,carbon,[c1,c3,n1]).
atom_elements(c3,carbon,[c2,c7,c4]).
atom_elements(c4,carbon,[c3,c5,n2]).
atom_elements(c5,carbon,[c4,c6,h5]).
atom_elements(c6,carbon,[c1,c5,n3]).
atom_elements(c7,carbon,[c3,h7,h8,h9]).
Example query on the 2,4,6-Trinitrotoluene:
?- tnt(X).
X = [[c1, [c2, n1, o1, o2], c3, [c4, n2, o3, o4], c5,
[c6, n3, o5, o6]]] .
My first step is to find a cycle path and show as a List. But the result is shown as fault. It cannot save the path as a list.
atom_elements(h1,hydrogen,[c1]).
atom_elements(n1,nitrogen,[o1, o2, c2]).
atom_elements(o1,oxygen,[n1]).
atom_elements(o2,oxygen,[n1]).
atom_elements(n2,nitrogen,[o3, o4, c4]).
atom_elements(o3,oxygen,[n2]).
atom_elements(o4,oxygen,[n2]).
atom_elements(h5,hydrogen,[c5]).
atom_elements(n3,nitrogen,[o5, o6, c6]).
atom_elements(o5,oxygen,[n3]).
atom_elements(o6,oxygen,[n3]).
atom_elements(h7,hydrogen,[c7]).
atom_elements(h8,hydrogen,[c7]).
atom_elements(h9,hydrogen,[c7]).
atom_elements(c1,carbon,[c2,c6,h1]).
atom_elements(c2,carbon,[c1,c3,n1]).
atom_elements(c3,carbon,[c2,c7,c4]).
atom_elements(c4,carbon,[c3,c5,n2]).
atom_elements(c5,carbon,[c4,c6,h5]).
atom_elements(c6,carbon,[c1,c5,n3]).
atom_elements(c7,carbon,[c3,h7,h8,h9]).
removeprevious(X,Y):-
X=Y.
filterList(A,In,Out) :-
exclude(removeprevious(A),In,Out).
nextlist(P,C,O) :-
atom_elements(C,_,L),
filterList(P,L,O).
findTNT(Start,Output):-
atom_elements(Start,_,List),
findTNT(Start,Start,List,[],Output).
findTNT(_,_,[],_,[]).
findTNT(Start,_,[H|_],_,Output) :-
H = Start,
write('Find it'), %For debugging%
append([H],[],Output).
findTNT(Start,Privious,[H|T],Visited,Output) :-
write(H+'--'), %For debugging%
H \== Start,
\+ member(H,Visited),
nextlist(Privious,H,List),
append([H],Visited,V),
(
findTNT(Start,H,List,V,Output),
Output = [],
findTNT(Start,Privious,T,V,Output);
append([H],Output,O),
Output is O).
The result is :
The error message is not very good, but it indicates that the problem is with your use of is. Concretely, line 65 of your code reads:
Output is O
At the problematic point in the program, Output is [] and O is [c6], which is why this goal is printed as
[] is [c6]
So the problem is that you are using is on something that is not an arithmetic expression. is is only usable for evaluating arithmetic, for example:
X is 2 + 2
It is not usable for equality of terms. Use = for that. So this last line should maybe be something more like:
Output = O
Except that that will also not work, because you are trying to "assign" a new term to a variable that is already bound to a different term. And you're trying to do "recursive append", which is something that is pretty much always wrong in Prolog. Some recent questions about this: Prolog - Recursively append numbers to a list, Prolog - Recursive append to list returning false

Prolog - Connectivity Graph Beginner

I am a beginner in Prolog and I have a task to do.
I need to check if the graph is connected.
For now I have that...
graph(
[arc(a,b)],
[arc(a,f)],
[arc(b,c)],
[arc(c,d)],
[arc(c,e)],
[arc(e,d)],
[arc(f,c)],
[arc(f,e)],
[arc(f,g)],
[arc(g,c)],
[arc(c,a)]).
edge(X,Y):-arc(X,Y);arc(Y,X).
path(X,Y):-edge(X,Y).
path(X,Y):-edge(X,Z),path(Z,Y).
triangle(X,Y,Z):-arc(X,Y),arc(Y,Z),arc(Z,X).
cycle(X):-arc(X,Y),path(Y,X).
connectivity([]):-forall(member(edge(X,Y)),path(X,Y)).
Check:
connectivity(graph).
upper I have arc(x,y) and I need check if every pair is connected.
Could u help me ?
Since you changed the question after I was almost done I will post what would solve the question before the change and you can figure out how to change it to meet your update.
arc(a,b).
arc(a,f).
arc(b,c).
arc(c,d).
arc(c,e).
arc(e,d).
arc(f,c).
arc(f,e).
arc(f,g).
arc(g,c).
arc(c,a).
edge(X,Y) :-
arc(X,Y), !.
edge(X,Y) :-
arc(Y,X).
path_prime(Visited,X,Y) :-
\+ member(X,Visited),
edge(X,Y), !.
path_prime(Visited,X,Y) :-
\+ member(X,Visited),
edge(X,Z),
path_prime([X|Visited],Z,Y).
path(X,X) :-
ground(X), !.
path(X,Y) :-
path_prime([],X,Y).
nodes(Nodes) :-
setof(A,B^arc(A,B),Starts),
setof(B,A^arc(A,B),Ends),
union(Starts,Ends,Nodes).
connected(X,Y) :-
nodes(Nodes),
member(X,Nodes),
member(Y,Nodes),
path(X,Y).
The first thing that has to be done is to get a list of the unique nodes which will be a set.
This can be done using
nodes(Nodes) :-
setof(A,B^arc(A,B),Starts),
setof(B,A^arc(A,B),Ends),
union(Starts,Ends,Nodes).
Notice that both the start and the end node of an arc are done separately. In particular notice that the node d is only in the destination of an arc.
Since you included edge(X,Y):-arc(X,Y);arc(Y,X). in your question, this indicated that the arcs should not be directional and so it is possible to get cycles. To avoid the cycles the list of visited nodes is added to the argument list and checked before proceeding.
As no test cases or examples of a correct solution were given, some times a node connected to itself is valid and so the clause
path(X,X) :-
ground(X), !.
was added.
This is by no means an optimal or best way to do this, just to give you something that works.
Partial run
?- connected(X,Y).
X = Y, Y = a ;
X = a,
Y = b ;
X = a,
Y = c ;
X = a,
Y = d ;
X = a,
Y = e ;
X = a,
Y = f ;
X = a,
Y = g ;
X = b,
Y = a ;
X = Y, Y = b ;
X = b,
Y = c ;
...
As I often comment, you should do problems with pen an paper first before writing code. If you don't know exactly what the code will be before you start typing the first line of code then why are you typing in code?
Questions from comments:
And setof ,union ,whats mean? Im rly beigneer and I don't understand that language and predicates.
setof/3 collects all of the values from arc/2. Since only one of the two values is needed, ^ tells setup/3 not to bind the variable in the Goal, or in beginner terms to just ignore the values from the variable.
union/3 just combines the to sets into one set; remember that a set will only have unique values.

Recursivity | Natural numbers in list swish prolog

i have the next problem,
"return the numbers of natural numbers of an array"
ex. naturales(R,[6,-7,-4,3,2,8]).
R = 4
when a negative numbers appears return false and break my recursivity
naturales(R,[Head|Tail]):-naturales(R1,Tail), Head >= 0, R is R1+1.
naturales(0,[]).
Here is a very short solution :
naturales(In, Out) :-
aggregate(count,X^(member(X, In), X >= 0), Out).
If your predicate really needs to have only 2 arguments, one being the result, R, and the other one the given list, [H|T], you can do something like this. Note that the first predicate calls the second "naturales" with 3 arguments and then, that one starts the recursive process. The C is only a counter where you can add the number of positive elements and then copy that value to the result, in the last line of code. The first line just its just to make sure the empty list returns 0 positive elements. There is probably better ways to do this, this one is probably the most intuitive.
naturales(X, []):- X = 0.
naturales(R, [H|T]):- naturales(R, [H|T], 0).
naturales(R, [H|T], C):- (H > 0, C1 is C + 1, naturales(R1, T, C1), R = R1) ; naturales(R1, T, C), R = R1.
naturales(X, [], X).
A common prolog idiom is the use of a helper predicate with an accumulator (extra) variable. Try something like this:
natural_numbers( Xs, N ) :- natural_numbers( Xs, 0, N ).
natural_numbers( [] , N , N ) .
natural_numbers( [X|Xs] , T , N ) :-
( X > 0 -> T1 is T+1 ; T1 = T ) ,
natural_numbers( Xs, T1, N ).
As others pointed out, the recursive call cannot complete when there are negative numbers. So, you can just patch your program in this way
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0, R is R1+1 ; R=R1).
naturales(0,[]).
Now, nearly every Prolog out there (except mine :) implements (->)/2, also know as 'if-then-else'. So, the patch could also be written like
naturales(R,[Head|Tail]):-naturales(R1,Tail), (Head >= 0 -> R is R1+1 ; R=R1).
naturales(0,[]).
Given that naturales/2 is anyway not tail recursive (see #NicholasCarey answer for that), I think it has no practical relevance for you.

Recursion confuses me

I have understood the theory part of Recursion. I have seen exercises but I get confused. I've tried to solve some, some I understand and some I don't. This exercise is confusing me. I can't understand why, so I use comments to show you my weak points. I should have power (X,N,P) so P=X^N.
Some examples:
?- power(3,5,X).
X = 243
?- power(4,3,X).
X = 64
?- power(2,4,X).
X = 16
The solution of this exercise is: (See comments too)
power(X,0,1). % I know how works recursion,but those numbers 0 or 1 why?
power(X,1,X). % X,1,X i can't get it.
power(X,N,P) :- % X,N,P if only
N1 is N-1, % N1=N-1 ..ok i understand
power(X,N1,P1), % P1 is used to reach the the P
P is P1*X. % P = P1*X
What I know recursion, I use a different my example
related(X, Y) :-
parent(X, Z),
related(Z, Y).
Compare my example with the exercise. I could say that my first line, what I think. Please help me out with it is a lot of confusing.
related(X, Y) :- is similar to power(X,N,P) :- . Second sentence of my example parent(X, Z), is similar to N1 is N-1, and the third sentence is related(Z, Y). similar to power(X,N1,P1), and P is P1*X..
Let's go over the definition of the predicate step by step. First you have the fact...
power(X,0,1).
... that states: The 0th power of any X is 1. Then there is the fact...
power(X,1,X).
... that states: The 1st power of any X is X itself. Finally, you have a recursive rule that reads:
power(X,N,P) :- % P is the Nth power of X if
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Possibly your confusion is due to the two base cases that are expressed by the two facts (one of those is actually superfluous). Let's consider the following queries:
?- power(5,0,X).
X = 1 ;
ERROR: Out of local stack
The answer 1 is certainly what we expect, but then the predicate loops until it runs out of stack. That's certainly not desirable. And this query...
?- power(5,1,X).
X = 5 ;
X = 5 ;
ERROR: Out of local stack
... yields the correct answer twice before running out of stack. The reason for the redundant answer is that the recursive rule can reduce any given N to zero and to one thus yielding the same answer twice. If you look at the structure of your recursive rule, it is obvious that the first base case is sufficient, so let's remove the second. The reason for looping out of stack is that, after N becomes zero, the recursive rule will search for other solutions (for N=-1, N=-2, N=-3,...) that do not exist. To avoid that, you can add a goal that prevents the recursive rule from further search, if N is equal to or smaller than zero. That leaves you with following definition:
power(X,0,1). % the 0th power of any X is 1
power(X,N,P) :- % P is the Nth power of X if
N > 0, % N > 0 and
N1 is N-1, % N1 = N-1 and
power(X,N1,P1), % P1 is the N1th power of X and
P is P1*X. % P = P1*X
Now the predicate works as expected:
?- power(5,0,X).
X = 1 ;
false.
?- power(5,1,X).
X = 5 ;
false.
?- power(5,3,X).
X = 125 ;
false.
I hope this alleviates some of your confusions.

Prolog - create simple function

I have a function that uses 4 parameters, called tile . It is designed to work the following way :
tile(?E, ?S, ?W, ?N, ?ID)
I would like a getter function that given an ID, it returns the first 4 parameters: E, S, W and N.
I have tried something like:
coordonates(tile(E,S,W,N,L), (E,S,W,N)).
But it does not return the actual values, only true.
If I type tile(E, S, W, N, #1) in the terminal I get the desired result but I do not know what exactly is returned (a list maybe?).
Let's suppose our facts describing tile looks as follows:
tile(p1,p2,p3,p4,id1).
tile(q1,q2,q3,q4,id2).
tile(r1,r2,r3,r4,id3).
In this we have a finite number of facts. That can be checked by the most general query for tile:
?- tile(E,S,W,N,I).
E = p1,
S = p2,
W = p3,
N = p4,
I = id1 ; % <---- user input ; to continue
E = q1,
S = q2,
W = q3,
N = q4,
I = id2 ; % <---- user input ; to continue
E = r1,
S = r2,
W = r3,
N = r4,
I = id3. % <---- toplevel outputs . -- we're done
So in theory, we could define coordonates as follows:
coordonates(id1, t(p1, p2, p3, p4)).
coordonates(id2, t(q1, q2, q3, q4)).
coordonates(id3, t(r1, r2, r3, r4)).
which could be queried for id2 as follows:
?- coordonates(id2,X).
X = t(q1, q2, q3, q4).
I used the functor t to group the solution, to make clear that it is not the predicate tile we defined earlier. There's also a lot of repetition in this definition which is already a hint, that we can do better. What we are looking for is a rule which tells us how, given we have a answer for tile, we can describe coordonates. In logical terms, this is written as an implication of the form: goal1 ∧ ... ∧ goalN → head. which means "Suppose I know that goal1 to goalN is true, then I also know that head is true." In Prolog, this is written backwards:
head :-
goal1,
% ...
goalN.
Let's go back to our task: we know something about a tile and we want to describe how the projection looks like. This means, our code looks as follows:
coordonates( ... ) :-
% ...
tile(E,S,W,N,I).
The body tile(E,S,W,N,I) is the most general form we can write (see our query above) and can be read as "suppose I have any tile at coordinates E S W N with id I". Now we only need to fill in, how coordonates should look like. We know it has two arguments, because it relates the id with the four other elements. Lets give them names, say Id and Coords:
coordonates(Id, Coords) :-
% ...
tile(E,S,W,N,I).
Now we only need to find out how to relate E,S,E,N and I with Id and Coords. One is easy: Id is just I. The other one is also not too hard, we just need to group the coordinates into one term. We can pick an arbitrary one, but already above decided to take t, so we will stick with it:
coordonates(Id, Coords) :-
Id = I,
Coords = t(E,S,W,N),
tile(E,S,W,N,I).
This already works as we expect:
?- coordonates(X,Y).
X = id1,
Y = t(p1, p2, p3, p4) ;
X = id2,
Y = t(q1, q2, q3, q4) ;
X = id3,
Y = t(r1, r2, r3, r4).
Now we can make one observation: if two terms are equal, we can use one instead of the other. So instead of writing Id = I, we can just reuse Id. The same goes for Coords and t(E,S,W,N):
coordonates(I, t(E,S,W,N)) :-
tile(E,S,W,N,I).
It couldn't be much shorter :-)
You have to declare 'E, S, W and N' so that prolog can unify those parameters with the input when you make the query. Something like (In the most basic case):
tile(['cordE1','cordS1','cordW1','cordN1'],1).
tile(['cordE2','cordS2','cordW2','cordN2'],2).
tile(['cordE3','cordS3','cordW3','cordN3'],3).
Query:
?- tile(C,2).
C = [cordE2, cordS2, cordW2, cordN2].
?- tile(C,1).
C = [cordE1, cordS1, cordW1, cordN1].
?- tile(C,3).
C = [cordE3, cordS3, cordW3, cordN3].

Resources