Generate a 3d List - prolog

I am trying to make a List of Lists of Lists without values. If N_meses = 4 I want List =[[[A,B,C,D]]].
I get what I want ( List = [[[]]] ) but every lists have the same values as you can see in the print I attached. How can I change this code so every lists have a different "value"?
I am doing this
generate_table(Num_investigadores, Num_actividades, N_Meses, Tabela) :-
length(Row, Num_actividades),
length(X,N_Meses),
maplist(=(X), Row),
length(Tabela, Num_investigadores),
maplist(=(Row), Tabela).

The culprit is in essence the:
%% ...
maplist(=(X), Row),
%% ...
Here you basically defined a list X, and then you set with maplist/2 that all elements in Row are unified with that X. In the unification process. This thus means that all the elements of Row will in essence point to the same list.
Nevertheless, I think it would definitely help if you make the predicate less ambitious: implement helper predicates and let each predicate do a small number of things.
We can for example first design a predicate lengthlist/2 that is the "swapped" version of length/2, and thus has as first parameter the length and as second parameter the list, like:
lengthlist(N, L) :-
length(L, N).
Now we can construct a predicate that generates a 2d rectangular list, for example:
matrix(M, N, R) :-
lengthlist(M, R),
maplist(lengthlist(N), R).
here we thus first use lengthlist to construct a list with N elements, and then we use maplist/2 to call lengthlist(N, ...) on every element, such that every element is unified with a list of N elements. We thus construct a 2d list with M elements where every elements is a list of N elements.
Then finally we can construct a 3d tensor:
tensor3(L, M, N, T) :-
lengthlist(L, T),
maplist(matrix(M, N), T).
Here we thus construct an L×M×N tensor.
We can in fact generalize the above to construct a arbitrary deep cascade of lists that is "rectangular" (in the sense that for each dimension, the lists have the same number of elements), but I leave this as an exercise.

Related

Prolog compare list elements to Head element

I have predicate which shows all numbers which are smaller than 10.
small([H|T],H):- H=<10.
small([_|T],X):-small(T,X).
It is quite simple. But how should I change it so that I could compare every next item to the first element?
For example, ?- small([4,2,3,9,1,0,12],X). would show X=2;X=3;X=1;X=0 ?
You can split the problem in two procedures, one that takes the first element and then applies the recursion over the remaining elements of the list and checks whether each item is less than or equal to the first element:
small([M|T],X):- small1(T, M, X).
small1([H|_], M ,H):- H =< M.
small1([_|T], M, X):- small1(T, M, X).

Prolog Question - How to generate sublists of a given length

I want to generate all the sublists of a given list with the given property that they have a certain length mentioned as argument and also they have as a containing element a given element which is passed as a parameter. I have managed to do this but with the help of two predicates, and in terms of optimality is very slow:
sublist([], []).
sublist([A|T], [A|L]):-
sublist(T, L).
sublist(T, [_|L]):-
sublist(T, L).
choose(T, L):-
sublist(T, L),
(dimension(2, T); dimension(1, T)),
belongs(f, T).
In here I would like to return through the T parameter of the choose predicate all the sublists of the L list which have the dimension 2 or 1 and which contains the f element. The predicates dimension and member has the same usage as the predefined predicates length, respectively member.Can you please tell me how to incorporate this two conditions within the sublist predicate so that the program builds only those particular sublists?
The following builds subsequences of length MinLen =< Len =< MaxLen. I've no idea why you renamed length and member, so I'm going to use the originals. sublist/4 calls your sublist/2.
sublist(Sub,List,MinLen,MaxLen) :-
between(MinLen,MaxLen,Len),
length(Sub,Len),
sublist(Sub,List).
Note that length is called on two variables, so you get an iterative deepening search. choose/2 can now be defined as
choose(Sub,List) :-
sublist(Sub,List,1,2),
member(f,Sub).
This is the clean solution. If it's is not fast enough, then roll all the conditions into one predicate:
choose(Sub,List),
(Sub = [f] ; Sub = [f,_] ; Sub = [_,f]),
sublist(Sub,List).

create a list from a list of lists

