printing pairs of a list in SWI-prolog - prolog

basically, I want to print pairs from one list like this
?- [1 2 3 4 5,R]
the output is
R = [1, 2]
R = [1, 3]
R = [1, 4]
R = [1, 5]
R = [2, 3]
R = [2, 4]
R = [2, 5]
R = [3, 4]
R = [3, 5]
R = [4, 5]
I used the code that creates subsets and modified it
sub(0,_,[]).
sub(N,[X|T],[X|R]):-N>0,N1 is N-1,sub(N1,T,R).
sub(N,[_|T],R):-N>0,sub(N,T,R).
and I would call
sub(2,[1,2,3,4,5],R)
but is there a way to do it without using a counter?

Prolog is about defining relations (in the form of rules) and to try to avoid thinking procedurally (steps of execution to achieve a result). You can solve this by breaking it down into simple rules for the pairs:
For a list with head H and tail T, a valid pair is [H,E] where E is a member of T.
For a list with head H and tail T, a valid pair is a pair taken from T.
If you think about these rules, they are (1) mutually exclusive (there isn't a solution that matches both rules), and (2) they are complete (they cover all of the valid solutions).
Writing these in Prolog, you get:
pair([H|T], [H,E]) :- member(E, T).
pair([_|T], P) :- pair(T, P).
This provides a relational solution which yields:
| ?- sub([a,b,c,d], S).
S = [a,b] ? ;
S = [a,c] ? ;
S = [a,d] ? ;
S = [b,c] ? ;
S = [b,d] ? ;
S = [c,d] ? ;
(1 ms) no
| ?-
And works in a more general case:
| ?- pair(L, P).
L = [A,B]
P = [A,B] ? ;
L = [A,B|_]
P = [A,B] ? ;
L = [A,_,B|_]
P = [A,B] ? ;
L = [A,_,_,B|_]
P = [A,B] ? ;
...

an easy way:
?- L = [1,2,3,4,5], forall((nth1(I,L,X), nth1(J,L,Y), I<J), writeln(I/J)).
1/2
1/3
1/4
1/5
2/3
2/4
2/5
3/4
3/5
4/5
L = [1, 2, 3, 4, 5].

Yes, there is, since you don't have to account for subsets of arbitrary length.
There are two steps you need to account for, and both have two variants.
Select the first element of the pair:
Use the head of the list
Discard the head and pick it out of the tail of the list
Select the second element of the pair:
Use the head of the list
Discard the head and pick it out of the tail of the list
% Use the head as the first element
pairs((H, P2), [H | T]) :- pairs((H, P2), T).
% If we have the first element, use the head as the second element
pairs((P1, H), [H | _]) :- nonvar(P1).
% Ignore the head and pick what we need out of the tail
pairs(P, [_ | T]) :- pairs(P, T).

Related

Calculate whether the sum of exactly three values in a list is equal to N

Examples: ([1,2,3,7,6,9], 6). should print True, as 1+2+3=6.
([1,2,3,7,6,9], 5). should print False as there are no three numbers whose sum is 5.
([],N) where N is equal to anything should be false.
Need to use only these constructs:
A single clause must be defined (no more than one clause is allowed).
Only the following is permitted:
+, ,, ;, ., !, :-, is, Lists -- Head and Tail syntax for list types, Variables.
I have done a basic coding as per my understanding.
findVal([Q|X],A) :-
[W|X1]=X,
[Y|X2]=X,
% Trying to append the values.
append([Q],X1,X2),
% finding sum.
RES is Q+W+Y,
% verify here.
(not(RES=A)->
% finding the values.
(findVal(X2,A=)->
true
;
(findVal(X,A)->
% return result.
true
;
% return value.
false))
;
% return result.
true
).
It does not seem to run throwing the following error.
ERROR:
Undefined procedure: findVal/2 (DWIM could not correct goal)
Can someone help with this?
You can make use of append/3 [swi-doc] here to pick an element from a list, and get access to the rest of the elements (the elements after that element). By applying this technique three times, we thus obtain three items from the list. We can then match the sum of these elements:
sublist(L1, S) :-
append(_, [S1|L2], L1),
append(_, [S2|L3], L2),
append(_, [S3|_], L3),
S is S1 + S2 + S3.
Well, you can iterate (via backtracking) over all the sublists of 3 elements from the input list and see which ones sum 3:
sublist([], []).
sublist([H|T], [H|S]) :- sublist(T, S).
sublist([_|T], S) :- sublist(T, S).
:- length(L, 3), sublist([1,2,3,7,6,9], L), sum_list(L, 6).
I'm giving a partial solution here because it is an interesting problem even though the constraints are ridiculous.
First, I want something like select/3, except that will give me the tail of the list rather than the list without the item:
select_from(X, [X|R], R).
select_from(X, [_|T], R) :- select_from(X, T, R).
I want the tail, rather than just member/2, so I can recursively ask for items from the list without getting duplicates.
?- select_from(X, [1,2,3,4,5], R).
X = 1,
R = [2, 3, 4, 5] ;
X = 2,
R = [3, 4, 5] ;
X = 3,
R = [4, 5] ;
X = 4,
R = [5] ;
X = 5,
R = [] ;
false.
Yeah, this is good. Now I want to build a thing to give me N elements from a list. Again, I want combinations, because I don't want unnecessary duplicates if I can avoid it:
select_n_from(1, L, [X]) :- select_from(X, L, _).
select_n_from(N, L, [X|R]) :-
N > 1,
succ(N0, N),
select_from(X, L, Next),
select_n_from(N0, Next, R).
So the idea here is simple. If N = 1, then just do select_from/3 and give me a singleton list. If N > 1, then get one item using select_from/3 and then recur with N-1. This should give me all the possible combinations of items from this list, without giving me a bunch of repetitions I don't care about because addition is commutative and associative:
?- select_n_from(3, [1,2,3,4,5], R).
R = [1, 2, 3] ;
R = [1, 2, 4] ;
R = [1, 2, 5] ;
R = [1, 3, 4] ;
R = [1, 3, 5] ;
R = [1, 4, 5] ;
R = [2, 3, 4] ;
R = [2, 3, 5] ;
R = [2, 4, 5] ;
R = [3, 4, 5] ;
false.
We're basically one step away now from the result, which is this:
sublist(List, N) :-
select_n_from(3, List, R),
sumlist(R, N).
I'm hardcoding 3 here because of your problem, but I wanted a general solution. Using it:
?- sublist([1,2,3,4,5], N).
N = 6 ;
N = 7 ;
N = 8 ;
N = 8 ;
N = 9 ;
N = 10 ;
N = 9 ;
N = 10 ;
N = 11 ;
N = 12 ;
false.
You can also check:
?- sublist([1,2,3,4,5], 6).
true ;
false.
?- sublist([1,2,3,4,5], 5).
false.
?- sublist([1,2,3,4,5], 8).
true ;
true ;
false.
New users of Prolog will be annoyed that you get multiple answers here, but knowing that there are multiple ways to get 8 is probably interesting.

Find the lower peaks of the list

Help, please, find the lower peaks of the list. For example, given an array [1,5,4,6,3] the answer would be [1,4,3]
lower_peaks([X,Y|T],[X|L]):-X<Y,lp2([Y|T],L).
lower_peaks([X,Y|T],L):-lp2([X,Y|T],L).
lp2([X,Y],[Y]):-Y<X.
lp2([_,_],[]).
lp2([X,Y,Z|T],[Y|L]):-Y<X,Y<Z,lp2([Y,Z|T],L).
lp2([X,Y,Z|T],L):-lp2([Y,Z|T],L).
The problem is multiple answers:
?- lower_peaks([1,5,4,6,3],V).
V = [1, 4, 3] ;
V = [1, 4] ;
V = [1, 3] ;
V = [1] ;
V = [4, 3] ;
V = [4] ;
V = [3] ;
V = [] ;
false.
Complete code:
lower_peaks(L,R) :-
lower_peaks_start(L,R).
lower_peaks([_],[]).
lower_peaks([],[]).
lower_peaks_start([X,Y|T],[X|L]) :-
X<Y,
lower_peaks_middle([Y|T],L).
lower_peaks_start([X,Y|T],L) :-
\+ (X<Y),
lower_peaks_middle([Y|T],L).
lower_peaks_middle([X,Y,Z|T],[Y|L]) :-
Y<X, Y<Z,
lower_peaks_middle([Y,Z|T],L).
lower_peaks_middle([X,Y,Z|T],L) :-
\+ (Y<X, Y<Z),
lower_peaks_middle([Y,Z|T],L).
lower_peaks_middle([X,Y],L) :-
lower_peaks_end([X,Y],L).
lower_peaks_end([X,Y],[Y]) :-
Y<X.
lower_peaks_end([X,Y],[]) :-
\+ (Y<X).
Example run:
?- lower_peaks([1,5,4,6,3],V).
V = [1, 4, 3] ;
false.
There were several problems with the code.
The code had guards, e.g. X<Y for the one predicate, but either a cut (!) or better a not guard \+ (X<Y) for the matching predicate was needed.
The code transitioned from the start of the list to the middle, e.g. lower_peaks then to lp2 but did not transition for the end.
The code needed base cases for a list of one or no items.
The code needed a way to transition from the start of list to the end of list if there was no middle.

SWI-Prolog Delete items that have pair occurrences

I need a solution that deletes elements that have pairs of occurrences from list.
I did it in haskell, but i don't have any ideas how to interpretate it in Prolog.
For example [1,2,2,2,4,4,5,6,6,6,6] -> [1,2,2,2,5]
Code in Haskell :
import Data.List
count e list = length $ filter (==e) list
isnotEven = (== 1) . (`mod` 2)
removeUnique :: [Int] -> [Int]
removeUnique list = filter (\x -> isnotEven (count x list) ) list
The following follows your Haskell code.
You need library(reif) for SICStus|SWI.
:- use_module(reif).
oddcount_t(List, E, T) :- % reified: last argument is truth value
tfilter(=(E), List, Eqs),
length(Eqs, Nr),
M is Nr mod 2,
=(M, 1, T).
removeevenocc(List, RList) :-
tfilter(oddcount_t(List), List, RList).
?- removeevenocc([1,2,2,2,4,4,5,6,6,6,6], R).
R = [1,2,2,2,5].
?- removeevenocc([1,X], R).
X = 1, R = []
; R = [1, X],
dif(X, 1).
Note the last question. Here, the list was not entirely given: The second element is left unknown. Therefore, Prolog produces answers for all possible values of X! Either X is 1, then the resulting list is empty, or X is not 1, then the list remains the same.
this snippet uses some of the libraries (aggregate,lists,yall) available, as well as some builtins, like setof/3, and (=:=)/2:
?- L=[1,2,2,2,4,4,5,6,6,6,6],
| setof(K,C^(aggregate(count,member(K,L),C),0=:=C mod 2),Ds),
| foldl([E,X,Y]>>delete(X,E,Y),Ds,L,R).
L = [1, 2, 2, 2, 4, 4, 5, 6, 6|...],
Ds = [4, 6],
R = [1, 2, 2, 2, 5].
edit
to account for setof/3 behaviour (my bug: setof/3 fails if there are no solutions), a possible correction:
?- L=[1],
(setof(K,C^(aggregate(count,member(K,L),C),0=:=C mod 2),Ds);Ds=[]),
foldl([E,X,Y]>>delete(X,E,Y),Ds,L,R).
L = R, R = [1],
Ds = [].
Now there is a choice point left, the correct syntax could be
?- L=[1],
(setof(K,C^(aggregate(count,member(K,L),C),0=:=C mod 2),Ds)->true;Ds=[]),
foldl([E,X,Y]>>delete(X,E,Y),Ds,L,R).
L = R, R = [1],
Ds = [].

How to generate every [X,Y] possible for a given list?

I'm trying to generate every combination possible given a list. I want every [X,Y] combination possible.
Here's an example :
?- arguments(A,[1,2,3]).
A = [1,2] ; A = [1,3] ; A = [2,1] ; A = [2,3] ; A = [3,1] ;
A = [3,2]
I have tried multiple things, but I've yet to find a working one.
I am pretty sure the idea is to use prolog's ability to try every possibility as such :
element(X,[X|_],1).
element(X,[_|Q],N) :- element(X,Q,NewN), N is NewN + 1.
This predicate can return the element at the position N, or return the position of the element X, or generate every possibility. Exemple :
?- element(X,[a,b,c],N).
N = 1
X = a
N = 2
X = b
N = 3
X = c
Thanks for the help.
Edit following gusbro answer :
I can't use already existing predicates, it's part of a course.
Reading your answer, I came up with this :
remove_element_x(X, [X|Q], Q).
remove_element_x(X, [T|Q], [T|Res]) :- remove_element_x(X,Q,Res).
arguments([X,Y],L) :-
element(X,L,_),
remove_element_x(X,L,L2),
element(Y,L2,_).
remove_element_x/3 remove the element x from the list and returns the new list.
But the backtracking is not working :
?- arguments(A,[1,2,3]).
A = [1,2] ?
yes
You can use select/3 to select an element from a list (and get the remaining list), then do it again to select another element from the remaining list).
i.e.:
arguments([A,B], L):-
select(A, L, L1),
select(B, L1,_).
Test case:
?- arguments(A,[1,2,3]).
A = [1, 2] ;
A = [1, 3] ;
A = [2, 1] ;
A = [2, 3] ;
A = [3, 1] ;
A = [3, 2]

