I need to implement nonrecusrsive scalar projection for lists. List is a recursive data structure in Prolog. Is that also possible? I try to implement like:
scalar(T,U,S) :- scalar(T,U,S,0).
scalar([X|T],[Y|U],S,M):- repeat,M1 = M + S, S1=X*Y,fail.
repeat.
repeat:-repeat.
But it wrong because I not pass M1 S1.
It's so difficult to understand after C coding. Prolog iteration clause is recursive but with "Tail" recursion. It's mean we have right answer on the end of recursion. Recursive clause need to bactrack to up to get the answer.
Nonrecursive method
scal(L1,L2,R):- scal(L1,L2,0,R).
scal([A|L1],[B|L2],F,R):- F1 is (F + A*B),scal(L1,L2,F1,R).
scal([],[],F,F).
Recursive method
scal([],[],0).
scal([A|L1],[B|L2],R) :- scal(L1, L2, R1), R is (R1+A*B).
Assuming you mean the scalar projection of vector A onto B given by:
s = (A dot B)/|B|
Then you could do it this way:
scalar(A, B, S) :-
dot_product(A, B, P),
magnitude(B, M),
S is P / M.
dot_product(A, B, P) :-
maplist(mult, A, B, M),
sum_list(M, P). % In SWI prolog, this would be sumlist
magnitude(V, M) :-
maplist(sq, V, S), % Or maplist(mult, V, V, S)
sum_list(S, SumS),
M is sqrt(SumS).
mult(X, Y, M) :- M is X * Y.
sq(X, S) :- S is X * X.
Related
Rosetta code delivers me the following code snippet
for modinv/3. It does calculate extended GCD via egcd/4 and then
derives from it modinv/3:
egcd(_, 0, 1, 0) :- !.
egcd(A, B, X, Y) :-
divmod(A, B, Q, R),
egcd(B, R, S, X),
Y is S - Q*X.
modinv(A, B, N) :-
egcd(A, B, X, Y),
A*X + B*Y =:= 1,
N is X mod B.
Example queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.
There is a slight problem with the solution. It is not
tail recursive. Namely the (is)/2 is the last call of
egcd/4 and not egcd/4 itself.
So the predicate might build-up a stack, a stack that
might contain large big numbers. How would one go about
and realize a more tail recursive solution?
The same site you mention has other algorithms amenable for a tail recursive solution.
Here I translated one from the C++ section (note there is a constraint missing in the original C++ code, it is not checking the last value of A):
modinv(A, B, N):-
modinv(A, B, 1, 0, N1),
(N1 < 0 -> N is N1 + B ; N1 = N).
modinv(A, B, X, Y, N):-
(B=0 -> (A=1, N=X) ;
(
divmod(A, B, Q, R),
Exp is X - Y * Q,
modinv(B, R, Y, Exp, N)
)
).
Sample queries:
?- modinv(42, 2017, N).
N = 1969.
?- modinv(42, 64, X).
false.
I'm trying to implement Quicksort in Prolog using the last element as pivot but somehow my predicate gets into an infinite loop. I'm using an accumulator to determine the part sorted so far (which in the end should be equal to the sorted list S that it should be looking for).
quicksort([], S, S).
quicksort(L, S, A ) :-
lastElement(L, P), /*last element P as pivot*/
split(L, P, Greater, Smaller), /* splits L into set Greater (than) and Smaller (than) by pivot P */
quicksort(Greater, Greater_S, A), /* require Greater to be sorted as well, calling this Greater_S */
quicksort(Smaller, S, [P|Greater_S]). /* same for Smaller, but accumulator should already have P and Greater_S sorted -> [P|Greater_S] as accumulator */
quicksort(L, S) :-
quicksort(L, S, []).
Somehow in quicksort(G, G_S, A), the list G_S seems to iteratively increase in size with the same element, i.e. [X, X, X, X, ...].
What am I doing wrong?
If anyone could help me out it'd be much appreciated!
Thanks in advance.
EDIT: Definitions of the predicates split/4 and lastElement/2:
lastElement([X], X).
lastElement([_|T], X) :- lastElement(T, X).
split([], _, [], []).
split([H|T], P, G, K) :-
H > P,
G = [H|T_],
split(T, P, T_, K).
split([H|T], P, G, K) :-
H =< P,
K = [H|T_],
split(T, P, G, T_).
Answer below; however please compare the original version to the "last element as pivot" version and you will see that "last element as pivot" is just silly. Is it possible that there is a gotcha somewhere in the problem statement that we are both missing?
It seems to me that your life will be easier if you used a simpler Quicksort implementation as a starting point. From the Prolog wiki page
partition([], _, [], []).
partition([X|Xs], Pivot, Smalls, Bigs) :-
( X #< Pivot ->
Smalls = [X|Rest],
partition(Xs, Pivot, Rest, Bigs)
; Bigs = [X|Rest],
partition(Xs, Pivot, Smalls, Rest)
).
quicksort([]) --> [].
quicksort([X|Xs]) -->
{ partition(Xs, X, Smaller, Bigger) },
quicksort(Smaller), [X], quicksort(Bigger).
You will have to use phrase:
quicksort(List, Sorted) :- phrase(quicksort(List), Sorted).
So now it sorts:
?- quicksort([c,b,a,b], S).
S = [a, b, b, c].
The only thing you would have to change is to take the last element instead of the first, probably in the second clause of quicksort//1, like this:
quicksort([X|Xs]) -->
{ append(Front, [Pivot], [X|Xs]),
partition(Front, Pivot, Smaller, Bigger)
},
quicksort(Smaller), [Pivot], quicksort(Bigger).
This use of append/3 leaves behind a choice point; you could write your own list_front_last/3 if you want, or use
once( append(...) )
Hope that helps.
EDIT:
you can change your implementation of lastElement just a bit:
list_front_last([], Last, [], Last).
list_front_last([X|Xs], X0, [X0|Front], Last) :-
list_front_last(Xs, X, Front, Last).
You have already unpacked the first value in the head of quicksort//1:
quicksort([X|Xs]) --> ...
so you can directly use
list_front_last(Xs, X, Front, Pivot)
instead of the call to append/3.
I'm trying to write rules for prolog that define a median of a list by using a partitioning method.
partition([], V, [], []).
partition([X | L], V, [X | A], B) :- (V > X), !, partition(L, V, A, B).
partition([X | L], V, A, [X | B]) :- (V < X), !, partition(L, V, A, B).
partition([X | L], V, A, B) :- (V =:= X), partition(L, V, A, B).
median([A], A).
median(L, M) :- partition(L, M, A, B), length(A, X), length(B, X).
partition(L, V, A, B) partitions list L into 2 sublists A and B with A having values less than V and B having values greater than V.
That part works fine, but when I try to write my median, I'm trying to say that it is a median when after partitioning, A and B are the same length.
median works when I use concrete values, like median([1, 2, 3], 2)
but when I try median([1, 2, 3], X).
it gives an error message ERROR: >/2: Arguments are not sufficiently instantiated.
I was wondering how to fix that? Thanks!
=:= operator requires both its operands to be instantiated. When you ask for median([1, 2, 3], X), one of its operands becomes X, which is not instantiated yet. The same problem is with other arithmetic operators like >.
To correct it, you can either use constraints programming (which provides arithmetic operators that aren't so strict) or rework your program to only use arithmetic on list elements. For example, try a classical approach like: sort the list of numbers, then divide the list into three segments: list of length N, a single element, list of length N. Hint: you can do the part after sorting using just a single append/3 and two length/2 invocations.
Easy way to make your program work with median([1, 2, 3], X) query - is to instantiate M to a member of L in the last rule:
median(L, M) :-
member(M, L),
partition(L, M, A, B), length(A, X), length(B, X).
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.
For some reason, this is not working. I am getting:
ERROR: is/2: Arguments are not sufficiently instantiated
1 add_list([]).
2 add_list([H|T]):-
3 Sum2 is Sum1 + H,
4 add_list(T).
I am trying to add the contents of a list (containing only numbers).
I'm not sure what you are trying to do. But if you are trying to calc total sum it will be this way (changed name to list_sum as add_list doesn't make any sense):
list_sum([], 0).
list_sum([H|T], Sum):-
list_sum(T, SubSum),
Sum is SubSum + H.
You can have a "functionnal mind" with foldl :
foldl(_P, [], V, V).
foldl(P, [H|T], V1, VF) :-
call(P, H, V1, V2),
foldl(P, T, V2, VF).
sum_list(L, S) :-
foldl(add, L, 0, S).
add(X, Y, Z) :-
Z is X+Y.
Alternatively you could also use an accumulator (the advantage is, that it is tail-recursive and therefore can be optimized)
list_sum(L,R) :- list_sum(L,0,R).
list_sum([],A,A).
list_sum([H|T],A,R) :- A1 is A + H, list_sum(T,A1,R).