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.
Related
How to use maplist on inner term?
Assuming the KB is:
gate(not(o), i).
gate(not(i), o).
gate(and(o, i), o).
gate(and(i, o), o).
gate(and(B, B), B).
bits([i,o,o,i,i]).
The following is not working:
?- bits(BITS), maplist(gate(not(X), Y), BITS, ANS)
How can I map over the list so that:
[i,o,o,i,i] -> [not(i), not(o), not(o), not(i), not(i)] ->[o,i,i,o,o]
This is to be done on any list length:
:- bits([A,B,C,D,E]), gate(not(A), Anew), gate(not(B), Bnew), gate(not(C), Cnew), gate(not(D), Dnew), gate(not(E), Enew), ANS = [Anew, Bnew, Cnew, Dnew, Enew].
So that the answer would be: ANS = [o, i, i, o, o]
With a helper predicate:
not(A, Z) :-
gate(not(A), Z).
?- bits(BITS), maplist(not, BITS, ANS).
ANS = [o, i, i, o, o],
BITS = [i, o, o, i, i]
But if you are going to add two lines of helper, skip the gate() stuff and write directly:
not(o, i).
not(i, o).
?- bits(BITS), maplist(not, BITS, ANS).
ANS = [o, i, i, o, o],
BITS = [i, o, o, i, i]
If you don't want to do that, or cannot change the database at all, the only way I know is using a lambda library such as yall in SWI Prolog, others may be available to write this:
?- bits(BITS), maplist([In, Out]>>gate(not(In), Out), BITS, ANS).
ANS = [o, i, i, o, o],
BITS = [i, o, o, i, i]
(It might be bad form to name it not, but this is not/2 and the builtin is not/1 so I don't think it will clash).
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.
Given the start position and length, I want to generate a sublist of that length. I did it below using an accumulator:
get_sublist(_,_,0,Sublist,Sublist):-!.
get_sublist(List,Position,Length,Sublist,Acc):-
nth1(Position,List,Element),
append([Element],Acc,Acc1),
Position1 is Position + 1,
Length1 is Length - 1,
get_sublist(List,Position1,Length1,Sublist,Acc1).
Is there a shorter/faster way to do this either by using more built in predicates or using an alternative method? Thanks.
I would go for:
sublist(List, Offset, Length, Sublist):-
length(Prefix, Offset),
append(Prefix, Rest, List),
length(Sublist, Length),
append(Sublist, _, Rest).
Example of use:
?- sublist([a,b,c,d,e,f,g,h,i,j,k], 3, 6, X).
X = [d, e, f, g, h, i].
Notice I'm using count-by-0 for the Offset argument here.
if I run your code, I get
?- get_sublist([a,b,c,d,e,f,g,h,i,j,k], 3, 6, X, []).
X = [h, g, f, e, d, c].
then, a reverse/2 is missing ? In case, I would propose the good old findall/3:
get_sublist(List,Position,Length,Sublist):-
Stop is Position+Length-1,
findall(X, (between(Position,Stop,P),nth1(P,List,X)), Sublist).
edit bagof/3, by means of declaration of scoped variables (just P here), will avoid problems introduced by findall:
get_sublist(List,Position,Length,Sublist):-
Stop is Position+Length-1,
bagof(X, P^(between(Position,Stop,P),nth1(P,List,X)), Sublist).
?- get_sublist([A,B,C,D,E,F,G,H,I,J,K], 3, 6, X).
X = [C, D, E, F, G, H].
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.
Here's my problem (by example since that's quicker):
?- enum_list([alpha, beta, gamma, beta, beta, delta, epsilon, alpha], L).
L = [alpha1, beta1, gamma, beta2, beta3, delta, epsilon, alpha2].
The problem is simple when I am allowed to reorder the list (just sort the list, group same elements into lists, enum the lists if they are longer than 1). But I want to keep the order. Any ideas?
How about:
enum_list(L, E):-
enum_list(L, E, [], _).
enum_list([], [], B, B).
enum_list([X|Tail], [Y|NTail], B, NB):-
select(X-C, B, MB),
succ(C, C1),
atom_concat(X, C1, Y),
!,
enum_list(Tail, NTail, [X-C1|MB], NB).
enum_list([X|Tail], [Y|NTail], B, NB):-
enum_list(Tail, NTail, [X-1|B], NB),
(member(X-1, NB) -> Y=X ; atom_concat(X, 1, Y)).
It iterates through the list and keeps a set of count of occurrences of each item so it knows when and what to append for each item to get the name.