I need to do the following: given a list of lists I need to find all possible combinations of the lists such that if some of these lists belong in such a combination, then they have no elements in common and the list created by appending the lists in the combination has a given length. Any ideas?
Example:
Say P= [[1,2,3],[4,5,6],[2,5],[7,9],[7,10],[8],[10]].
N a given number, say N=10. I need to search through P in order to find appropriate lists, with no elements in common, and add them in a list L such that the length of the union of L is 10. So in the above example :
L=[[1,2,3],[4,5,6],[7,9],[8],[10]]. It might be very easy but I'm new in Prolog
Given nobody's answered, and it's been quite a while since I've written anything in Prolog and I figured I needed the practice, here's how you'd do it.
First, to make generating the combinations easier, we create a term to preprocess the lists to pair them with their lengths to avoid having to get the lengths multiple times. The cut avoids needless backtracking:
with_lengths([], []) :- !.
with_lengths([H|T1], [(Len, H)|T2]) :-
length(H, Len),
with_lengths(T1, T2).
Here's the comb/3 predicate, which you use for generating the combinations:
comb(L, R, Max) :-
with_lengths(L, L1),
comb1(L1, R, Max).
comb1/3 does the actual work. The comments explain what's going on:
% Combination works.
comb1([], [], 0).
% Try combining the current element with the remainder.
comb1([(Len, Elem)|T1], [Elem|T2], Max) :-
NewMax is Max - Len,
comb1(T1, T2, NewMax).
% Alternatively, ignore the current element and try
% combinations with the remainder.
comb1([_|T1], T2, Max) :-
comb1(T1, T2, Max).

Prolog : Learning by example

I am trying to learn a little bit about swi-prolog (beyond the basic, useless programs).
Can anyone explain (perhaps in pseudocode) what this sudoku solver and the related functions are doing? If you need more reference it is found in the CLP(FD) package of swi-prolog.
Thanks!
:- use_module(library(clpfd)).
sudoku(Rows) :-
length(Rows, 9), maplist(length_(9), Rows),
append(Rows, Vs), Vs ins 1..9,
maplist(all_distinct, Rows),
transpose(Rows, Columns), maplist(all_distinct, Columns),
Rows = [A,B,C,D,E,F,G,H,I],
blocks(A, B, C), blocks(D, E, F), blocks(G, H, I).
length_(L, Ls) :- length(Ls, L).
blocks([], [], []).
blocks([A,B,C|Bs1], [D,E,F|Bs2], [G,H,I|Bs3]) :-
all_distinct([A,B,C,D,E,F,G,H,I]),
blocks(Bs1, Bs2, Bs3).
problem(1, [[_,_,_,_,_,_,_,_,_],
[_,_,_,_,_,3,_,8,5],
[_,_,1,_,2,_,_,_,_],
[_,_,_,5,_,7,_,_,_],
[_,_,4,_,_,_,1,_,_],
[_,9,_,_,_,_,_,_,_],
[5,_,_,_,_,_,_,7,3],
[_,_,2,_,1,_,_,_,_],
[_,_,_,_,4,_,_,_,9]]).
Prolog is a different way of thinking about programs: you have to think logically.
First of all A :- B, C, D means A is true (succeds) if B AND C AND D are true.
The snippet of code you posted checks for the correctness of a Sudoku puzzle, there are three condition:
elements are all different by rows
elements are all different by columns
elements are all different by 3x3 blocks
How does it work?
sudoku(Rows) is true if:
length(Rows, 9) -> there are 9 elements in rows
maplist(_length(9), Rows) -> maplist checks the predicate (first parameter) on every element of the list (second parameter). This means that every row must be of length 9.
maplist(all_distinct, Rows) -> same as before, but we check if every row has distinct (not equal pairwise) elements.
transpose(Rows, Columns), maplist(all_distinct, Columns) -> we transpose the rows into columns to check if they are all distinct also by selecting them in the vertical way
Rows = [A,B,C,D,E,F,G,H,I] -> splits rows list and place every one in a different variable A, B, C, D ... so A will be first row, B second one and so on
blocks(A, B, C), blocks(D, E, F), blocks(G, H, I) -> this predicate must be true for the triplets of rows.
Let's talk about the blocks part, that is quite funny to understand. We want to check that every 3x3 block contains distinct values. How can we do that?
Suppose to have 3 rows, the condition must be true for first three elements of every row (first 3x3 block), for elements 4th to 6th (second block) and 7th-9th (third block).
So we can think recursively: blocks([],[],[]) is trivially true, we've got empty lists.
The case blocks([A,B,C|Bs1],[D,E,F|Bs2],[G,H,I|Bs3]) is chosen when you call blocks predicate with parameters that are list with AT LEAST 3 elements. So we can check if A,B,C,D,E,F,G,H,I are all distinct, then we call blocks recursively using as parameters the remainder lists (without the first three elements). This is what Prolog is about!
So blocks will be called first with three rows of 9 elements, it will check that first 3 of every row are distinct and call itself with 3 lists of 6 elements, check it again and call itself with 3 lists of 3 elements, check it again and call itself with three empty lists (the trival case that always succeds).
sudoku/1 basically describes the constraints a Sudoku solution must satisfy, where the board is represented as a list of nine lists of length nine. problem/2 assigns a partially instantiated board to a problem number. To use it you should do
?- problem(1, Board), sudoku(Board).
You should read up on the predicates used in the documentation.
about "append(Rows, Vs), Vs ins 1..9"
http://www.swi-prolog.org/pldoc/man?predicate=append%2F2
It means that all elements of the list of lists must be in the domain 1..9.

