Count number of matching elements in two lists - prolog

I have 2 lists with random number of elemets. Eg A=[1,2,4,5] and B=[1,2,3]. Result should be 2.
Code that I tried:
domains
Numbers1 = integer*
Numbers2 = integer*
int_list=integer*
predicates
nondeterm prinadl(integer, int_list)
clauses
//here going the code that read number that I've entered, and according to entered numer,programm should do something
answer(T):- T=5,
P = 0,
write ("Enter the 1st list"), readterm (int_list, L),
write ("Enter the 2nd list"), readterm (int_list, L2),
L2 = [H|V], prinadl(H, L), P1 = P + 1,
write(L2, P1, V).
prinadl (X, L):- L=[X|_], !.
prinadl (X, L):- L=[_|T], prinadl (X, T).
I'm totally new with prolog. Can you please say me where I'm wrong? All I need is to get number of matches printed to the console.
Thanks in advance.

This answer is based on two things: first, guesswork. second, if_/3 by #false.
Let's define
the meta-predicate count_left_while2/4.
count_left_while2(P_2,Xs,Ys,N)
counts
the number N of corresponding list items in Xs and Ys fulfilling P_2. Proceeding from left to right, count_left_while2 stops at the first two items not satisfying P_2. It also stops when one list is empty, but the other one is not.
:- use_module(library(clpfd)).
:- meta_predicate count_left_while2(2,?,?,?).
count_left_while2(P_2,Xs,Ys,N) :-
N #>= 0,
list_list_countleft_while(Xs,Ys,N,P_2).
nil_or_cons([]).
nil_or_cons([_|_]).
:- meta_predicate list_list_countleft_while(?,?,?,2).
list_list_countleft_while([],Xs,0,_) :-
nil_or_cons(Xs).
list_list_countleft_while([X|Xs],Ys,N,P_2) :-
list_list_prev_countleft_while(Ys,Xs,X,N,P_2).
:- meta_predicate list_list_prev_countleft_while(?,?,?,?,2).
list_list_prev_countleft_while([],_,_,0,_).
list_list_prev_countleft_while([Y|Ys],Xs,X,N,P_2) :-
if_(call(P_2,X,Y),
( N0 #>= 0, N #= N0+1, list_list_countleft_while(Xs,Ys,N0,P_2) ),
N = 0).
Let's use it in combination with reified term equality predicate (=)/3, like this:
:- count_left_while2(=,[1,2,4,5],[1,2,3],N).
N = 2.

Related

Comparing prolog lists

I'm trying to make a prolog predicate "comprueba(A,B,C,D,E)" that do the next statements:
All arguments are lists.
List D contains only the elements that are on A and B at the same time.
List D elements number of ocurrences must be the same ocurrences in A.
List E contains only the elements of A that are not on C and not on D.
List E elements number of ocurrences must be three times the occurrences in A.
There are no more elements than these in D or E.
The predicate must be true even if the order of D or E differs from A.
So here is my code:
comprueba(A,B,C,D,E) :- lista([A]),
lista([B]),
lista([C]),
lista([D]),
lista([E]),
inter(A,B,D),
checko(D,D,A,1).
%checke2(A,C,D,E),
%checko(E,E,A,3).
lista([]).
lista([_|T]) :-lista(T).
inter([], _, []).
inter([H1|T1], L2, [H1|Res]) :- memberof(H1, L2), inter(T1, L2, Res).
inter([_|T1], L2, Res) :- inter(T1, L2, Res).
checke2([],_,_,_).
checke2(A,C,D,E) :- subtract(A,D,X), subtract(A,C,Y), inter(X,Y,E).
count(_, [], N) :- N is 0.
count(X, [X|T], N1) :- count(X, T, N2), N1 is N2 + 1.
count(X, [Y|T], N) :- X \= Y, count(X, T, N).
memberof(X, [X|_]).
memberof(X, [_|T]) :- memberof(X,T).
checko([],_,_,_).
checko([H|T],L1,L2,N) :- count(H,L1,N1), count(H,L2,N2), N3 is N * N2, N1 = N3, checko(T,L1,L2,N).
After doing some testing I'm stucked, because I cannot get it true, if the list are not on the same order, e.g:
17 ?- comprueba([1,2,3,4,2,5,8,9],[2,3,4,7],[1,2,3,8],[2,2,3,4],[5,5,5,9,9,9]).
false.
18 ?- comprueba([1,2,3,4,2,5,8,9],[2,3,4,7],[1,2,3,8],[2,3,4,2],[5,5,5,9,9,9]).
true
So I really ask you for help to try to solve it, and continue with the next part, with E list.
Thanks you in advance.
PD:
sorry if the format is not the properly, it's my first post here :)
You could add a goal that describes D as any permutation of the 4th list (in the below example D2).
comprueba(A,B,C,D,E) :- lista([A]),
lista([B]),
lista([C]),
lista([D2]),
lista([E]),
inter(A,B,D2),
checko(D2,D2,A,1),
permutation(D2,D).
If you are not allowed to use permutation/2 from library(lists) permutation could look something like this:
% permutation(List1,List2)
% List2 is a permutation of List1
permutation([],[]).
permutation(Xs,[Z|Zs]) :-
element(Z,Xs,Ys),
permutation(Ys,Zs).
% element(X,List1,List2)
% X is element of List1, List2 = List1 without X
element(X,[X|Xs],Xs).
element(X,[Y|Ys],[Y|Zs]) :-
element(X,Ys,Zs).
With this additional goal your predicate comprueba/5 works with both of your queries.
?- comprueba([1,2,3,4,2,5,8,9],[2,3,4,7],[1,2,3,8],[2,2,3,4],[5,5,5,9,9,9]).
yes
?- comprueba([1,2,3,4,2,5,8,9],[2,3,4,7],[1,2,3,8],[2,3,4,2],[5,5,5,9,9,9]).
yes

dividing a list up to a point in prolog

my_list([this,is,a,dog,.,are,tigers,wild,animals,?,the,boy,eats,mango,.]).
suppose this is a list in prolog which i want to divide in three parts that is up to three full stops and store them in variables.
how can i do that...
counthowmany(_, [], 0) :- !.
counthowmany(X, [X|Q], N) :- !, counthowmany(X, Q, N1), N is N1+1.
counthowmany(X, [_|Q], N) :- counthowmany(X, Q, N).
number_of_sentence(N) :- my_list(L),counthowmany(.,L,N).
i already counted the number of full stops in the list(my_list) now i want to divide the list up to first full stop and store it in a variable and then divide up to second full stop and store in a variable and so on.........
UPDATE: the code slightly simplified after #CapelliC comment.
One of the many ways to do it (another, better way - is to use DCG - definite clause grammar):
You don't really need counthowmany.
split([], []).
split(List, [Part | OtherParts]) :-
append(Part, ['.' | Rest], List),
split(Rest, OtherParts).
Let's try it:
?- my_list(List), split(List, Parts).
List = [this, is, a, dog, '.', tigers, are, wild, animals|...],
Parts = [[this, is, a, dog], [tigers, are, wild, animals], [the, boy, eats, mango]]
Your problem statement did not specify what a sequence without a dot should correspond to. I assume that this would be an invalid sentence - thus failure.
:- use_module(library(lambda)).
list_splitted(Xs, Xss) :-
phrase(sentences(Xss), Xs).
sentences([]) --> [].
sentences([Xs|Xss]) -->
sentence(Xs),
sentences(Xss).
sentence(Xs) -->
% {Xs = [_|_]}, % add this, should empty sentences not be allowed
allseq(dif('.'),Xs),
['.'].
% sentence(Xs) -->
% allseq(\X^maplist(dif(X),['.',?]), Xs),
% (['.']|[?]).
allseq(_P_1, []) --> [].
allseq( P_1, [C|Cs]) -->
[C],
{call(P_1,C)},
allseq(P_1, Cs).
In this answer we define split_/2 based on splitlistIf/3 and list_memberd_t/3:
split_(Xs, Yss) :-
splitlistIf(list_memberd_t(['?','.','!']), Xs, Yss).
Sample queries:
?- _Xs = [this,is,a,dog,'.', are,tigers,wild,animals,?, the,boy,eats,mango,'.'],
split_(_Xs, Yss).
Yss = [ [this,is,a,dog] ,[are,tigers,wild,animals] ,[the,boy,eats,mango] ].
?- split_([a,'.',b,'.'], Yss).
Yss = [[a],[b]]. % succeeds deterministically

Sort a sublist prolog

I have this list in Prolog:
[[13,Audi A3,11.11.2011,75000,berlina,audi,12100,verde pisello,[4wd],3.0000133333333334],[11,santafe,11.11.2011,80000,fuoristrada,audi,2232232,verde pisello,[Metalizzata,Sedile in Pelle,4wd],7.0000125]]|
I want to sort this list for last value of sublist, as example I want to have this result:
[[11,santafe,11.11.2011,80000,fuoristrada,audi,2232232,verde pisello,[Metalizzata,Sedile in Pelle,4wd],7.0000125],[13,Audi A3,11.11.2011,75000,berlina,audi,12100,verde pisello,[4wd],3.0000133333333334]]
predsort it's your friend. Then sort is easy, but to sell an Audi verde pisello will remain very, very hard...
sort_on_last(List, Sorted) :-
predsort(compare_last, List, Sorted).
compare_last(R, X, Y) :-
last(X, Xl),
last(Y, Yl),
compare(R, Xl, Yl).
To try it:
test :- sort_on_last(
[[11,santafe,'11.11.2011',80000,fuoristrada,audi,2232232,'verde pisello',['Metalizzata','Sedile in Pelle','4wd'],7.0000125],
[13,'Audi A3','11.11.2011',75000,berlina,audi,12100,'verde pisello',['4wd'],3.0000133333333334]
], S),
maplist(writeln, S).
?- test.
[13,Audi A3,11.11.2011,75000,berlina,audi,12100,verde pisello,[4wd],3.0000133333333334]
[11,santafe,11.11.2011,80000,fuoristrada,audi,2232232,verde pisello,[Metalizzata,Sedile in Pelle,4wd],7.0000125]
true.
A particularity of predsort/3: it acts as sort/2, thus remove duplicates.
To avoid this problem, compare_last/3 can be changed, avoiding return =, in this way:
compare_last(R, X, Y) :-
last(X, Xl),
last(Y, Yl),
( Xl < Yl -> R = (<) ; R = (>) ).

Can't get minimize from CLPFD to work

Me and a friend are writing a program which is supposed to solve a CLP problem. We want to use minimize to optimize the solution but it won't work, because it keeps saying that the number we get from sum(P,#=,S) is between two numbers (for example 5..7). We haven't been able to find a good way to extract any number from this or manipulate it in any way and are therefore looking for your help.
The problem seems to arise from our gen_var method which says that each element of a list must be between 0 and 1, so some numbers come out as "0..1" instead of being set properly.
Is there any way to use minimize even though we get a number like "5..7" or any way to manipulate that number so that we only get 5? S (the sum of the elements in a list) is what we're trying to minimize.
gen_var(0, []).
gen_var(N, [X|Xs]) :-
N > 0,
M is N-1,
gen_var(M, Xs),
domain([X],0,1).
find([],_).
find([H|T],P):- match(H,P),find(T,P).
match(pri(_,L),P):-member(X,L), nth1(X,P,1).
main(N,L,P,S) :- gen_var(N,P), minimize(findsum(L,P,S),S).
findsum(L,P,S):- find(L,P), sum(P,#=,S).
I've slightly modified your code, to adapt to SWI-Prolog CLP(FD), and it seems to work (kind of). But I think the minimum it's always 0!
:- use_module(library(clpfd)).
gen_var(0, []).
gen_var(N, [X|Xs]) :-
N > 0,
M is N-1,
gen_var(M, Xs),
X in 0..1 .
find([], _).
find([H|T], P):-
match(H, P),
find(T, P).
match(pri(_,L),P):-
member(X, L),
nth1(X, P, 1).
findsum(L,P,S) :-
find(L, P),
sum(P, #=, S).
main(N, L, P, S) :-
gen_var(N, P),
findsum(L, P, S),
labeling([min(S)], P).
Is this output sample a correct subset of the expected outcome?
?- main(3,A,B,C).
A = [],
B = [0, 0, 0],
C = 0 ;
A = [],
B = [0, 0, 1],
C = 1 ;

Prolog Programming

I have made two programs in Prolog for the nqueens puzzle using hill climbing and beam search algorithms.
Unfortunately I do not have the experience to check whether the programs are correct and I am in dead end.
I would appreciate if someone could help me out on that.
Unfortunately the program in hill climbing is incorrect. :(
The program in beam search is:
queens(N, Qs) :-
range(1, N, Ns),
queens(Ns, [], Qs).
range(N, N, [N]) :- !.
range(M, N, [M|Ns]) :-
M < N,
M1 is M+1,
range(M1, N, Ns).
queens([], Qs, Qs).
queens(UnplacedQs, SafeQs, Qs) :-
select(UnplacedQs, UnplacedQs1,Q),
not_attack(SafeQs, Q),
queens(UnplacedQs1, [Q|SafeQs], Qs).
not_attack(Xs, X) :-
not_attack(Xs, X, 1).
not_attack([], _, _) :- !.
not_attack([Y|Ys], X, N) :-
X =\= Y+N,
X =\= Y-N,
N1 is N+1,
not_attack(Ys, X, N1).
select([X|Xs], Xs, X).
select([Y|Ys], [Y|Zs], X) :- select(Ys, Zs, X).
I would like to mention this problem is a typical constraint satisfaction problem and can be efficiency solved using the CSP module of SWI-Prolog. Here is the full algorithm:
:- use_module(library(clpfd)).
queens(N, L) :-
N #> 0,
length(L, N),
L ins 1..N,
all_different(L),
applyConstraintOnDescDiag(L),
applyConstraintOnAscDiag(L),
label(L).
applyConstraintOnDescDiag([]) :- !.
applyConstraintOnDescDiag([H|T]) :-
insertConstraintOnDescDiag(H, T, 1),
applyConstraintOnDescDiag(T).
insertConstraintOnDescDiag(_, [], _) :- !.
insertConstraintOnDescDiag(X, [H|T], N) :-
H #\= X + N,
M is N + 1,
insertConstraintOnDescDiag(X, T, M).
applyConstraintOnAscDiag([]) :- !.
applyConstraintOnAscDiag([H|T]) :-
insertConstraintOnAscDiag(H, T, 1),
applyConstraintOnAscDiag(T).
insertConstraintOnAscDiag(_, [], _) :- !.
insertConstraintOnAscDiag(X, [H|T], N) :-
H #\= X - N,
M is N + 1,
insertConstraintOnAscDiag(X, T, M).
N is the number of queens or the size of the board (), and , where , being the position of the queen on the line .
Let's details each part of the algorithm above to understand what happens.
:- use_module(library(clpfd)).
It indicates to SWI-Prolog to load the module containing the predicates for constraint satisfaction problems.
queens(N, L) :-
N #> 0,
length(L, N),
L ins 1..N,
all_different(L),
applyConstraintOnDescDiag(L),
applyConstraintOnAscDiag(L),
label(L).
The queens predicate is the entry point of the algorithm and checks if the terms are properly formatted (number range, length of the list). It checks if the queens are on different lines as well.
applyConstraintOnDescDiag([]) :- !.
applyConstraintOnDescDiag([H|T]) :-
insertConstraintOnDescDiag(H, T, 1),
applyConstraintOnDescDiag(T).
insertConstraintOnDescDiag(_, [], _) :- !.
insertConstraintOnDescDiag(X, [H|T], N) :-
H #\= X + N,
M is N + 1,
insertConstraintOnDescDiag(X, T, M).
It checks if there is a queen on the descendant diagonal of the current queen that is iterated.
applyConstraintOnAscDiag([]) :- !.
applyConstraintOnAscDiag([H|T]) :-
insertConstraintOnAscDiag(H, T, 1),
applyConstraintOnAscDiag(T).
insertConstraintOnAscDiag(_, [], _) :- !.
insertConstraintOnAscDiag(X, [H|T], N) :-
H #\= X - N,
M is N + 1,
insertConstraintOnAscDiag(X, T, M).
Same as previous, but it checks if there is a queen on the ascendant diagonal.
Finally, the results can be found by calling the predicate queens/2, such as:
?- findall(X, queens(4, X), L).
L = [[2, 4, 1, 3], [3, 1, 4, 2]]
If I read your code correctly, the algorithm you're trying to implement is a simple depth-first search rather than beam search. That's ok, because it should be (I don't see how beam search will be effective for this problem and it can be hard to program).
I'm not going to debug this code for you, but I will give you a suggestion: build the chess board bottom-up with
queens(0, []).
queens(N, [Q|Qs]) :-
M is N-1,
queens(M, Qs),
between(1, N, Q),
safe(Q, Qs).
where safe(Q,Qs) is true iff none of Qs attack Q. safe/2 is then the conjunction of a simple memberchk/2 check (see SWI-Prolog manual) and your not_attack/2 predicate, which on first sight seems to be correct.
A quick check on Google has found a few candidates for you to compare with your code and find what to change.
My favoured solution for sheer clarity would be the second of the ones linked to above:
% This program finds a solution to the 8 queens problem. That is, the problem of placing 8
% queens on an 8x8 chessboard so that no two queens attack each other. The prototype
% board is passed in as a list with the rows instantiated from 1 to 8, and a corresponding
% variable for each column. The Prolog program instantiates those column variables as it
% finds the solution.
% Programmed by Ron Danielson, from an idea by Ivan Bratko.
% 2/17/00
queens([]). % when place queen in empty list, solution found
queens([ Row/Col | Rest]) :- % otherwise, for each row
queens(Rest), % place a queen in each higher numbered row
member(Col, [1,2,3,4,5,6,7,8]), % pick one of the possible column positions
safe( Row/Col, Rest). % and see if that is a safe position
% if not, fail back and try another column, until
% the columns are all tried, when fail back to
% previous row
safe(Anything, []). % the empty board is always safe
safe(Row/Col, [Row1/Col1 | Rest]) :- % see if attack the queen in next row down
Col =\= Col1, % same column?
Col1 - Col =\= Row1 - Row, % check diagonal
Col1 - Col =\= Row - Row1,
safe(Row/Col, Rest). % no attack on next row, try the rest of board
member(X, [X | Tail]). % member will pick successive column values
member(X, [Head | Tail]) :-
member(X, Tail).
board([1/C1, 2/C2, 3/C3, 4/C4, 5/C5, 6/C6, 7/C7, 8/C8]). % prototype board
The final link, however, solves it in three different ways so you can compare against three known solutions.

Resources