Merge lists of lists in prolog - list

I would like to perform something like:
merge([[[],[],[],[t1]],[[],[],[],[t2,t3]]], X).
where X would return as: [[],[],[],[t1,t2,t3]].
But I have tried everything to my prolog knowledge and came up with nothing.
Any hints?
Imagine it as:
Computer(
Tasklist1(
core1[sometasks],core2[sometasks],...,coreX(sometasks)),
...
TasklistX(
core1[sometasks],core2[sometasks],...,coreX(sometasks))
)
so the tasklist after tasklist1 needs to be scheduled on the same cores, after the tasks of tasklist1.

It's not totally clear what the limits of the problem may be. But here is a solution which assumes you may have more than two inner list-of-lists, and the count of the innermost lists might vary.
merge2(L, [], L) :- L \= [].
merge2([], L, L).
merge2([LH1|LT1], [LH2|LT2], [LH3|LT3]) :-
append(LH1, LH2, LH3),
merge2(LT1, LT2, LT3).
merge([L], L).
merge([H1,H2|T], R) :-
merge2(H1, H2, H),
merge([H|T], R).
So,
| ?- merge([[[],[],[],[t1]],[[],[],[],[t2,t3]]], L).
L = [[],[],[],[t1,t2,t3]] ? ;
no
| ?- merge([[[1],[2],[3]], [[4],[5],[6]],[[a],[b],[c,d]]], L).
L = [[1,4,a],[2,5,b],[3,6,c,d]] ? a
no
| ?- merge([[[1],[2],[3]], [[5],[6]],[[a],[b],[c,d]]], L).
L = [[1,5,a],[2,6,b],[3,c,d]] ? ;
(1 ms) no
| ?-
If you want to restrict the innermost list counts to be the same, you can replace merge2 with maplist, and the merge predicate simply becomes:
merge([L], L).
merge([H1,H2|T], R) :-
maplist(append, H1, H2, H),
merge([H|T], R).

I thought it could be easier...
merge(L, R) :-
maplist(length_list(N), L),
findall(S, (
between(1,N,I),
findall(Zs, (
member(Z,L),
nth1(I,Z,Zs)), T),
append(T, S)), R).
length_list(Len, L) :- length(L, Len).

Related

Simple square program in Prolog

Why is following simple program not working?
main :-
squares([1,2,3,4,5], L),
writeln(L).
squares([H|T], Outl) :-
Sq is H*H,
squares(T, [Sq|Outl]).
squares([], []).
The output is:
?- main.
false.
Replacing Outl with [Outl] ( in squares([H|T], Outl) ) does not help.
Using = and #= instead or is also did not help.
Nor did squares([], P) instead of squares([], []).
This is a great candidate for maplist.
Define squaring of one element:
squared(X, XX) :- XX #= X * X.
Then apply maplist:
squared_list(L, LL) :- maplist(squared, L, LL).
By using #= here instead of is/2, it's behavior is more relational:
| ?- squared_list([1,2,3], L).
L = [1,4,9]
yes
| ?- squared_list(L, [1,4,9]).
L = [1,2,3] ? ;
(1 ms) no
| ?-
Look at what you have written
squares([H|T],Outl):-
Sq is H*H,
squares(T,[Sq|Outl]).
Sq is misplaced, you should write
squares([H|T],[Sq|Outl]):-
Sq is H*H,
squares(T,Outl).
You add Sq at the result of the computation of the rest of the list T.

How to check different between two list integers are greater than or equal to 2?