Passing results in prolog

I'm trying to make a function that has a list of lists, it multiplies the sum of the inner list with the outer list.
So far i can sum a list, i've made a function sumlist([1..n],X) that will return X = (result). But i cannot get another function to usefully work with that function, i've tried both is and = to no avail.
Is this what you mean?
prodsumlist([], 1).
prodsumlist([Head | Tail], Result) :-
sumlist(Head, Sum_Of_Head),
prodsumlist(Tail, ProdSum_Of_Tail),
Result is Sum_Of_Head * ProdSum_Of_Tail.
where sumlist/2 is a SWI-Prolog built-in.
Usage example:
?- prodsumlist([[1, 2], [3], [-4]], Result).
Result = -36.
The part "it multiplies the sum of the inner list with the outer list" isn't really clear, but I believe you mean that, given a list [L1,...,Ln] of lists of numbers, you want to calculate S1*..*Sn where Si is the sum of the elements in Li (for each i).
I assume the existence of plus and mult with their obvious meaning (e.g. plus(N,M,R) holds precisely when R is equal to N+M). First we need predicate sum such that sum(L,S) holds if, and only if, S is the sum of the elements of L. If L is empty, S obviously must be 0:
sum([],0).
If L is not empty but of the form [N|L2], then we have that S must be N plus the sum S2 of the elements in L2. In other words, we must have both sum(L2,S2) (to get S2 to be the sum of the elements of L2) and plus(N,S2,S). That is:
sum([N|L2],S) :- sum(L2,S2), plus(N,S2,S).
In the same way you can figure out the predicate p you are looking for. We want that p(L,R) holds if, and only if, R is the product of S1 through Sn where L=[L1,...,Ln] and sum(Li,Si) for all i. If L is empty, R must be 1:
p([],1).
If L is not empty but of the form [LL|L2], then we have that R must be the product of 'S', the sum of the elements of LL, and 'P', the product of the sums of the lists in L2. For S we have already have sum(LL,S), so this gives us the following.
p([LL|L2],R) :- sum(LL,S), p(L2,P), mult(S,P,R).
One thing I would like to add is that it is probably not such a good idea to see these predicates as functions you might be used to from imperative or functional programming. It is not the case that sumlist([1,..,n],X) returns X = (result); (result) is a value for X such that sumlist([1,...,n],X) is true. This requires a somewhat different mindset. Instead of thinking "How can I calculate X such that p(X) holds?" you must think "When does P(X) hold?" and use the answer ("Well, if q(X) or r(X)!") to make the clauses (p(X) :- q(X) and p(X) :- r(X)).
Here is a rewrite of Kaarel's answer (that's the intention anyway!) but tail-recursive.
prodsumlist(List, Result) :-
xprodsumlist(List,1,Result).
xprodsumlist([],R,R).
xprodsumlist([Head|Rest],Sofar,Result) :-
sumlist(Head, Sum_Of_Head),
NewSofar is Sofar * Sum_Of_Head,
xprodsumlist(Rest, NewSofar, Result).

Resources