I'm trying to work my way through the exercises at the bottom of this page and I find myself utterly confused on number 3.
We are given the following knowledge base of travel information:
byCar(auckland, hamilton).
byCar(hamilton, raglan).
byCar(valmont, saarbruecken).
byCar(valmont, metz).
byTrain(metz, frankfurt).
byTrain(saarbruecken, frankfurt).
byTrain(metz, paris).
byTrain(saarbruecken, paris).
byPlane(frankfurt, bangkok).
byPlane(frankfurt, singapore).
byPlane(paris, losAngeles).
byPlane(bangkok, auckland).
byPlane(singapore, auckland).
byPlane(losAngeles, auckland).
It's simple to find out if it's possible to travel between two cities. I just did this:
connected(X, Y) :- byCar(X, Y); byTrain(X, Y); byPlane(X, Y).
travel(X, Y) :- connected(X, Y).
travel(X, Z) :- connected(Y, Z), travel(X, Y).
However, when I have to actually unify the path with a variable, I am utterly confused!
I wrote this:
connected(X, Y) :- byCar(X, Y); byTrain(X, Y); byPlane(X, Y).
connected(Y, Z, Out) :- connected(Y, Z).
travel(X, Y, Out) :- connected(X, Y).
travel(A, Z, Out) :- connected(Y, Z),travel(A, Y, connected(Y, Z, Out)).
And called travel(valmont, losAngeles,X).
There is a point during the trace where the correct path shows up, aside from the anonymous variable at the end:
travel(valmont, metz, connected(metz, paris, connected(paris, losAngeles, _17)))
but I don't actually know how to unify this with the variable X!
I can't really wrap my mind around this. Can anyone give me a hint just to push me in the right direction? Is there just a termination condition I'm missing or something?
Edit:
Now I have:
connected(X,Y) :- byCar(X,Y);byTrain(X,Y);byPlane(X,Y).
go(X,Y) :- connected(X,Y).
travel(X,Y,go(X,Y)) :- connected(X,Y).
travel(A,Z,Path) :- travel(Y,Z,Path),go(A,Y,Path).
go(A,Y,Path) :- travel(A,Y,Path).
but it gets stuck like this:
4 4 Exit: byPlane(paris,losAngeles) ?
3 3 Exit: connected(paris,losAngeles) ?
2 2 Exit: travel(paris,losAngeles,go(paris,losAngeles)) ?
5 2 Call: go(metz,paris,go(paris,losAngeles)) ?
6 3 Call: travel(metz,paris,go(paris,losAngeles)) ?
7 4 Call: travel(_217,paris,go(paris,losAngeles)) ?
8 5 Call: travel(_242,paris,go(paris,losAngeles)) ?
9 6 Call: travel(_267,paris,go(paris,losAngeles)) ?
10 7 Call: travel(_292,paris,go(paris,losAngeles)) ?
I've played around with it, but I can't get it to build the whole go(a,b,go(b,c)) etc...
I'll give you the base case of the recursion:
travel(X, Y, go(X, Y)) :- connected(X, Y).
The recursive case looks extremely similar, except that the go/3 term you're building must have locations as its first two arguments, and a path (another go/2 or go/3 term) as its second.
I had this explained to me by aBathologist the following way:
Your objective is to get X = go(valmont,metz,go(metz,paris,go(paris,losAngeles))) in response to the query travel(valmont,losAngeles,X).
To solve this problem, your travel/3 predicate needs to have a From, To, and Path, but it must end with a simple go(From, To) without the Path. The simple go(From, To) is your base condition of travel/3, so:
travel(X, Y, go(X, Y)) :- connected(X, Y).
This is exactly as larsmans states.
Now, you need to create your recursive travel/3 predicate:
travel(X, Y, go(X, Z, Path)) :-
connected(X, Z),
travel(Z, Y, Path).
Your go/2 predicate is redundant and a little confusing given the travel/3 predicate has something that looks like a go predicate. By removing the go/2 predicate, the code is a little easier to read and understand.
Related
I'm trying to multiply two numbers in Prolog recursively i.e. 3*4 = 3+3+3+3 = 12.
My code is :
mult(0,Y,Y).
mult(X,Y,Z) :-
NewX is X-1,
Z is Y + mult(NewX,Y,Z).
but I keep either in an infinite loop or being told mult is not a function.
What you here constructed is a predicate. A predicate is not the same as a function in computer science, you can not write A is B + some_pred(C), or at least not as far as I know in ISO Prolog, and definitely not without adding some extra logic.
In order to pass values, one uses variables. We can thus call the mult/3 predicate recursively, and use a variable that will be unified with the result. We can then perform arithmetic with it, like:
mult(0, _, 0).
mult(X, Y, Z) :-
X1 is X - 1,
mult(X1, Y, Z1),
Z is Y + Z1.
Note that you can not reassign a (different) value to a variable. So if, like you did in the question, use Z twice, then given Y is not 0, this will fail.
The above is however still not sufficient, since it will produce a result, but then get stuck in an infinite loop since if it calls (eventually) mult(0, 4, Z) (4 is here just a value), there are two ways to resolve this: with the base case, and with the recursive case.
We thus need a "guard" for the second case, like:
mult(0, _, 0).
mult(X, Y, Z) :-
X > 0,
X1 is X - 1,
mult(X1, Y, Z1),
Z is Y + Z1.
We then obtain for example:
?- mult(14, 25, Z).
Z = 350 ;
false.
One can improve the speed of this mult/3 predicate by implementing a version with an accumulator. I leave this as an exercise.
I am trying to learn z3, and this is the first program I write.
In this exercise, I am trying to determine if x is prime. If x is prime, return SAT, otherwise, return UNSAT alongside with two of its factors.
Here is what I have so far
http://rise4fun.com/Z3/STlX
My problem is I don't think the code is doing anything right now. It returns SAT for whatever I do. i.e if I assert that 7 is prime, it returns SAT, if I assert 7 is not prime, it returns SAT.
I am not sure how recursion works in z3, but I've seen some examples, and I tried to mimic how they did the recursion.
If you guys are able to take a look and instruct me where I went wrong, I would be really appreciative.
The following formula does not achieve what your comment specifies:
; recursively call divides on y++
;; as long as y < x
;; Change later to y < sqrt(x)
(declare-fun hasFactors (Int Int) Bool)
(assert
(and (and (not (divides x y))
(not (hasFactors x (+ y 1)))) (< y x))
)
The first problem is that x, y are free. They are declared as constants before.
Your comment says you want to recursively call divides, incrementing y until it reaches x.
You can use quantified formulas to specify a relation that satisfies this property.
You would have to write something along the lines of:
(assert (forall ((x Int) (y Int)) (iff (hasFactors x y) (and (< y x) (or (divides y x) (hasFactors x (+ y 1))))))
You would also have to specify which formulas you want to check before calling check-sat.
Finding prime numbers using an SMT solver is of course not going to be practical, but will illustrate some of the behavior you get when Z3 instantiates quantifiers, which depending
on problem domain and encoding can be either quick or very expensive.
I'm so used to thinking recursively, after tampering for a few hours, I found another way to implement it. For anyone who's interested, here is my implementation.
http://rise4fun.com/Z3/1miFN
Thanks for the partial solution! A complete solution for isPrime is:
http://rise4fun.com/Z3/jBr0
(define-fun isPrime ((x Int)) Bool
(and
(> x 1)
(not (exists ((z Int) (y Int))
(and (< y x) (< z x) (> y 1) (> z 1) (= x (* y z)))))))
Took me more than I care to admit to get it right.
This is exercise 3.5 from Learn Prolog Now. They put it before explaining lists so I need a procedure that doesn't involve lists.
The task is to swap the leaves of nested binary trees. If the query is
swap(tree(tree(leaf(1), leaf(2)), leaf(4)), T).
the answer should be
T = (tree(leaf(4), tree(leaf(2), leaf(1))).
With
swap((X, Y), (Y, X)).
swap(tree(X, Y), T) :-
swap((X, Y), (Y, X)),
T = (Y, X).
I get
T = (leaf(4), tree(leaf(1), leaf(2))).
As you see the leaf(1) and leaf(2) didn't get swapped. I want some hints or even your procedure and it should work with any depth of the nodes. Thanks.
You have a base case swap a leaf, and a general case swap a tree!
For a leaf, nothing to do :
swap(leaf(X), leaf(X)).
When you swap a tree, you must swap its leaves too, so
swap(tree(X,Y), tree(Y1,X1)) :-
swap(X,X1),
swap(Y,Y1).
The context, first. What I am trying to modelate with prolog are two separated graphs, both represent a group of friends, so in both of them I can put the relation friend(X,Y), and, because it's doesn't have sense the friendship isn't mutual in this model, I also put the relation friend(Y, X).
So this means that both graphs have bidirectional relationships between their elements.
For example:
friend(foo1, foo2).
friend(foo2, foo1).
friend(foo3, foo4).
friend(foo4, foo3).
In which foo1 is related with foo2, and the same goes for foo3 and foo4, but the first two are not related with the another two ones.
Because it is a group of friends, it also doesn´t have sense that in the same group of friends, two people of the same group aren't friends, so I am using recursion to determine if one person is friend of another.
definitivefriend(X, Z) :- friend(X, Z).
definitivefriend(X, Z) :- friend(X, Y), definitivefriend(Y, Z).
The problem I have is when I try to check if one person of one group is friend of a person of the other group. In other words, check if one element of of a graph is related with another element of the other graph.
Instead of getting false, which is the expected result, the compiler (SWI-Prolog, in this case), gives me an error of out of local stack.
I want to know how to solve this.
Edit
So thanks to CapelliC I have an approach of this problem. Because the main objective is complete, but there's a secondary problem I will describe it from now on.
These are the two graphs I am working with. Remember that I said before, both graphs are biredirectional.
Here's my program in prolog:
writeit :- write('Frienship').
definitivefriend(X, Z) :- friend(X, Z), friend(Z, X).
definitivefriend(X, Y) :- friend(X, Z), X #< Z, definitivefriend(Z, Y), Y \= X.
friend(amanda, ryan). % graph1 %
friend(ryan, amanda).
friend(ryan, lisa).
friend(lisa, ryan).
friend(bryan, ryan).
friend(ryan, bryan).
friend(sara, ryan).
friend(ryan, sara).
friend(sara, simone).
friend(simone, sara). % graph2 %
friend(sandra, jeff).
friend(jeff, sandra).
friend(betty, jeff).
friend(jeff, betty).
friend(jeff, antonia).
friend(antonia, jeff).
friend(jeff, oskar).
friend(oskar, jeff).
friend(jeff, leslie).
friend(leslie, jeff).
And here is some of the outputs I got
?- definitivefriend(amanda, ryan).
true . % It's correct, both nodes are neighbours %
?- definitivefriend(amanda, simone).
true . % It's correct, both nodes are in the same graph %
?- definitivefriend(ryan, simone).
true . % It's correct, same explanation as before %
?- definitivefriend(simone, amanda).
false. % It's wrong, expected result is true %
?- definitivefriend(ryan, jeff).
false. % It's correct, nodes are in different graphs %
?- definitivefriend(amanda, leslie).
false. % It's correct, same explanation as before %
?- definitivefriend(sandra, oskar).
false. % It's wrong, expected result is true %
?- definitivefriend(oskar, sandra).
false. % It's wrong, expected result is true %
?- definitivefriend(betty, oskar).
true . % It's correct, both nodes are in the same graph %
?- definitivefriend(oskar, betty).
false. % It's wrong, expected result is true %
As I said in the comments, even with some elements of the same graph (excepting the neighbour ones), definitivefriend gives me false. And are some cases when I execute definitivefriend(X, Y) I get true, but when I execite definitivefriend(Y, X) I get false.
I feel that you are not modelling in the right way, anyway this seems working (abusing of the suggestion by Jean-Bernard, +1)
definitivefriend(X, Y) :-
friend(X, Y),
friend(Y, X).
definitivefriend(X, Y) :-
friend(X, Z), X #< Z,
definitivefriend(Z, Y), Y \= X.
edit: this cannot work with your model. I can't see any other way than following Daniel suggestion (+1).
For your second definitivefriend rule, add a condition that X < Y. This will avoid cycles. Then simply add a rule for:
definitivefriend(X,Y) :- definitivefriend(Y,X)
As it is now, you could have:
definitivefriend(1,2) :- friend(1,3), definitivefriend(3,2)
definitivefriend(3,2) :- friend(2,1), definitivefriend(1,2)
Which leads to infinite recursion
The problem, basically, is cycles. Your graph is acyclic, but your code is not. Here's the question. Suppose I give the query :- definitivefriend(foo1, foo2).. What's to stop Prolog from expanding that like this:
definitivefriend(foo1, foo2)
:- friend(foo1, foo2), definitivefriend(foo2, foo2). % by clause 2
:- friend(foo1, foo2), friend(foo2, foo1), definitivefriend(foo1, foo2). % by clause 2
:- friend(foo1, foo2), friend(foo2, foo1), friend(foo1, foo2),
definitivefriend(foo2, foo2). % by clause 2
etc.
#Jean-Bernard Pellerin provides one useful way to prevent cycles, by forcing a total ordering. I don't think that's the right approach here, but I can't quite put my finger on why. However, one thing you can do is provide a visited list to check against and not re-enter nodes you've already been to. That code's going to look like this:
definitivefriend(X, Z) :- definitivefriend(X, Z, [X]).
definitivefriend(X, Y, Visited) :-
friend(X, Y), \+ memberchk(Y, Visited).
definitivefriend(X, Z, Visited) :-
friend(X, Y), \+ memberchk(Y, Visited),
definitivefriend(Y, Z, [Y|Visited]).
What is wrong with my power function?
pow(_,0,1).
pow(X,Y,Z) :-
pow(X,Y-1,X*Z).
?- pow(2,3,Z).
ERROR: Out of global stack
Your Y does not get decremented, you can not use predicates like functions. You also have to unify Z with the result of the multiplication.
pow(_,0,1).
pow(X,Y,Z) :- Y1 is Y - 1,
pow(X,Y1,Z1), Z is Z1*X.
There is also a builtin power function which will be much faster:
pow2(X,Y,Z) :- Z is X**Y.
Also note that pow is not a last call and can not be optimized to use only one stack frame. You should reformulate it to:
pow3(X,Y,Z) :- powend(X,Y,1,Z),!.
powend(_,0,A,Z) :- Z is A.
powend(X,Y,A,Z) :- Y1 is Y - 1, A1 is A*X, powend(X,Y1,A1,Z).
Predicates
fac(Integer,Integer,Integer).
Clauses
fac(X,N,X):- N=1,!.
fac(X,N,M):- N1=N-1,fac(X,N1,M1), M= X*M1.
Goal
fac(5,3,X).
DOMAINS
num=INTEGER
PREDICATES
nondeterm power(num,num,num)
CLAUSES
power(X,0,1).
power(X,P,F):-X>0,P1=P-1,power(X,P1,F1),F=X*F1.
GOAL
power(2,5,X).