Given two sorted lists Xs and Ys, how do I ensure the absolute difference between any X in Xs and any Y in Ys is at least two?
Sample queries with expected answers:
?- different([1,2,4],[5,6]). % 5-4 < 2
false
?- different([1,4],[2,6]). % 2-1 < 2
false
?- different([1,2,6],[4,8]). % 4-2 >= 2 and 6-4 >= 2 and 8-6 >= 2
true
?- different([],[4]).
true
How can I get to this result? Any ideas? Thank you!
Edit: Here is the code I have now:
difference([], []).
difference([_|_], []).
difference([], [_|_]).
difference(L1, L2) :-
L1 = [X1|X2],
L2 = [Y1|_],
Dif is X1-Y1,
(-1>Dif|Dif>1),
difference(X2, L2).
In this answer we use clpfd to attain both
versatility and optimum (linear) arithmetic complexity.
diff_to_mdist([], _, _).
diff_to_mdist([_|_], [], _).
diff_to_mdist([X|Xs], [Y|Ys], D) :-
( X #=< Y-D, diff_to_mdist(Xs, [Y|Ys], D)
; X #> Y-D, X #>= Y+D, diff_to_mdist([X|Xs], Ys, D)
).
diff_to_mdist([X0,X1|Xs], [Y0,Y1|Ys], D) :-
X0 #> Y0-D, X0 #< Y0+D,
( X0 #< Y0, X0 #=< Y0-D, X1 #>= Y0+D, diff_to_mdist([X0,X1|Xs], [Y1|Ys], D)
; X0 #> Y0, Y0 #=< X0-D, Y1 #>= X0+D, diff_to_mdist([X1|Xs], [Y0,Y1|Ys], D)
).
Let's use gnu-prolog version 1.4.4 and run queries like the ones suggested by the OP!
| ?- diff_to_mdist([1,2,4], [5,6], 2).
no
| ?- diff_to_mdist([1,4], [2,6], 2).
no
| ?- diff_to_mdist([1,2,6], [4,8], 2).
true ? ;
no
| ?- diff_to_mdist([], [4], 2).
yes
First, you can make your current code a lot neater and easier to read as follows:
different([], []).
different([_|_], []).
different([], [_|_]).
different([X|Xs], [Y|Ys]) :-
abs(X-Y) >= 2, % Prolog evaluates arithmetic expressions for compares
different(Xs, [Y|Ys]).
In this case, you've done one level of the recursion I mentioned in my comment, as it only checks each element of the first list against only the first element of the second. It ignores all the other elements of the second list. So you need to break it down further. You could make a helper predicate which compares each element of a list against a single value. Then have your main predicate call this helper predicate with each element of the other list. The main predicate would then look like:
different([], []).
different([], [_|_]).
different([X|Xs], L) :-
different_element(X, L),
different(Xs, L).
Then the helper predicate would be:
% This predicate succeeds if the first argument has the desired difference
% to each of the elements of the second argument (a list)
%
different_element(_, []).
different_element(X, [Y|Ys]) :-
abs(X-Y) >= 2,
different_element(X, Ys).

Prolog: Take the first "N" elements of a list

I need to write a Prolog predicate take(L, N, L1) which succeeds if list L1 contains the first N elements of list L, in the same order. For example:
?- take([5,1,2,7], 3, L1).
L1 = [5,1,2]
?- take([5,1,2,7], 10, L1).
L1 = [5,1,2,7]
Prolog thus far is making little sense to me, and I'm having a hard time breaking it down. Here is what I have so far:
take([H|T], 0, []).
take([H|T], N, L1) :-
take(T, X, L2),
X is N-1.
Can you please explain what I did wrong here?
Here is a definition that implements the relational counterpart to take in functional languages like Haskell1. First, the argument order should be different which facilitates partial application. There is a cut, but only after the error checking built-in (=<)/2 which produces an instantiation_error should the argument contain a variable.
take(N, _, Xs) :- N =< 0, !, N =:= 0, Xs = [].
take(_, [], []).
take(N, [X|Xs], [X|Ys]) :- M is N-1, take(M, Xs, Ys).
?- take(2, Xs, Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_B|_C], Ys = [_A,_B].
Note how above query reads:
How can one take 2 elements from Xs to get Ys?
And there are 3 different answers. If Xs is empty, then so is Ys. If Xs is a list with one element, then so is Ys. If Xs has at least 2 elements, then those two are Ys.
1) The only difference being that take(-1, Xs,Ys) fails (for all Xs, Ys). Probably the best would be to issue a domain_error similar to arg(-1,s(1),2)
findall/3 it's a bit the 'swiss knife' of Prolog. I would use this snippet:
take(Src,N,L) :- findall(E, (nth1(I,Src,E), I =< N), L).
The code by #CapelliC works if the instantiation is right; if not, it can show erratic behavior:
?- take(Es, 0, Xs).
**LOOPS** % trouble: goal does not terminate
?- take([A,_], 1, [x]).
true. % trouble: variable A remains unbound
To safeguard against this you can use
iwhen/2 like so:
take(Src, N, L) :-
iwhen(ground(N+Src), findall(E, (nth1(I,Src,E), I =< N), L)).
Sample queries run with SWI-Prolog 8.0.0:
?- take([a,b,c,d,e,f], 3, Ls).
Ls = [a,b,c].
?- take([a,b,c,d,e,f], N, Ls).
ERROR: Arguments are not sufficiently instantiated
?- take(Es, 0, Xs).
ERROR: Arguments are not sufficiently instantiated
?- take([A,_], 1, [x]).
ERROR: Arguments are not sufficiently instantiated
Safer now!
The obvious solution would be:
take(List, N, Prefix) :-
length(List, Len),
( Len =< N
-> Prefix = List
; length(Prefix, N),
append(Prefix, _, List)
).
Less thinking means less opportunity for mistakes. It also makes the predicate more general.
your base case is fine
take([H|T], 0, []).
And also you can say what if N is 1
take([H|T],1,[H]).
But you recursive case some variable is not defined like L2. So we can write this as
take([X|T1],N,[X|T2]):-
N>=0,
N1 is N-1,
take(T1,N1,T2).
which case all varibles are pattern-matched.
take(L, N, L1) :- length(L1, N), append(L1, _, L).
This is performant, general and deterministic:
first_elements_of_list(IntElems, LongLst, ShortLst) :-
LongLst = [H|T],
( nonvar(IntElems) -> Once = true
; is_list(ShortLst) -> Once = true
; Once = false
),
first_elements_of_list_(T, H, 1, IntElems, ShortLst),
(Once = true -> ! ; true).
first_elements_of_list_([], H, I, I, [H]).
first_elements_of_list_([_|_], H, I, I, [H]).
first_elements_of_list_([H|LongLst], PrevH, Upto, IntElems, [PrevH|ShortLst]) :-
Upto1 is Upto + 1,
first_elements_of_list_(LongLst, H, Upto1, IntElems, ShortLst).
Result in swi-prolog:
?- first_elements_of_list(N, [a, b, c], S).
N = 1,
S = [a] ;
N = 2,
S = [a,b] ;
N = 3,
S = [a,b,c].
?- first_elements_of_list(2, [a, b, c], S).
S = [a,b].
Below is a variant which also supports:
?- first_elements_of_list_more(10, [5, 1, 2, 7], L1).
L1 = [5,1,2,7].
first_elements_of_list_more(IntElems, [H|LongLst], [H|ShortLst]) :-
once_if_nonvar(IntElems, first_elements_of_list_more_(LongLst, 1, IntElems, ShortLst)).
first_elements_of_list_more_([], Inc, Elems, []) :-
(var(Elems) -> Inc = Elems
; Elems >= Inc).
first_elements_of_list_more_([_|_], E, E, []).
first_elements_of_list_more_([H|LongLst], Upto, IntElems, [H|ShortLst]) :-
succ(Upto, Upto1),
first_elements_of_list_more_(LongLst, Upto1, IntElems, ShortLst).
once_if_nonvar(Var, Expr) :-
nonvar(Var, Bool),
call(Expr),
(Bool == true -> ! ; true).
nonvar(Var, Bool) :-
(nonvar(Var) -> Bool = true ; Bool = false).

