Transposing a Matrix in prolog - prolog

I have written the following code below to transpose a Matrix in prolog
listFirst([],[]).
listFirst([H1|T1],[H2|Z]):-
H1 = [H2|_],
listFirst(T1,Z).
listFollowers([],[]).
listFollowers([H1|T1],[T2|Z]):-
H1 = [H2|T2],
listFollowers(T1,Z).
decompose(A,L1,L2):-
listFollowers(A,L2),listFirst(A,L1).
transpose([],[]).
transpose([H|T],[L1|R]):-
decompose([H|T],L1,L2),
transpose(L2,R).
Test Case
transpose([[1,2],[3,4],[5,6]], R).
R = [[1,3,5],[2,4,6]] ;
I am having problems with the transpose predicate no sure how to implement this. Other predicates seem to work okay.

Taken from library(clpfd) in SWI-Prolog (see the source code for more information):
transpose([], []).
transpose([L|Ls], Ts) :- foldl(transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :-
maplist(list_first_rest, Lists0, Fs, Lists).
list_first_rest([L|Ls], L, Ls).
Example query:
?- transpose([[a,b,c],[d,e,f]], Ts).
Ts = [[a, d], [b, e], [c, f]].

my old code - rather efficient tough
transpose_col_row([], []).
transpose_col_row([U], B) :- gen(U, B).
transpose_col_row([H|T], R) :- transpose_col_row(T, TC), splash(H, TC, R).
gen([H|T], [[H]|RT]) :- gen(T,RT).
gen([], []).
splash([], [], []).
splash([H|T], [R|K], [[H|R]|U]) :-
splash(T,K,U).

This might help.
If you change the base case in order to have the lists of lists to a complete list it will work. Even though it probably won`t be the most efficient method, since it will only be able to get up to 4 lists. This means a matrix of four rows.
transpose([[X],[Y],[Z],[B]],[[X,Y,Z,B]]).
transpose([H|T],[L1|R]):-
decompose([H|T],L1,L2),
transpose(L2,R).

Related

Prolog: Swapping two halves of a list

I am writing a predicate in prolog that will break a list with an even number of variables into two halves and swap them. For example [a,b,c,d] --> [c,d,a,b].
append([], List, List).
append([Head|Tail], List, [Head|Rest]) :-
append(Tail, List, Rest).
divide(L, X, Y) :-
append(X, Y, L),
length(X, N),
length(Y, N).
swap([], []).
swap([A], D) :-
divide(A, B, C),
append(C, B, D).
I would expect this to work by dividing [A] into two smaller equal sized lists, then appending them together in the reverse order, and then assigning the variable "D" to the list.
What I am getting is "false", why does this not work?
I'm very new to prolog so this might be a silly/simple question, thanks!
Your question is why swap([a,b,c,d],[c,d,a,b]) fails. And here is the actual reason:
?- swap([_/*a*/,_/*b*/|_/*,c,d*/],_/*[c,d,a,b]*/).
:- op(950, fy, *).
*(_).
swap([], _/*[]*/).
swap([A], D) :-
* divide(A, B, C),
* append(C, B, D).
So, not only does your original query fail, but even this generalization fails as well. Even if you ask
?- swap([_,_|_],_).
false.
you just get failure. See it?
And you can ask it also the other way round. With above generalization, we can ask:
?- swap(Xs, Ys).
Xs = []
; Xs = [_A].
So your first argument must be the empty list or a one-element list only. You certainly want to describe also longer lists.
Maybe this helps
:- use_module(library(lists), []).
divide(L, X, Y) :-
append(X, Y, L),
length(X, N),
length(Y, N).
swap([], []).
swap(L, D) :-
divide(L, B, C),
append(C, B, D).

How to create list of list

I having a problem with predicate which creates list of list for example
?-listoflist([p v q, p, r], R).
R=[ [p,q],[p],[r] ]
So far i have:
:- op(500, xfy, v).
listoflist([],[]):-!.
listoflist([H], [[H]]):-!
listoflist([H|T], [Result]):-
change_to_list(H,Tmp),
listoflist(T, [Tmp|Result])..
change_to_list(X v Y, [X|List]):-
change_to_list(Y,List),!.
change_to_list(X,[X]).
For operator declarations, always look what Prolog already has and fit your own operators into it:
?- current_op(Pri,Fix,\/).
Pri = 500, Fix = yfx.
A left-associative operator makes much more sense here. Maybe you can reuse this, instead of defining your own? And in case you want your own, take the very same priorities.
:- op(500, yfx, v).
operands(Op) --> [Op], {functor(Op,Op,0)}.
operands(L v R) --> operands(L), operands(R).
expr_operands(Expr, Ops) :-
phrase(operands(Expr), Ops).
?- maplist(expr_operands, [p v q, p, r], R).
R = [[p,q],[p],[r]].
Your listoflists/2 should be simpler and doesn't need cuts:
listoflists([], []).
listoflists([X|Xs], [Y|Ys]) :-
change_to_list(X, Y),
listoflists(Xs, Ys).
The other predicate, change_to_list/2 seems fine to me.
Notice how you collect the results in the head of the clause, not in the recursive call!

Append list of lists elements in Prolog

I'm learning Prolog for about a week, so I'm a newbie.
I'm trying to do a function, that appends, the elements of a list of lists.
So the input would be: [ [[a,b,c],[g,h,i]], [[j,k,l],[m,n,o]], [[s,t,u],[v,w,x]] ].
And the output would be : [ [a,b,c,j,k,l,s,t,u], [g,h,i,m,n,o,v,w,x] ].
Or
Input: [ [[a,b], [c,d]], [[e,f], [g,h]], [[i,j],[k,l]] ].
Output: [ [a,b,e,f,i,j], [c,d,g,h,k,l] ].
It would be important, that it has to work with a lot of elements, not only 3.
I wrote this, but it only works with 2 elements, so i can only do it, with pairs.
merge([],[],[]).
merge(L1,[],L1).
merge([H1|T1],[H2|T2],LL):-
append(H1, H2, HE),
merge(T1,T2,TE),
append([HE], TE, LL).
If I understand your question correctly...
First, if you know that your input has exactly two levels of nesting in it, and if your Prolog had higher-order predicates for mapping and for folding, and if you could compose them, you could simply write:
merge_foldl([], []).
merge_foldl([X|Xs], R) :-
reverse([X|Xs], [Y|Ys]),
foldl(maplist(append), Ys, Y, R).
This works as expected for SWI-Prolog.
Here it is with your two examples:
?- merge_foldl([ [[a,b,c],[g,h,i]], [[j,k,l],[m,n,o]], [[s,t,u],[v,w,x]] ], R).
R = [[a, b, c, j, k, l, s, t, u], [g, h, i, m, n, o, v, w, x]].
?- merge_foldl([ [[a,b], [c,d], [e,f]], [[g,h], [i,j], [k,l]] ], R).
R = [[a, b, g, h], [c, d, i, j], [e, f, k, l]].
If you don't have access to neither foldr nor foldl, you would have to hardcode the folding:
merge([], []).
merge([X|Xs], Result) :-
merge_maplist(Xs, X, Result).
merge_maplist([], Result, Result).
This is not all, but it says that if you are at the end of the list of lists, the last element is the result.
Now you have to define the step where you append to the front of each sublist. This is easier with maplist:
merge_maplist([X|Xs], Prev, Result) :-
merge_maplist(Xs, X, Result0),
maplist(append, Prev, Result0, Result).
Note that here we are "emulating" a right fold by using a non-tail-recursive definition: we are doing the appending in reverse, after the recursive step. For a tail-recursive definition (identical to hard-coded left fold), you would have to reverse the original list first!
So you keep on peeling off one list of lists from your input until you are done. Then, you use maplist to apply append/3 to each pair of lists from the previous element and the result so far, to get the final result.
If you don't have access to maplist either, you'd have to hardcode the mapping as well. For the three arguments that append/3 takes:
map_append([], [], []).
map_append([X|Xs], [Y|Ys], [Z|Zs]) :-
append(X, Y, Z),
map_append(Xs, Ys, Zs).
and your merge/2 and merge_/3 become:
merge([], []).
merge([X|Xs], Result) :-
merge_(Xs, X, Result).
merge_([], Result, Result).
merge_([X|Xs], Prev, Result) :-
merge_(Xs, X, Result0),
map_append(Prev, Result0, Result).
This is a lot of code for something that can be solved quite nicely if you have higher-order predicates.

Searching Prolog structures

I'm interested in formulae made up from lots of conjunctions (part of a larger problem). I want to write a program that takes something like this:
:- get_params(conj(conj(a,b),c),X)
and returns a list of all the parameters of the conjunctions i.e. X=[a,b,c]. At the moment I can do
:- get_params(conj(a,b),X) to get X=[a,b]
using simple Prolog pattern matching but how would you go about doing things such as
:- get_params(conj(conj(a,b),c),X) to get X=[a,b,c]
It seems really simple but I've been struggling all day!
Since you are describing a list, consider using DCG notation:
params(conj(A,B)) --> !, params(A), params(B).
params(X) --> [X].
Example:
?- phrase(params(conj(conj(a,b),c)), Ps).
Ps = [a, b, c].
Assuming that all conj functors are binary:
get_params(X, Y, L) :-
get_params(X, L1),
get_params(Y, L2),
append(L1, L2, L).
get_params(conj(X, Y), L) :-
get_params(X, Y, L), !.
get_params(A, [A]).

Prolog: Getting unique atoms from propositional formulas

I can easily write a predicate to get unique elements from a given list in Prolog e.g.
no_doubles( [], [] ).
no_doubles( [H|T], F ) :-
member( H, T ),
no_doubles( T, F ).
no_doubles( [H|T], [H|F] ) :-
\+ member( H, T ),
no_doubles( T, F ).
However, how can you do the same thing but for something other than a normal list i.e. not something like [a,b,c...]? So in my case, I want to extract unique atoms for a propositional formula e.g. unique_atoms(and(x,and(x,y),z),[x,y,z]). is satisfied. Do you use recursion just like in my no_doubles example but for a formula like this?
Any ideas are welcomed :). Thanks.
So you need to process a general term (i.e. a tree structure) and get a list of its atomic leaf nodes, without duplicates. Does the result list have to have a specific order (e.g. depth-first left-to-right), or is this not important?
If you have an option to use variables instead of atoms in your formulas then you can use the (SWI-Prolog) builtin term_variables/2, e.g.
?- term_variables(and(X, and(X, Y), Z), Vars).
Vars = [X, Y, Z].
Otherwise you have to go with a solution similar to:
term_atoms(Term, AtomSet) :-
term_to_atomlist(Term, AtomList),
list_to_set(AtomList, AtomSet).
term_to_atomlist(Atom, [Atom]) :-
atom(Atom),
!.
term_to_atomlist(Term, AtomList) :-
compound(Term),
Term =.. [_ | SubTerms],
terms_to_atomlist(SubTerms, AtomList).
terms_to_atomlist([], []).
terms_to_atomlist([Term | Terms], AtomList) :-
term_to_atomlist(Term, AtomList1),
terms_to_atomlist(Terms, AtomList2),
append(AtomList1, AtomList2, AtomList).
Usage example:
?- term_atoms(f(x^a1+a3*a3/a4)='P'-l, Atoms).
Atoms = [x, a1, a3, a4, 'P', l].
You might want to extend it to deal with numbers and variables in the leaf nodes.
?- setof(X, member(X,[a,b,c,a,b,c]), L).
L = [a, b, c].
?- sort([a,b,c,a,b,c], L).
L = [a, b, c].
Propositional formulas:
get_atoms(X,[X]) :-
atom(X).
get_atoms(and(P,Q),Atoms) :-
get_atoms(P,Left),
get_atoms(Q,Right),
append(Left,Right,Atoms).
etc. Optimize using difference lists if necessary.
unique_atoms(P,UniqueAtoms) :- get_atoms(P,Atoms), sort(Atoms,UniqueAtoms).
A more direct way is to use sets.

Resources