Prolog different variable, same value - prolog

If you query e.g.
?- X = 10, Y = 10, Z = 10.
The output is
X = Y, Y = Z, Z = 10.
But my X is totally different from Y, they just happen to accidentally both be 10, so it doesn't seem clear/logical to display it that way.
Can i make it look like this instead?:
X = 10, Y = 10, Z = 10.

I share your preference. Note that different Prolog systems have different top levels...
SWI-Prolog gives me this:
$ swipl
?- X = 10, Y = 10, Z = 10.
X = Y, Y = Z, Z = 10.
Traella Prolog says something quite similar:
$ tpl
?- X = 10, Y = 10, Z = 10.
X = 10, Y = X, Z = X.
GNU-Prolog and Scryer Prolog, however, give me answers that I like better:
$ gprolog
| ?- X = 10, Y = 10, Z = 10.
X = 10
Y = 10
Z = 10
yes
$ scryer-prolog
?- X = 10, Y = 10, Z = 10.
X = 10, Y = 10, Z = 10.

change([H,Q,D,N,P]) :-member(H,[0,1,2]), /* Half-dollars /member(Q,[0,1,2,3,4]), / quarters /member(D,[0,1,2,3,4,5,6,7,8,9,10]) , / dimes /member(N,[0,1,2,3,4,5,6,7,8,9,10, / nickels /11,12,13,14,15,16,17,18,19,20]),S is 50H + 25Q +10D + 5*N,S =< 100,P is 100-S.

Related

To generate all the prime numbers using the isprime/1 build in function. Prolog

Question ask:
?- prime(X).
The solution should look like:
X = 1;
X = 1;
X = 2;
X = 3;
X = 5;
X ....
So this is what i have until now:
prime(X) :- repeat, incr(X,X), isprime(X).
incr(X,X1) :- X1 is X+1.
isprime(X):-
Y is 2,
X > 1,
\+div(X,Y).
div(X,Y):-
N is Y*Y,
N =< X,
X mod Y =:= 0.
div(X,Y):-
Y < X,
Y1 is Y+1,
div(X,Y1).
Use the following alternative for the incr/2 predicate:
incr(I, I).
incr(I, K) :-
J is I + 1,
incr(J, K).
Call it using the goal:
| ?- incr(1,X), isprime(X).
?- incr(1,X), isprime(X).
X = 2 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 11 ;
X = 13 ;
...

How can we select a random data set from the list of solutions given by Prolog?

i am new to prolog and working my way through the FD solvers in it. I am exploring both SWI-Prolog and Gnu Prolog. I have a case where a constraint like below needs to be solved and one of the possible solutions needs to be picked at random based on a seed. Not sure how much of it is possible in Prolog.
Below is the equation i am trying to solve:
?- X #< 7 , X #> -10, 4*X+2*Y #< 8, Y #< 10, Y #>0, label([X]).
X = -9,
Y in 1..9 ;
X = -8,
Y in 1..9 ;
X = -7,
Y in 1..9 ;
X = -6,
Y in 1..9 ;
X = -5,
Y in 1..9 ;
X = -4,
Y in 1..9 ;
X = -3,
Y in 1..9 ;
X = -2,
Y in 1..7 ;
X = -1,
Y in 1..5 ;
X = 0,
Y in 1..3 ;
X = Y, Y = 1.
As you can see above, it gives me multiple solutions. For my application, I would be interested in choosing one of the data set from above based on a seed.
Is this possible in prolog? It would be great if you can help me with your suggestions.
Thanks,
Venkat
You can specify random choice strategy for labeling variables. That's how to do it in ECLiPSe CLP Prolog:
:- lib(ic).
one_random_solution(X, Y) :-
X #< 7 , X #> -10, 4*X+2*Y #< 8, Y #< 10, Y #>0,
once search([X, Y], 0, input_order, indomain_random, complete, []).
And run with:
[eclipse]: seed(10), one_random_solution(X, Y).
X = -9
Y = 5
Yes (0.00s cpu)
Unfortunately, it looks like SWI-Prolog doesn't support random choice strategy for labeling.

How to shorten following program?

I would like to shorten the following program. Just imaging there are tens of variables instead of just X and Y. The problem is that I need to define domain for each variable separately. I don't like it because it makes my program much longer and less transparent.
Input:
?- Dom1 in 0..2, Dom2 in 0..2, global_cardinality([X,Y], [0-Dom1,1-Dom2]), labeling([],[X,Y]).
Results:
X = 0,
Y = 0,
Dom1 = 2,
Dom2 = 0 ? ;
X = 0,
Y = 1,
Dom1 = 1,
Dom2 = 1 ? ;
X = 1,
Y = 0,
Dom1 = 1,
Dom2 = 1 ? ;
X = 1,
Y = 1,
Dom1 = 0,
Dom2 = 2 ? ;
no
At first I thought that I would solve it simply by writing:
?- Dom1 in 0..2, global_cardinality([X,Y], [0-Dom1,1-Dom1]), labeling([],[X,Y]).
but it does not work because Dom1 unifies (is this the proper term for what happens in clpfd?) with one value and therefore the only results are:
X = 0,
Y = 1,
Dom1 = 1 ? ;
X = 1,
Y = 0,
Dom1 = 1 ? ;
no
Thanks!
Suppose that L = [X1,...,Xn] and you want every variable to be in 1..10.
Alternative 1, works for intervals only:
?- domain(L, 1, 10).
Alternative 2, works for domains that are not intervals too:
?- (foreach(X,L) do X in 1..10).
I can't understand your use case. The result you're after seems to be the same of
?- [X,Y] ins 0..1, labeling([], [X,Y]).
X = Y, Y = 0 ;
X = 0,
Y = 1 ;
X = 1,
Y = 0 ;
X = Y, Y = 1.
Your explanation
it does not work because Dom1 unifies (...) with one value
seems clear to me. Since Dom1 means 'number of occurrences' of key and there are 2 variables with 2 possible values (the 'keys' 0, 1), Dom1 must be 1.

Narcissistic Number in Prolog

hi everyone I'm here again, this week I got this Homework:
I should find all the numbers between 10 and 10000 which has property like the following example:
89 = 8^1 + 9^2
2427 = 2^1 + 4^2 + 2^3 + 7^4 = 2 + 16 + 8 + 2401
I have this in Haskell implemented, and it works just fine(I think) and return a List like this:
[89,135,175,518,598,1306,1676,2427]
and then I tried to write it in Prolog(as required too) like the following:
num(0).
num(1).
num(2).
num(3).
num(4).
num(5).
num(6).
num(7).
num(8).
num(9).
allNarc(X):- num(A),num(B),num(C),num(D),
X = A*1000+B*100+C*10+D,Y = A**1+B**2+C**3+D**4,
X =:= Y,X>10.
allNarc(X):- num(B),num(C),num(D),
X = B*100+C*10+D,Y = B**1+C**2+D**3,
X =:= Y,X>10.
allNarc(X):- num(C),num(D),
X = C*10+D,Y = C**1+D**2,
X =:= Y,X>10.
the result is something like this:
?- allNarc(X).
X = 1*1000+3*100+0*10+6 ;
X = 1*1000+6*100+7*10+6 ;
X = 2*1000+4*100+2*10+7 ;
X = 0*100+4*10+3 ; <- 43
X = 0*100+6*10+3 ; <- 63
X = 1*100+3*10+5 ;
X = 1*100+7*10+5 ;
X = 5*100+1*10+8 ;
X = 5*100+9*10+8 ;
X = 8*10+9 ;
false.
clearly 43 and 64 should not belong to this group and the result is just ugly, can anyone help me to get output like the result in my Haskell implementation?
Two points.
when you say X = you are unifying the left and right sides of =. If you want X to be a number equal to evaluating the expression, use X is <expression here> .
you want to prevent a zero in the first position: num(A), A \= 0, num(B), ...
After making those changes I get:
?- allNarc(X).
X = 1306 ? ;
X = 1676 ? ;
X = 2427 ? ;
X = 135 ? ;
X = 175 ? ;
X = 518 ? ;
X = 598 ? ;
X = 89 ? ;
no
You could also use bagof to collect the values. e.g. bagof(X,allNarc(X),Narcs). Narcs is then a list of your values.
You need to:
Prevent the first digits being 0.
Make sure that X is evaluated to the value you want. At the moment you are using term unification which is not appropriate, you need to use the is keyword.
See:
num(0).
num(1).
num(2).
num(3).
num(4).
num(5).
num(6).
num(7).
num(8).
num(9).
posnum(A) :- num(A), A \= 0.
allNarc(X):- posnum(A),num(B),num(C),num(D),
X is A*1000+B*100+C*10+D,Y is A**1+B**2+C**3+D**4,
X =:= Y,X>10.
allNarc(X):- posnum(B),num(C),num(D),
X is B*100+C*10+D,Y is B**1+C**2+D**3,
X =:= Y,X>10.
allNarc(X):- posnum(C),num(D),
X is C*10+D,Y is C**1+D**2,
X =:= Y,X>10.
Note that you can then find all the numbers using setof:
?- setof(X,allNarc(X),XL).
XL = [89, 135, 175, 518, 598, 1306, 1676, 2427].
This is much more convenient that listing through them one by one.

Understanding prolog [lists]

I am to write a program that does this:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5 ;
false.
(gives all pairs X,X+1 between 2 and 5, plus the special case at the end).
This is supposedly the solution. I don't really understand how it works, could anyone guide me through it?
pLeap(X,X,X,X).
pLeap(L,H,X,Y) :-
L<H,
X is L,
Y is X+1.
pLeap(L,H,X,Y) :-
L=<H,
L1 is L+1,
pLeap(L1,H,X,Y).
I'd do it simply like this:
pLeap(L,H,X,Y) :-
X >= L,
X =< H,
Y is X+1.
Why doesn't it work (ignoring the special case at the end)?
You could use library clpfd for you problem.
:- use_module(library(clpfd)).
pLeap(L,H,X,Y) :-
X in L..H,
Y #= min(H, X+1),
label([X]).
Here is the output:
?- pLeap(2,5,X,Y).
X = 2,
Y = 3 ;
X = 3,
Y = 4 ;
X = 4,
Y = 5 ;
X = 5,
Y = 5.
The >= and =< operators don't instantiate their arguments, and you can only use them once the arguments have already been instantiated.
Put another way, in the given solution, X and Y are given values with is, and the < and =< operators are only used on L and H, whose values are given by the user. (On the given solution, try pLeap(L,H,2,3) and you'll get the same problem as you're having.)
In your case, though, you try to use >= and =< on X, which has no value yet, and so the interpreter complains.

Resources