How can i find pairs in a list, Prolog? - list

I have a problem,
I have a list with numeric elements such as in the example.
I´d like to find all pairs, and count it. (Every Element can only be one part of one pair)
?- num_pairs([4,1,1,1,4],N).
N=1;
Can anyone help me to solve this problem??

You need several things to make it work:
An ability to count the number an item is repeated in a list
An ability to remove all elements matching a value from the list
An ability to conditionally increment a number
Here is how you can count:
count([], _, 0).
count([H|T], H, R) :- count(T, H, RT), R is RT + 1.
count([H|T], X, R) :- H \= X, count(T, X, R).
Deletion can be done with SWI's delete/3 predicate; this is a built predicate.
Adding one conditionally requires two rules - one when the count equals one, and another one for when the count does not equal one.
add_if_count_is_one(H, T, RT, R) :- count(T, H, 1), R is RT + 1.
add_if_count_is_one(H, T, R, R) :- count(T, H, X), X \= 1.
Finally, counting pairs could look like this:
num_pairs([], 0).
num_pairs([H|T], R) :- delete(T, H, TT),
num_pairs(TT, RT),
add_if_count_is_one(H, T, RT, R).
An empty list has no pairs; when an item is counted as part of a pair, its copies are removed from the rest of the list.
Here is this running program on ideone.

Related

Prolog - Give out every nth element of a list

I'm working on a Prolog program which should load every nth element of a list into another list. For example:
?- pred([a,b,c,d,e,f,g,h,i,j],3,R) =>
R = [c,f,i]
Where pred is the predicate I'm attempting to implement.
But I honestly don't know how to do it. I know that I need a counter, which represents the current position of my Head, so it's gonna be a /4 predicate summarized into a /3 one later one, like
nth(list,number,result) :- nth(list,number,result,counter) or similiar.
Though, I don't know how to give the head a position number that can reset itself. Because once it hits n (let's say n=3, which is the c in the list), it has to turn back to 1 logically and count again up to 3, give out the element, and so on.
How can I work around these specific problems in my implementation?
An example of how this could be implemented:
nth_pos(L, N, R):-
nth_pos(L, 1, N, [], R).
nth_pos([], I, N, Acc, Acc).
nth_pos([H|T], I, N, Acc, R):-
I =:= N,
append(Acc, [H], Acc2),
I2 is 1,
nth_pos(T, I2, N, Acc2, R).
nth_pos([H|T], I, N, Acc, R):-
I < N,
I2 is I + 1,
nth_pos(T, I2, N, Acc, R).
Test-run:
?- nth_pos([a,b,c,d,e,f,g,h,i,j],3,R).
R = [c, f, i] .
?- nth_pos([a,b,c,d,e,f,g,h,i,j],1,R).
R = [a, b, c, d, e, f, g, h, i|...]
But I honestly don't know how to do it. I know that I need a counter,
which represents the current position of my Head, so it's gonna be a
/4 predicate summarized into a /3 one later one, like
nth(list,number,result) :- nth(list,number,result,counter) or
similiar.
Yes you are on the right track, note that an accumulator is used as well to build up the list so we get pred/5. Hope it helps. Note that this is not the only way to solve it.

Multiplying lists and list of lists in Prolog

I'm currently working on a Prolog program and having a lot of trouble figuring out how to implement it.
I want to put a list such as [1,2,2,1] into a function. I want it to multiply into itself to make a new matrix by doing this example.
1 * [1,2,2,1] which would yield [1,2,2,1]
2 * [1,2,2,1] which would yield [2,4,4,2]
2 * [1,2,2,1] which would yield [2,4,4,2]
1 * [1,2,2,1] which would yield [1,2,2,1]
And I want it to create all those together in a matrix like:
[[1,2,2,1],[2,4,4,2],[2,4,4,2],[1,2,2,1]].
Last part would be I want to zero out when I multiply by itself. So the 2nd spot would zero out the second spot making the final matrix:
[[0,2,2,1],[2,0,4,2],[2,4,0,2],[1,2,2,0]].
I want to have a predicate that calls another which makes each list. So heres my thoughts:
main(A,O):-
second(A,A,O).
second([],_,[]).
second([A|As],B,[O|Os]):- %creates the list of lists.
third(A,B,O),
second(As,B,Os).
third(_,[],[]).
third(A,[B|Bs],[O|Os]):-
fourth(A,B,O),
third(A,Bs,Os). %multiplies single digit by list.
fourth(A,B,0):- A == B.
fourth(A,B,O):- O is A * B.
I am getting the correct matrix but can not get the zero diagonal.
I just cant figure out a correct way to get the matrix with zeros down the diagonal. Any thoughts?
You can do the zeroes by introducing indices that indicate row and column you are at and check for a match:
main(A, O) :-
second(A, A, 0, O).
second([], _, _, []).
second([A|As], B, R, [O|Os]) :- %creates the list of lists.
third(A, B, 0, R, O),
R1 is R + 1,
second(As, B, R1, Os).
third(_, [], _, _, []).
third(A, [B|Bs], C, R, [O|Os]) :-
fourth(A, B, C, R, O),
C1 is C + 1,
third(A, Bs, C1, R, Os). %multiplies single digit by list.
fourth(_, _, X, X, 0).
fourth(A, B, C, R, O) :- C \== R, O is A * B.
Check:
| ?- main([1,2,2,1], L).
L = [[0,2,2,1],[2,0,4,2],[2,4,0,2],[1,2,2,0]] ? ;
no
Another interesting approach would be to create a maplist_with_index predicate which works just like maplist but manages an index and implicitly assumes the given predicate accepts the index as its first argument:
maplist_with_index(Pred, L, M) :-
maplist_with_index_(Pred, 0, L, M).
maplist_with_index_(Pred, I, [H|T], [M|Ms]) :-
Pred =.. [P|Pt],
append([P,I|Pt], [H], NewPred),
Call =.. NewPred,
call(Call, M),
I1 is I + 1,
maplist_with_index_(Pred, I1, T, Ms).
maplist_with_index_(_, _, [], []).
Then, the matrix program, using this predicate, looks like:
main(A, O) :-
second(A, A, O).
second(M, A, O) :-
maplist_with_index(third(A), M, O).
third(R, A, E, O) :-
maplist_with_index(fourth(R, E), A, O).
fourth(X, X, _, _, 0).
fourth(C, R, A, B, O) :- C \== R, O is A * B.