List combination start

I copied this code from this page:
% combination(K,L,C) :- C is a list of K distinct elements
% chosen from the list L
combination(0,_,[]).
combination(K,L,[X|Xs]) :- K > 0,
el(X,L,R), K1 is K-1, combination(K1,R,Xs).
el(X,[X|L],L).
el(X,[_|L],R) :- el(X,L,R).
For example, if you enter combination(2,[1,2,3,4],L), the result is:
L = [1, 2] ;
L = [1, 3] ;
L = [1, 4] ;
L = [2, 3] ;
L = [2, 4] ;
L = [3, 4] ;
Now I would like to enter something that allows you to start at a determined point of the combination. For example, something like: combination(2,[1,2,3,4],[1,4],L), and the result:
L = [1, 4] ;
L = [2, 3] ;
L = [2, 4] ;
L = [3, 4] ;
Starting the combination at [1,4] and skipping the "steps" [1,2] and [1,3].
Thanks for you help!
try this
combination(0,_,[]).
combination(K,L,[X|Xs]) :-
K > 0,
el(X,L,R),
K1 is K-1,
combination(K1,R,Xs).
generate(K, L, X, Pivot, Resault) :-
bagof(X, L^combination(K, L, X), Bag),
iterate(Bag, Pivot, Resault).
iterate([], _, []).
iterate([P|T], P, [P|T]):-!.
iterate([H|T], P, Res) :-
iterate(T, P, Res).
el(X,[X|L],L).
el(X,[_|L],R) :- el(X,L,R).
use generate/5 like this:
| ?- generate(2, [1,2,3,4], X, [1,4], Res).
Res = [[1,4],[2,3],[2,4],[3,4]]
yes.
first I gather all the solutions in a bag, then I iterate through the bag to find a pivot member, if I find it the resault is a list with the pivot as head, and rest of solutions as tail. and if I don't the resault is an empty list.
not a very wise solution, but works.

Resources