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].
Related
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.
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.
I am a beginner of Prolog and I'd like to know how to implement this correspond function.
correspond(E1, L1, E2, L2)
this holds when in one place where list L1 has the value E1, L2
has E2. This must work in any mode in which L1 and L2 are proper
lists (that is, either [] or a list whose tail is a proper list).
For example:
correspond(e,[h,e,l,l,o],X,[1,2,3,4,5])
should have only the solution X = 2.
Here is what I have tried by now:
correspond(E1, L1, E2, L2).
correspond(E1,[Elt1|List1],E2,[Elt2|List2]) :-
nth0(Index, [Elt1|List1], E1).
nth0(Index, [Elt2|List2], E2).
I wanted to use Index as intermediate to get the value of E1 or E2, but these code returns either True or False.
This is what I tried, and it works at least for your example :
correspond(e,[h,e,l,l,o],X,[1,2,3,4,5]) has the solution X = 2
Code :
correspond(E1,[E1|_T1],E2,[E2|_T2]).
correspond(E1,[_H1|T1],E2,[_H2|T2]) :-
correspond(E1,T1,E2,T2).
Explanation :
if E1 is the first element of the first list, then E2 should be the first element of the second list.
else, we try the same with tails of lists 1 and 2 and we iterate recursively.
Note that :
correspond(l,[h,e,l,l,o],X,[1,2,3,4,5]) has both solutions X = 3 and X = 4.
Try correspond(X,[h,e,l,l,o],Y,[1,2,3,4,5] and you'll get :
X = h, Y = 1
X = e, Y = 2
X = l, Y = 3
X = l, Y = 4
X = o, Y = 5
false
Edit:
If you really want to get true instead of false after the last result, you might want to prepend the predicate :
correspond(_,[],_,[]).
Resulting in :
correspond(_,[],_,[]).
correspond(E1,[E1|_T1],E2,[E2|_T2]).
correspond(E1,[_H1|T1],E2,[_H2|T2]) :-
correspond(E1,T1,E2,T2).
This means when you try it with empty lists (e.g. the last iteration when lists are of same size), it is true.
so I just got started with Prolog this semester, and got the homework to implement a pretty basic d(function, variable, derivative) which I did like this:
d(X,X,1) :- !.
d(C,X,0) :- atomic(C). %, (C \= X).
d(X**E,X,E*X**(E-1)).
d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).
d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).
d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
I know this is not complete, but it covers all the tasks required in the exercise.
However,
?- d((x*x+2*x+3)/(3*x),x,R).
leads to
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)).
which doesn't look pretty at all. is/2 unfortunately doesn't like my x as it is not a number...
Is there a simple solution to achieve a cleaner result?
I would rather see this as two separate problems:
First, get derivation right (you're probably getting close, depending on your concrete requirements).
Then, work on simplifying expressions on an algebraic level. Exploit algebraic identities, see if applying the laws of commutativity / associativity / distributivity on some subexpressions enable their rewriting into something equivalent (but simpler / more compact).
As a starting point, you may want to look at the somewhat related question "Replacing parts of expression in prolog".
Here's a simplistic sketch how you could do the simplification—using iwhen/2 to safeguard against insufficient instantiation:
expr_simplified(A, B) :-
iwhen(ground(A), xpr_simplr(A,B)).
xpr_simplr(A, B) :-
( atomic(A)
-> A = B
; ( A = X+0 ; A = 0+X ; A = 1*X ; A = X*1 )
-> xpr_simplr(X, B)
; ( A = 0*_ ; A = _*0 )
-> B = 0
; A = X+X
-> B = X*2
; A = X*X
-> B = X**2
; A = X**1
-> B = X
; A =.. [F|Xs0], % defaulty catch-all
maplist(xpr_simplr, Xs0, Xs),
B =.. [F|Xs]
).
Let's see what it does with the expression you gave. We apply expr_simplified/2 until we reach a fixed point:
?- A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
expr_simplified(A,B),
expr_simplified(B,C),
expr_simplified(C,D).
A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3*1))/(3*x*(3*x)),
B = ((x+x+(0+2))*(3*x)-(x**2+2*x+3)*(0+3))/(3*x)**2,
C = ((x*2+2)*(3*x)-(x**2+2*x+3)*3)/(3*x)**2,
D = C. % fixed point reached
As imperfect as the simplifier is, the expression got a lot more readable.
a possibility to get a number is to replace each instance of variable x with a value, visiting the derived tree. You should do writing a clause to match each binary operator, or use a generic visit, like
set_vars(E, Vs, Ev) :-
E =.. [F,L,R],
set_vars(L, Vs, Lv),
set_vars(R, Vs, Rv),
Ev =.. [F,Lv,Rv].
set_vars(V, Vs, N) :- memberchk(V=N, Vs).
set_vars(V, _, V).
that yields
?- d((x*x+2*x+3)/(3*x),x,R), set_vars(R,[x=5],E), T is E.
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)),
E = ((1*5+5*1+ (0*5+2*1)+0)* (3*5)- (5*5+2*5+3)* (0*5+3*1))/ (3*5* (3*5)),
T = 0.29333333333333333
but, there is a bug in your first clause, that once corrected, will allow to evaluate directly the derived expression:
d(X,V,1) :- X == V, !.
...
now, we can throw away the utility set_vars/3, so
?- d((T*T+2*T+3)/(3*T),T,R), T=8, V is R.
T = 8,
R = ((1*8+8*1+ (0*8+2*1)+0)* (3*8)- (8*8+2*8+3)* (0*8+3*1))/ (3*8* (3*8)),
V = 0.3177083333333333.
append([],U,U).
append([X|U1],U2,[W|U3]) :- **W = X** , append(U1,[X|U2],[I|Quyruk]) ,
**W = I**, U3 = Quyruk .
This code appends first two lists when I delete "W is X".
This code has unnecessary variables like "W is X" but they are about my question.
When I set any value to "W" between ":-" and ",append..." like "W is X" or "W = 3" or "W = 6" -- returns false.
Why can't I set any value to the W at that position in code but I CAN set "W = I" at the end of the code?
The query is append([1,2],[3],U). I want to get [2,1,3] at this code
at append([1,2,3],[4,5,6],U). I want to get [3,2,1,4,5,6].
append([1],[2,3],U). returns [1,2,3] , when I take the length of first list "1" (when first list only has one element) the code is perfect ; but when I take the length of first list >1 (when first list has more than one element) the code returns false.
In prolog, you can't assign variables, and then reassign them. Variables are unified and instantiated. Once instantiated, they cannot be re-instantiated inside of a clause. So if you have this inside of a clause:
W = X,
...
W = I,
Then first W is unified with X (=/2 is the unification operator). That means they either both now have the same value instantiated (if at least one was instantiated before), or their values will be forced to be identical instantiation later in the clause. When W = I is encountered later, then I must be unifiable with W or the clause will fail. If I has a specific value instantiated that is different from the instantiation of W (and, therefore, X), the clause will necessarily fail.
Let's see it happen (note I changed the name to my_append since Prolog rejects redefining the built-in predicate, append):
my_append([],U,U).
my_append([X|U1], U2, [W|U3]) :-
W = X,
my_append(U1, [X|U2], [I|Quyruk]),
write('I = '), write(I), write('; W = '), write(W), nl,
W = I,
U3 = Quyruk.
If we run:
?- my_append([1], [1,2], L).
I = 1; W = 1
L = [1,2,3]
yes
Life is good. Now let's try:
| ?- my_append([1,2], [3,4], L).
I = 2; W = 2 % This will be OK
I = 2; W = 1 % Uh oh... trouble
no
Prolog cannot unify 1 and 2, as I described above. They are two different values. So the predicate fails due to the W = I statement.
The solution is a little simpler than what you're attempting (although you are very close):
% Append empty to list gives the same list
my_append([], U, U).
% Append of [X|U1] and U2 is just append U1 and [X|U2]
% Or, thought of another way, you are moving elements of the first list
% over to the head of the second one at a time
my_append([X|U1], U2, U3) :-
my_append(U1, [X|U2], U3).
| ?- my_append([1,2,3],[4,5,6],L).
L = [3,2,1,4,5,6]
yes
The essence of this was in your code. Those other variables were just getting in the way (as C.B. pointed out). :)
The is operator is specifically used to compare or unify integers. W = I Is attempting to unify W with I (regardless of type). When you Unify W with X (assuming X is an integer), you have already unified W, and if X\=I (doesn't unify) you will return false.
In your example, W unifies with 1, but then you try to unify it with 2.
You have a lot of unnecessary variables, here is a very simple implementation of append:
append([],XS,XS).
append([X|XS],YS,[X|ZS]):- append(XS,YS,ZS).
To understand whats going wrong with your code, lets walk through it
append([],U,U).
append([X|U1],U2,[W|U3]) :- W is X , append(U1,[X|U2],[I|Quyruk]) , W = I, U3 = Quyruk .
?-append([1,2,3],[4,5,6],U).
I will use X1,X2,... to differentiate between different bindings.
In the first call, X unifies with 1, U1 unifies with [2,3] and U2 unifies with [4,5,6]. W and U3 are not yet bound before going into the horn clause.
W is X unifies W with 1.
append(U1,[X|U2],[I|Quyruk]) is calling append([2,3],[1,4,5,6],[I|Quyruk]). Already you should see that your recursion isn't working correctly.