Prolog: Solving a Puzzle - prolog

I am new to prolog and I am trying to solve the following question. I am having difficulty trying to understand the logic to solve the problem. I know its similar to zebra problem but, I am unsure how to approach. Any help would be greatly appreciated.
The answers submitted by five students to a T/F quiz are as follows.
Teresa: T T F T F
Tim: F T T T F
Tania: T F T T F
Tom: F T T F T
Tony: T F T F T
Tania got more answers right than Teresa did.
Tom got more right than Tim.
Tony did not get all the answers right, nor did he get them all wrong.
Write a Prolog program quiz(Answer) that asserts Answer is the list of t and f constants that is the correct answer to the quiz..

If you use SWI-Prolog, you can use library clpfd to solve the puzzle :, I get only one solution (f,f,t,f,t).
You have a solution [A,B,C,D,E].
You initialize the possibles solutions with
[A,B,C,D,E] ins 0..1,
You reify all the answers for teresa for example
teresea([1,1,0,1,0]).
A #= 1 #<==> TA
B #= 1 #<==> TB
.....
you compute the sum of Tis
sum([TA, TB, ...], #= , Steresa),
and later you will have for
Tania got more answers right than Teresa did.
Stania #> Steresa
You get the solution with
label([A,B,C,D,E]).
Hope this helps

small puzzles like this can be solved by generate-and-test
solve(L) :-
% generator
length(L, 5), maplist(tf, L),
% Tania got more answers right than Teresa did.
matches(L, tania, Tania),
matches(L, teresa, Teresa), Tania > Teresa,
...
tf(t).
tf(f).
teresa(t, t, f, t, f).
tim(f, t, t, t, f).
...
Of course, matches(L, tania, Tania) counts correct Tania' answers.
But, I don't find a solution. The only tuple that 'get thru' Tony, it's its exact result. So, this condition
Tony did not get all the answers right
cannot be solved...
edit I had a bug in matches/3. Of course there is a solution.
edit well, the CLP(FD) version can be very compact, while being more general...
teresa(t, t, f, t, f).
...
matches(L, P, N) :-
call(P, A,B,C,D,E),
foldl(eqsum, [A,B,C,D,E], L, 0, N).
eqsum(t,Ls,Acc,N) :- N #= Acc + (° #<==> Ls #= 1).
eqsum(f,Ls,Acc,N) :- N #= Acc + (° #<==> Ls #= 0).
solve(L) :-
length(°L, 5) ins 0..1,
% Tania got more answers right than Teresa did.
matches(L, tania, °) #> matches(L, teresa, °),
% Tom got more right than Tim.
matches(L, tom, °) #> matches(L, tim, °),
% Tony did not get all the answers right, nor did he get them all wrong.
matches(L, tony, °Tony) #> 0, Tony #< 5.
I used my lifter here.

Related

Symbolic & Numeric Calculation

I'm a Computer Science student, on last semester we learned to program in Prolog. Now I'm trying to have fun with it.
I'm trying to build a program that given a symbolic/mathematical input it return the result.
example:
? solve(2+3+Z+K+5+Z+1, R).
R = 11+2*Z+K or R = 11+Z+K+Z
This is the snippet (for + operation)
solve(X, R) :-
eval(X, R).
eval(X, X) :- var(X),!.
eval(X, X) :- number(X), !.
eval(+(X, Y), R) :-
eval(X, A),
eval(Y, B),
add(A, B, R), !.
add(A, B, R) :-
number(A),
number(B),
!,
R is A + B.
add(A, B, A+B) :-
var(A); var(B),!.
add(A+X, B, R+X) :-
number(A),
number(B),
var(X),
!,
R is A + B.
add(X+A, B, R+X) :-
number(A),
number(B),
var(X),
!,
R is A + B.
I have some issue when numbers are separated by many variables, example:
? solve(5+Z+5+4+K+Z+6, R).
FALSE.
or, (not form source code above), if numbers are separated by many variables, they are not "processed", example:
? solve(5+Z+K+7, R).
R = 5+Z+K+7.
Thanks for help, any suggestion or reference will be appreciate.
This is a bit more involved than what your code is doing at the moment. At the end, you seem to want to have a solver for symbolic equations, is that so? So for example, if you type into Wolfram Alfa your equation, 2+3+Z+K+5+Z+1 = R, you get the answer K+2 Z+11 = R.
Similar functionality is provided for example by metafont:
$ mf
This is METAFONT, Version 2.7182818 (TeX Live 2014) (preloaded base=mf)
**\relax
*tracingequations:=tracingonline:=1;
*2+3+a+b+5+a+1=r;
## a=0.5r-0.5b-5.5
*x^2+3=0;
## x^2=-3
... and I guess by every program as Matlab, Mathematica, etc.
In Prolog, for integers, you get something very similar for free if you use library(clpfd):
?- use_module(library(clpfd)).
true.
?- 2 + 3 + Z + K + Z + 1 #= R.
2*Z+K+ -1*R#= -6.
If you want to program this yourself, you should probably start with deciding how you want to represent your answers: as you see, the three programs demonstrated here choose different approaches. From there, you can either try to see how to get there yourself (see the comment by #lurker), or try to figure out how others have implemented it.

SWI-Prolog Creating/Printing lists, Recursion etc

I'm trying to teach myself some Prolog, however right now i'm really struggling just adapting to the declarative style having never done declarative programming before.
I'm attempting to get my program to come up with a two positive integer numbers, A & B, where A + B =< 50 and B > A. Obviously there are lots of solutions (e.g. A = 5 & B = 12 or A = 15 & B = 17) and i want my program to print all the different solutions.
I honestly don't really know where to begin and would appreciate some guidance or some example code of how to do something as explained above.
Cheers!
Looks like a good problem to use constraint logic programming:
:- use_module(library(clpfd)).
model(A, B) :-
A #> 0, B #> 0,
A + B #=< 50,
B #> A.
(I assume you want only positive integer solutions, otherwise there will be infinite number of them). Look how the model code directly reflects the problem statement.
After you have the model you can use it to find all solutions:
?- findall(_, (model(A, B), label([A, B]), writeln([A, B])), _).
[1,2]
[1,3]
[1,4]
[1,5]
[1,6]
... skipped many lines ...
[24,25]
[24,26]
true.
A more traditional Prolog solution without constraint programming (with the same results):
model2(A, B) :-
between(1, 50, A),
between(1, 50, B),
A + B =< 50,
B > A.
?- findall(_, (model2(A, B), writeln([A, B])), _).
You could do something like this:
combos(A,B) :-
between(1,50,A) ,
between(1,50,B) ,
S is A+B ,
S =< 50
.
This, on backtracking, will successively find all the solutions.
Use findall/3 to collect the results into a list:
findall(A+B,combos(A,B),X).

Graph path define issue

The solution
ppath(X,Y,M,Path,[Y|Path]) :- edge(X,Y,M),\+ memberchk(Y,Path).
path(X,Y,P,SoFar,Path) :- edge(X,W,M), \+ memberchk(W,SoFar),
path(W,Y,N,[W|SoFar],Path), P is M+N.
pravilo(X,Y,Z) :-
aggregate(min(W), P^path(X,Y,W,[],P),Z).
Here is the code i have. The question is that starting point is a, and ending point is z.
There is an error after execution, the result is displayed like [z, c, h, b]. But the correct answer should [a,b,c,z].
Please help to fix my problem.
library(aggregate) allows for a witness on min/max scalar operations. We can use that feature to report back the path as well as the travel length:
path(X,Y,M,Path,FullPath) :-
edge(X,Y,M), \+ memberchk(Y,Path),
reverse([Y|Path], FullPath).
path(X,Y,P,SoFar,Path) :-
edge(X,W,M), \+ memberchk(W,SoFar),
path(W,Y,N,[W|SoFar],Path), P is M+N.
pravilo(X,Y,Z,Path) :-
aggregate(min(W,P), P^path(X,Y,W,[X],P), min(Z,Path)).
Note there is a typo in edge/3: edge(b,e,16 should be edge(b,e,16)..
Once corrected the DB, I get
pravilo(a,z,M,P).
M = 16,
P = [a, b, h, c, z].

Why does this Prolog Fibonacci function cause a "instantiation_error"?

I am trying to calculate the Fibonacci series using the following function:
fib(0,A,_,A).
fib(N,A,B,F) :-
N1 is N-1, Sum is A+B, fib(N1, B, Sum, F).
fib(N, F) :- fib(N, 0, 1, F).
This is intended to works like this:
| ?- fib(20,Result).
Result = 6765 ?
But when I try this, it complains:
| ?- fib(What,6765).
uncaught exception: error(instantiation_error,(is)/2)
Does anyone understand why this is happening?
In the second clause:
fib(N,A,B,F) :-
N1 is N-1, Sum is A+B, fib(N1, B, Sum, F).
N is a variable to be decremented, and in your call to:
fib(What, 6765).
The variable is not yet defined, so you get the instantiation error on N1 is N - 1.
In swipl I do even get the error:
?- fib(W, 6765).
ERROR: fib/4: Arguments are not sufficiently instantiated
Now that you know it's an error, do you mind to know if it's actually possible to answer your query?
How do you would approach the problem? Your function it's ok, isn't it? Exactly, because it's a function, and not a relation, you get the error.
It's a bit complicate to solve it, but CLP can do !
See this fascinating example from CLP(FD) documentation (cited here)
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :-
N #> 0, N1 #= N - 1, F #= N * F1,
n_factorial(N1, F1).
We need something like this, but for fibonacci.
See how easy it is:
:- [library(clpfd)].
fib(0,A,_,A).
fib(N,A,B,F) :-
N #> 0,
N1 #= N-1,
Sum #= A+B,
fib(N1, B, Sum, F).
fib(N, F) :- fib(N, 0, 1, F).
i.e. replace is/2 by #=/2 and we get
?- fib(20,Result).
Result = 6765 .
?- fib(X,6765).
X = 20 ;
^C
note, after the first response the program loops!
Do you a see a way to correct it? Or another question could be worth...
A more clear and more natural predicate definition may be:
//The two base steps
fib1(0,0).
fib1(1,1).
//the recursive step
fib1(N,F) :-
N >= 0, M is N-2, O is N-1, fib1(M,A), fib1(O,B), F is A+B.
It is also a definition with only one predicate: fib/2

Depth limited search in prolog (vanilla meta-interpreter)

I need to modify the vanilla meta-interpreter in order to make a search with limited depth. I'm using the following code for testing my sollution:
value(wire1,1).
connected(wire2, wire1).
connected(wire3, wire2).
connected(wire4, wire3).
connected(wire5, wire4).
connected(wire6, wire5).
connected(wire7, wire6).
connected(wire8, wire7).
connected(wire9, wire8).
value(W,X):-connected(W,V), value(V,X).
And the target is that something like:
solve(value(w9,X), 3). /*depth =3, it should return false*/
solve(value(w9,X), 20). /*depth=20 is enought for returning X=1*/
By the way my code is
solve(true,_):-!.
solve((A,B),D) :-!, solve(A,D), solve(B,D).
solve(A,D) :- clause(A, B),solve(B,D2),D=D2+1,D>0).
But it don't work property. Can you help me? Thanks a lot in advance
An interesting page on metaprogramming came from a good developer: Markus Triska.
Here (A Couple of Meta-interpreters in Prolog) you find both theory and practice. For instance:
... Another group of extensions aims to improve the incomplete default computation strategy. We start from an MI that limits the depth of the search tree:
mi_limit(Goal, Max) :-
mi_limit(Goal, Max, _).
mi_limit(true, N, N).
mi_limit((A,B), N0, N) :-
mi_limit(A, N0, N1),
mi_limit(B, N1, N).
mi_limit(g(G), N0, N) :-
N0 > 0,
mi_clause(G, Body),
N1 is N0 - 1,
mi_limit(Body, N1, N).
You were almost there. Only the last clause needs a slight rearranging:
solve(A, D) :- clause(A, B), D1 is D - 1, D1 > 0, solve(B, D1).
?- solve(value(wire9, X), 9). ===> false.
?- solve(value(wire9, X), 10). ===> X = 1.
dls(X,X,[X],L):-
L >0 goal(X).
dls(X,Y,[A|p],L):-
L > 0 ,goal(Y) ,
move(X,Y),
L1 is L - 1 ,
dls(Z,Y ,P,L1).

Resources