Prolog - removing elements from sublists

Problem statement:
You're given a list containing integers and lists of integers. You must remove
from each sublist, the 1st, 2n, 4th, 8th.. etc, element.
My solution
domains
list=integer*
elem=i(integer);l(list)
clist=elem*
predicates
modify(list, list, integer, integer)
exec(clist, clist)
clauses
modify([], [], _, _).
modify([H|T], Mod, I, P):-
P=I,
!,
I1=I+1,
P1=P*2,
modify(T, Mod, I1, P1).
modify([H,T], [H|Mod], I, P):-
I1=I+1,
modify(T, Mod, I1, P).
exec([], []).
exec([i(N)|T], [i(N)|LR]):-
exec(T, LR).
exec([l(L)|T], [l(Mod)|LR]):-
modify(L, Mod, 1, 1).
do():-
exec([i(1),l([1,2,3,4,5,6,7,8,9]),l([1,2,3,4])],X),
write(X).
The problem is that the algorithm works until it removes the 1st and 2nd element from each sublist, but from then on doesn't remove a thing and I'm not sure what I'm doing wrong.
the exec predicate is used to assert whether the current element is an integer or a list of integers, add the integer to the result, or add the modified list to the result.
the modify predicate modifies a given list and should remove all elements on position power of 2.
I wrote the do predicate just for calling it as a goal, to avoid writing the list every time I want to test it.
I think you're doing P1=P*2 too often, then you mismatch successive powers of 2
also, you have a typo here
modify([H,T], [H|Mod], I, P):- ...
should read
modify([H|T], [H|Mod], I, P):- ...
I would write
modify([], [], _).
modify([_|T], Mod, I):-
is_pow2(I), !, % as noted by SQB
I1 is I+1,
modify(T, Mod, I1).
modify([H|T], [H|Mod], I):-
I1 is I+1,
modify(T, Mod, I1).
To keep is_pow2/1 simple, you could do
is_pow2(1).
is_pow2(2).
is_pow2(4).
is_pow2(8).
is_pow2(16).
...
or use your Prolog arithmetic facilities. In SWI-Prolog a simple minded definition could be
is_pow2(N) :-
between(0, 63, L),
N is 1 << L.
Actually, the core of your modify is correct, so it may a problem in exec. The following works for me:
do_modify(X) :-
modify([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18], X, 2).
modify(Lin, Lout, Base) :- modify(Lin, Lout, Base, 1, 1).
modify([], [], _, _, _).
modify([_|T], X, Base, N, Power) :-
N = Power,
!,
P1 is Power * Base,
N1 is N + 1,
modify(T, X, Base, N1, P1).
modify([H|T], [H|X], Base, N, Power) :-
N1 is N + 1,
modify(T, X, Base, N1, Power).
Tested it on http://www.compileonline.com/execute_prolog_online.php.

Prolog-Multiplying a list with a list of lists

