Related
Here's the line of code written in prolog to make an lcm (Least Common Multiple) rule:
lcm(A, B, A) :-
A > B,
A mod B =:= 0,
!.
lcm(A, B, B) :-
B > A,
B mod A =:= 0,
!.
lcm(A, B, X) :-
A < B,
ImproveB is B + B,
lcm(A, ImproveB, X).
lcm(A, B, X) :-
A > B,
ImproveA is A + A,
lcm(ImproveA, B, X).
I noticed that there's a bug in these lines of code.
For example, the case is lcm(16,10,X) which operated as below:
lcm(16,10,X).
lcm(32,10,X).
lcm(64,10,X).
lcm(128,10,X).
...
It will double the larger number and not increment it by the expected constant. The expected operation is as below:
lcm(16,10,X).
lcm(32,10,X).
lcm(48,10,X).
lcm(64,10,X).
lcm(80,10,X).
since 80 mod 10 is 0, so the result of X is 80
So, how to handle this situation?
To solve the problem, the constant value to be added must be passed as an extra argument (which does not change). Also, to reduce the number of clauses, you can fix the order of the arguments so that the first one is the maximum and the second one is the minimum:
lcm(A, B, C) :-
Min is min(A, B),
Max is max(A ,B),
lcm_loop(Max, Min, Max, C).
lcm_loop(A, B, K, C) :-
( A mod B =:= 0
-> C = A
; A1 is A + K,
lcm_loop(A1, B, K, C) ).
I am working on defining an intersection predicate, that takes in two lists, allowing duplicated elements. This is what I have so far.
intersection([], _, []).
intersection([H1|T1], L2, [H1|R]) :- m_member(H1, L2), intersection(T1, L2, R).
intersection([_|T1], L2, R) :- intersection(T1, L2, R).
However, in the case of the follows:
intersection([a,b,b,a],[c,b,b,c,e,f], S).
The predicate-call returns [b, b]. I would like to return [b] instead. Any pointers?
A possible solution to obtain the intersection D of [X|A] and B is:
Suppose, as induction hypothesis, that the intersection of A and B is C (without repetition).
Therefore:
if X is member of C or X is not member of B, then D is equal to C;
otherwise, D is equal to [X|C].
% inter(++Set1, ++Set2, -Set3)
inter([], _, []).
inter([X|A], B, D) :-
inter(A, B, C),
( ( memberchk(X, C)
; \+ memberchk(X, B) )
-> D = C
; D = [X|C] ).
Example:
?- inter([a,b,b,a], [c,b,b,c,e,f], S).
S = [b].
I'm programming some knight and knaves puzzles using both sat/1 and a more natural language approach using the custom propositions A says B and false().
Question 3 is stated as follows:
You meet three inhabitants, A, B and C.
A says: "All three of us are knaves".
B says: "Exactly one of us is a knight".
However, in my solutions that use custom propositions for some reason prolog is giving me Unknown procedure card/2. Here's the code (see question3_again proposition).
question3(A,B,C):- sat(A =:= card([0],[A,B,C])), sat(B =:= card([1],[A,B,C])).
% Now let's make it more intuitive to work with prolog by creating our own operator:
:- op(900,xfy,says).
knight says S :- S.
knave says S :- false(S).
false(A = B) :- dif(A,B).
false( (A ; B) ) :- false(A), false(B).
false( (A , B) ) :- false(A); false(B).
question3_again(A,B,C) :- A says ( A = knave, B = knave, C = knave ),
B says ( card( [1], [A = knight, B = knight, C = knight] ) ).
I tried counting the number of knights and using this solution below instead, but it gives me incorrect answers( I added false(A #= B) :- A #\= B. so false could reason about integers):
false(A #= B) :- A #\= B.
counte(_,[],Count,Count).
counte(E,[H|T],C,Count) :- (E = H, CC is C+1 ; CC is C), counte(E,T,CC,Count).
counte(E,L,Count) :- counte(E,L,0,Count).
question3_again(A,B,C) :- counte(knight,[A,B,C],Knights),
A says ( Knights #= 0 ),
B says ( Knights #= 1 ).
Can someone give me a light?
Thank you in advance!
question3_again(A,B,C) :- A says ( A = knave, B = knave, C = knave ),
B says (permutation([A, B, C], [knave, knave, knight])).
?- question3_again(A, B, C).
A = C, C = knave,
B = knight
With permutation you will get same solution multiple times. If you want to, you can avoid that with some thing like:
one_knight(X) :- nth0(_, X, knight, [knave, knave]).
?- one_knight(X).
X = [knight, knave, knave] ;
X = [knave, knight, knave] ;
X = [knave, knave, knight] ;
false.
permutation would have given 6 choices.
Now your solution will be:
question3_again(A,B,C) :- A says ( A = knave, B = knave, C = knave ),
B says (one_knight([A, B, C])).
I am trying to implement a kind of planner that to a given integer N generates X possible plans with N actions. A action has conditions and restrictions that must be fulfilled, and a list of effects that will be applied to the current state. I implemented the predicates that check the restrictions and conditions and the one that applies the effects. This method that i created already generates a plan with the N actions, but when i press ";" in swi-prolog to see other results, i get the following error:
ERROR: Out of local stack
This is my code:
makePlan(0,_,List):- List = [].
makePlan(N,I,R):- makeSinglePlan(N,I,R).
makeSinglePlan(0, _ ,_).
makeSinglePlan(N,I,[X|LIST]):-
accao(nome : X, condicoes : Y, efeitos : Z, restricoes : W),
checkAllConditions(Y, I),
checkRestrictions(W),
applyEffects(I, Z, Current),
decrement(N, B),
list_to_set(Current, NC),
makeSinglePlan(B,NC,LIST).
decrement(N,B):- B is N-1.
This is how i call the predicate from the console, the first param is the integer N that represents the number of actions that the plans should have, the second is the initial state, and third the return value:
makePlan(2, [clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,mesa)], R).ยด
Example of an action:
accao(nome : putOn(X,Y), %name
condicoes : [on(X,Z),clear(X),clear(Y)], %conditions
efeitos : [clear(Z),on(X,Y),-on(X,Z),clear(b)], %effects
restricoes : [(Y\==mesa),(X\==Y),(X\==Z),(Y\==Z)]) %restrictions
Auxiliar Predicates:
% 1 - conditions to be checked 2 - current state
checkAllConditions([],_).
checkAllConditions([X|T],L):- checkCond(X,L) , checkAllConditions(T,L) .
checkCond(X,[X|_]).
checkCond(X,[_|T]):-checkCond(X,T).
% 1 - restrictions to be checked
checkRestrictions([]).
checkRestrictions([X|T]):- X, checkRestrictions(T).
% 1 -current state 2 - effects to be applied 3 - result
applyEffects(L,[],L).
applyEffects(L, [-X|YTail], A):- ! ,remove(X, L, B), applyEffects(B,YTail, A).
applyEffects(L, [Y|YTail], A):- insert(Y, L, B), applyEffects(B,YTail, A).
insert(E, L1, [E|L1] ).
remove(_,[],[]).
remove(X, [X|L1], A):- !, remove(X,L1,A).
remove(X, [Y|L1], [Y|A]):- remove(X,L1,A).
Two changes are necessary:
makeSinglePlan(0, _ ,[]).
makeSinglePlan(N,I,[X|LIST]):-
N > 0,
....
The list of actions should end with [], and the rule only applies for N > 0.
?- makePlan(2, [clear(b),on(b,a),on(a,mesa),clear(d),on(d,c),on(c,mesa)], R).
R = [putOn(b, d), putOn(b, a)]
; R = [putOn(b, d), putOn(a, b)]
; R = [putOn(b, d), putOn(a, d)]
; R = [putOn(b, d), putOn(d, b)]
; R = [putOn(b, d), putOn(d, a)]
; R = [putOn(d, b), putOn(d, c)]
; R = [putOn(d, b), putOn(b, c)]
; R = [putOn(d, b), putOn(b, d)]
; R = [putOn(d, b), putOn(c, b)]
; R = [putOn(d, b), putOn(c, d)]
; false.
While attempting to learn Prolog I came across a good exercise which was to write a program that displays the Nth Fibonacci number. After some work I got it working and then decided to see if I could write a program that displays a range of Fibonacci numbers according to the input.
For instance the input:
?- fib_sequence(2,5,Output).
Gives the output:
?- Output = [1,1,2,3]
I am having difficulty, however, in finding a good starting point. This is what I have so far:
fib(0, 0).
fib(1, 1).
fib(N, F) :- X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.
fib_sequence(A,B,R) :- fib(A,Y) , fib(B,Z).
I know I must assign a value to R, but I'm not sure how to assign multiple values. Any help is greatly appreciated.
Observe that your fib_sequence cannot be done in a single predicate clause: you need at least two to keep things recursive - one to produce an empty list when A is greater than B (i.e. we've exhausted the range from A to B), and another one to prepend X from fib(A,X) to a list that you are building, increment A by 1, and call fib_sequence recursively to produce the rest of the sequence.
The first predicate clause would look like this:
fib_sequence(A,B,[]) :- A > B.
The second predicate clause is a bit harder:
fib_sequence(A,B,[H|T]) :-
A =< B /* Make sure A is less than or equal to B */
, fib(A, H) /* Produce the head value from fib(A,...) */
, AA is A + 1 /* Produce A+1 */
, fib_sequence(AA, B, T). /* Produce the rest of the list */
Prolog has some helper builtin to handle numeric sequences, then as an alternative to dasblinkenlight' answer, here is an idiomatic 'query':
fib_sequence(First, Last, Seq) :-
findall(F, (between(First,Last,N), fib(N,F)), Seq).
note that it will not work out-of-the-box with your fib/2, because there is a bug: I've added a condition that avoid the endless loop you would experience trying to backtrack on fib/2 solutions:
fib(N, F) :- N > 1, % added sanity check
X is N - 1, Y is N - 2, fib(X, A), fib(Y, B), F is A + B.
Here's yet another approach. First, I redid fib a little so that it only recursively calls itself once instead of twice. To do this, I created a predicate that returns the prior the last two Fibonacci values instead of the last one:
fib(N, F) :-
fib(N, F, _).
fib(N, F, F1) :-
N > 2,
N1 is N-1,
fib(N1, F1, F0),
F is F0 + F1.
fib(1, 1, 0).
fib(2, 1, 1).
For getting the sequence, I chose an algorithm with the Fibonacci calculation built-in so that it doesn't need to call fib O(n^2) times. It does, however, need to reverse the list when complete:
fib_sequence(A, B, FS) :-
fib_seq_(A, B, FSR),
reverse(FSR, FS).
fib_sequence_(A, B, []) :-
A > B.
fib_sequence_(A, B, [F]) :-
A =:= B,
fib(A, F, _).
fib_sequence_(A, B, [F1,F0]) :-
1 is B - A,
fib(B, F1, F0).
fib_sequence_(A, B, [F2,F1,F0|FT] ) :-
B > A,
B1 is B - 1,
fib_sequence_(A, B1, [F1,F0|FT]),
F2 is F1 + F0.
Here's one more way, to do it without the reverse, but the reverse method above still appears to be a little faster in execution.
fib_sequence_dl(A, B, F) :-
fib_sequence_dl_(A, B, F, [_,_|[]]).
fib_sequence_dl_(A, B, [], _) :-
A > B, !.
fib_sequence_dl_(A, B, [F], _) :-
A =:= B,
fib(A, F, _), !.
fib_sequence_dl_(A, B, [F0,F1|T], [F0,F1|T]) :-
1 is B - A,
fib(B, F1, F0), !.
fib_sequence_dl_(A, B, F, [F1,F2|T]) :-
A < B,
B1 is B - 1,
fib_sequence_dl_(A, B1, F, [F0,F1|[F2|T]]),
F2 is F0 + F1.