Prolog. Sum of the elements of two lists of different length

Please help me!
I need to find sum of the elements of two lists of different length.
It should look like:
?-p([1,2,3],[1,2,3,9],L),write(L),nl.
L = [2,4,6,9].
p([],_,[]).
p(_,[],[]).
p([H1|T1],[H2|T2],[H|T]):-H is H1 + H2,p(T1,T2,T).
?-p([1,2,3],[1,2,3],L),write(L),nl.
So I've got some troubles with different length of lists. I don't know how to do it.
Thanks for your help! Tanya.
I prefer shorter, deterministic code, where possible:
p([X|Xs], [Y|Ys], [Z|Zs]) :-
Z is X + Y,
!, p(Xs, Ys, Zs).
p([], Ys, Ys) :- !.
p(Xs, [], Xs).
This should work:
p([], [], []).
p([], [H2|T2], [L|Ls]) :-
L = H2,
p([], T2, Ls).
p([H1|T1], [], [L|Ls]) :-
L = H1,
p(T1, [], Ls).
p([H1|T1], [H2|T2], [L|Ls]) :-
L is H1 + H2,
p(T1, T2, Ls).
Explanation:
As long as there are elements in both lists, they get added and 'prepended' to L. Whenever there is 1 list empty, it will just 'prepend' them to L without adding it. When both are empty, the recursivity stops.

Working with list of lists in Prolog

Please help me to solve this problem:
I have a list of lists
[[1,2],[3,4]]
How do I get:
[1,3]
[1,4]
[2,3]
[2,4]
Or if I have a list of lists
[[1,2],[3,4],[6,7]]
How do I get:
[1,3,6]
[1,3,7]
[1,4,6]
[1,4,7]
[2,3,6]
[2,3,7]
[2,4,6]
[2,4,7]
The predicate for accessing a single list element is the most basic Prolog building block: member/2.
And you want a list of all lists' elements: maplist/3 does such mapping. Thus we can write
combine(Ls, Rs) :-
maplist(get1, Ls, Rs).
get1(L, E) :-
member(E, L).
note that get1/2 is only required so that we swap the member/2 arguments. But because in (pure) Prolog we are describing relations between arguments, we can swap arguments' order and simplify it even more:
combine(Ls, Rs) :-
maplist(member, Rs, Ls).
Test output:
?- combine( [[1,2],[a,b]], Xs).
Xs = [1, a] ;
Xs = [1, b] ;
Xs = [2, a] ;
Xs = [2, b].
%% this is the same as:
%% maplist( member, Xs, [[1,2],[a,b]]) :-
%% member( X1, [1,2] ),
%% member( X2, [a,b]), Xs = [X1,X2].
edit
A joke: really, my first combine/2 should have been written like
combine(Ls, Rs) :-
maplist(rebmem, Ls, Rs).
rebmem(L, E) :-
member(E, L).
You can do something like this:
lists([], []).
lists([[Head|_]|Lists], [Head|L]):-
lists(Lists, L).
lists([[_,Head|Tail]|Lists], L):-
lists([[Head|Tail]|Lists], L).
That is, take the first element of the first list in your input list and continue recursively with the remaining lists. As a second chance, skip that element and redo with the remaining elements.