I'm trying to simulate a product of a matrix with a vector using these two predicates:
eva([], [], []).
eva([A|A1], [W], [Res|R1]) :-
vectormultiplication(A, W, Res),
eva(A1, W, R1).
vectormultiplication([A], [W], [A*W]).
vectormultiplication([A|A1], [W|W1], [A*W|Out1]) :-
vectormultiplication(A1, W1, Out1).
Where the [A|A1] in eva is a matrix (or a list of lists), [W] is a vector (a list),and [Res|R1] is the resulting product. vectormultiplication is supposed to go multiply each list in the list with the vector W. However, this strategy just produces a false response. Is there anything apparent that I'm doing wrong here that prevents me from getting the desired product? I'm currently using SWI Prolog version 5.10
you have 2 other problems apart that evidenced by Daniel (+1): here a cleaned up source
eva([], _, []). % here [] was wrong
eva([A|A1], W, [Res|R1]) :- % here [W] was wrong
vectormultiplication(A, W, Res),
eva(A1, W, R1).
vectormultiplication([A], [W], [M]) :-
M is A*W.
vectormultiplication([A|A1], [W|W1], [M|Out1]) :-
M is A*W,
vectormultiplication(A1, W1, Out1).
test:
?- eva([[1,2],[3,5]],[5,6],R).
R = [[5, 12], [15, 30]]
when handling lists, it's worth to use maplist if available
eva(A, W, R) :-
maplist(vectormultiplication1(W), A, R).
vectormultiplication1(W, A, M) :-
maplist(mult, A, W, M).
mult(A, W, M) :-
M is A*W.
Note I changed the order of arguments of vectormultiplication1, because the vector is a 'constant' in that loop, and maplist append arguments to be 'unrolled'.
Well, your first problem is that you think A*W is going to do anything by itself. In Prolog, that's just going to create the expression A*W, no different from *(A,W) or foo(A, W)--without is/2 involved, no actual arithmetic reduction will take place. That's the only real problem I see in a quick glance.

Prolog Assignment

This is the question for one of my assignments:
Write repCount(L, X, N) which is true when N is the number of occurrences of X in list L.
Here's my code where I try to tackle the problem recursively:
repCount([], X, N) :-
N is 0.
repCount([H|T], X, N) :-
count([H|T], X, N).
count([], X, 0).
count([H|T], X, N) :-
count(T, X, N1),
X =:= H,
N is N1 + 1.
And it works when I supply a list full of identical numbers like this:
?- repCount([2,2,2], 2, N).
N = 3.
But if I supply a list with at least one different value:
?- repCount([2,2,22], 2, N).
false.
It returns false. I cannot figure out why this happens or how to change it to 'skip' the non-matching value, rather than declare the whole thing false. Any input is appreciated.
count([H|T], X, N):- count(T, X, N1), X=:=H, N is N1 + 1.
here you declare that N should be N1+1 if X is H; however you do not define what should happen if X is not H (basically missing an else clause)
this should work:
count([H|T], X, N):-
count(T, X, N1),
(X=:=H->
N is N1 + 1
; N is N1).
another way would be:
count([H|T], X, N):- count(T, X, N1), X=:=H, N is N1 + 1.
count([H|T], X, N):- X=\=H, count(T, X, N1), N is N1.
but this is inefficient since count(T,X,N1) will be called twice if X is not H. we can fix this by doing the check in the head of the clause:
count([H|T], H, N):- count(T, X, N1), N is N1 + 1.
count([H|T], X, N):- count(T, X, N1), N is N1.
or simply:
count([H|T], H, N):- count(T, X, N1), N is N1 + 1.
count([H|T], X, N1):- X=\=H, count(T, X, N1).
One maybe interesting addition to what #magus wrote: If you only care about the number of elements instead of the elements themselves, you can use findall/3 like this:
list_elem_num(Ls, E, N) :-
findall(., member(E, Ls), Ds),
length(Ds, N).
Preserve logical-purity—with a little help from
meta-predicate tcount/3 and (=)/3!
The goal tcount(=(X),Es,N) reads "there are N items in list Es that are equal to X".
Sample query:
?- tcount(=(X), [a,b,c,a,b,c,a,b,a], N).
( N = 4, X=a
; N = 3, X=b
; N = 2, X=c
; N = 0, dif(X,a), dif(X,b), dif(X,c)
). % terminates universally
But assuming you aren't allowed to 'cheat', if you want to use recursion, you don't need to do the '==' comparison.. you can use Prolog's variable unification to reach the same end:
% Job done all instances
repCount2([], _, 0).
% Head unifies with X/2nd parameter - ie X found
repCount2([H|T], H, N) :-
repCount2(T, H, NewN),
N is NewN + 1.
% We got here, so X not found, recurse around
repCount2([_|T], X, N) :-
repCount2(T, X, N).
In the second predicate, H is mentioned twice, meaning that if the Head of the list is the same as X, then recurse down, then add 1 to the result of the rest of the recursion (which ends in adding 0 - the base case, which is how the accumulator is built).
Almost there...you need to use an accumulator, thus:
repCount(Xs,Y,N) :-
count(Xs,Y,0,N) % the 3rd argument is the accumulator for the count, which we seed as 0
.
count([],_,N,N). % if the list is empty, unify the accumulator with the result
count([X|Xs],Y,T,N) :- % if the list is non-empty,
X == Y , % and the head of the list (X) is the the desired value (Y),
T1 is T+1 , % then increment the count, and
count(Xs,Y,T1,N) % recurse down, passing the incremented accumulator
. %
count([X|Xs],Y,T,N) :- % if the list is non-empty,
X \== Y , % and the head of the list(X) is not the desired value (Y),
count(Xs,Y,T,N) % simply recurse down
. %
The original question didn't say whether there were constraints on which predicates you could use.
If you are allowed to 'cheat' ie. use higher order predicates like 'findall' that recurse for you Vs you doing the recursion yourself, this can be done in a single predicate:
repCount(L, X, N) :-
findall(X, member(X, L), ListOfX),
length(ListOfX, N).